tmf: Bug 494952: Remove deadlock in Time Chart view
authorPatrick Tasse <patrick.tasse@gmail.com>
Mon, 30 May 2016 21:20:10 +0000 (17:20 -0400)
committerPatrick Tasse <patrick.tasse@gmail.com>
Mon, 6 Jun 2016 17:48:40 +0000 (13:48 -0400)
The handling of signal TmfTraceUpdated is now done in a
ProcessTraceThread. There is only one such thread per trace active at a
time. If an update is requested while a thread is active, the thread is
marked to be restarted after its current iteration completion.

The starting or restarting of a ProcessTraceThread is consolidated in a
method and synchronized.

The ProcessTraceThread now always processes the full time range of the
trace, even when the view is opened with a trace already opened.

A missing synchronization on DecorateThread concurrent access is added.

Method ITimeDataProvider.resetStartFinishTime(boolean) is added to allow
the TimeChartView to reset its window range without notifying listeners.

Change-Id: I0d49d2712af4e5c645bd61bfde46ba37fc42779c
Signed-off-by: Patrick Tasse <patrick.tasse@gmail.com>
Reviewed-on: https://git.eclipse.org/r/73996
Reviewed-by: Hudson CI
Reviewed-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
Reviewed-by: Bernd Hufmann <bernd.hufmann@ericsson.com>
Tested-by: Matthew Khouzam <matthew.khouzam@ericsson.com>
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/views/timechart/TimeChartView.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/TimeGraphViewer.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/ITimeDataProvider.java
tmf/org.eclipse.tracecompass.tmf.ui/src/org/eclipse/tracecompass/tmf/ui/widgets/timegraph/widgets/TimeDataProviderCyclesConverter.java

index ff31a99cb40b53dede9df71731adaad99e983569..28a198ed714d7b8a1f129b92c51b882066cd7220 100644 (file)
@@ -82,6 +82,7 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
     private final List<TimeChartAnalysisEntry> fTimeAnalysisEntries = new ArrayList<>();
     private final Map<ITmfTrace, TimeChartDecorationProvider> fDecorationProviders = new HashMap<>();
     private final List<DecorateThread> fDecorateThreads = new ArrayList<>();
+    private final Map<ITmfTrace, ProcessTraceThread> fProcessTraceThreads = new HashMap<>();
     private long fStartTime = 0;
     private long fStopTime = Long.MAX_VALUE;
     private boolean fRefreshBusy = false;
@@ -120,8 +121,7 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
             TimeChartAnalysisEntry timeAnalysisEntry = new TimeChartAnalysisEntry(trace, fDisplayWidth * 2);
             fTimeAnalysisEntries.add(timeAnalysisEntry);
             fDecorationProviders.put(trace, new TimeChartDecorationProvider(bookmarksFile));
-            Thread thread = new ProcessTraceThread(timeAnalysisEntry);
-            thread.start();
+            startProcessTraceThread(timeAnalysisEntry);
         }
         fViewer.setInput(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0]));
 
@@ -132,8 +132,10 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
     @Override
     public void dispose() {
         ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
-        for (DecorateThread thread : fDecorateThreads) {
-            thread.cancel();
+        synchronized (fDecorateThreads) {
+            for (DecorateThread thread : fDecorateThreads) {
+                thread.cancel();
+            }
         }
         ColorSettingsManager.removeColorSettingsListener(this);
         super.dispose();
@@ -144,22 +146,50 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
         fViewer.setFocus();
     }
 
+    private void startProcessTraceThread(TimeChartAnalysisEntry entry) {
+        synchronized (fProcessTraceThreads) {
+            ProcessTraceThread thread = fProcessTraceThreads.get(entry.getTrace());
+            if (thread != null) {
+                thread.restart();
+            } else {
+                thread = new ProcessTraceThread(entry);
+                fProcessTraceThreads.put(entry.getTrace(), thread);
+                thread.start();
+            }
+        }
+    }
+
     private class ProcessTraceThread extends Thread {
 
         private final TimeChartAnalysisEntry fTimeAnalysisEntry;
+        private boolean fRestart;
 
         public ProcessTraceThread(TimeChartAnalysisEntry timeAnalysisEntry) {
             super("ProcessTraceJob:" + timeAnalysisEntry.getName()); //$NON-NLS-1$
             fTimeAnalysisEntry = timeAnalysisEntry;
         }
 
+        public void restart() {
+            synchronized (fProcessTraceThreads) {
+                fRestart = true;
+            }
+        }
+
         @Override
         public void run() {
-            TmfTimeRange range = TmfTraceManager.getInstance().getCurrentTraceContext().getWindowRange();
-
-            updateTraceEntry(fTimeAnalysisEntry, Long.MAX_VALUE,
-                    range.getStartTime().toNanos(),
-                    range.getEndTime().toNanos());
+            while (true) {
+                updateTraceEntry(fTimeAnalysisEntry, Long.MAX_VALUE,
+                        TmfTimestamp.BIG_BANG.toNanos(),
+                        TmfTimestamp.BIG_CRUNCH.toNanos());
+                synchronized (fProcessTraceThreads) {
+                    if (fRestart) {
+                        fRestart = false;
+                    } else {
+                        fProcessTraceThreads.remove(fTimeAnalysisEntry.getTrace());
+                        return;
+                    }
+                }
+            }
         }
     }
 
@@ -240,7 +270,7 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
                     return;
                 }
                 fViewer.setInput(fTimeAnalysisEntries.toArray(new TimeChartAnalysisEntry[0]));
-                fViewer.resetStartFinishTime();
+                fViewer.resetStartFinishTime(false);
                 synchronized (fSyncObj) {
                     fRefreshBusy = false;
                     if (fRefreshPending) {
@@ -598,8 +628,7 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
             timeAnalysisEntry = new TimeChartAnalysisEntry(trace, fDisplayWidth * 2);
             fTimeAnalysisEntries.add(timeAnalysisEntry);
             fDecorationProviders.put(trace, new TimeChartDecorationProvider(bookmarksFile));
-            Thread thread = new ProcessTraceThread(timeAnalysisEntry);
-            thread.start();
+            startProcessTraceThread(timeAnalysisEntry);
         }
         refreshViewer();
     }
@@ -667,7 +696,7 @@ public class TimeChartView extends TmfView implements ITimeGraphRangeListener, I
         for (int i = 0; i < fTimeAnalysisEntries.size(); i++) {
             TimeChartAnalysisEntry timeAnalysisEntry = fTimeAnalysisEntries.get(i);
             if (timeAnalysisEntry.getTrace().equals(trace)) {
-                updateTraceEntry(timeAnalysisEntry, Long.MAX_VALUE, 0, Long.MAX_VALUE);
+                startProcessTraceThread(timeAnalysisEntry);
                 break;
             }
         }
index f4060c299247d2f66bcdbb28819da1824530ab05..976eafec7bb79eee227e700b0371c688ad2ed8bb 100644 (file)
@@ -979,6 +979,19 @@ public class TimeGraphViewer implements ITimeDataProvider, IMarkerAxisListener,
         fTimeRangeFixed = false;
     }
 
+    /**
+     * @since 2.0
+     */
+    @Override
+    public void resetStartFinishTime(boolean notify) {
+        if (notify) {
+            setStartFinishTimeNotify(fTime0Bound, fTime1Bound);
+        } else {
+            setStartFinishTime(fTime0Bound, fTime1Bound);
+        }
+        fTimeRangeFixed = false;
+    }
+
     @Override
     public void setSelectedTimeNotify(long time, boolean ensureVisible) {
         setSelectedTimeInt(time, ensureVisible, true);
index e83509f2eae507c44ac73023303e92def44c2b68..b60f22719ed4906cfbd2b7826e8de589bf790e3b 100644 (file)
@@ -1,5 +1,5 @@
 /*****************************************************************************
- * Copyright (c) 2007, 2015 Intel Corporation, Ericsson
+ * Copyright (c) 2007, 2016 Intel Corporation, Ericsson
  *
  * All rights reserved. This program and the accompanying materials
  * are made available under the terms of the Eclipse Public License v1.0
@@ -176,6 +176,21 @@ public interface ITimeDataProvider {
      */
     void resetStartFinishTime();
 
+    /**
+     * Reset the start and end times.
+     *
+     * @param notify
+     *            if true, notify the registered listeners
+     * @since 2.0
+     */
+    default void resetStartFinishTime(boolean notify) {
+        if (notify) {
+            setStartFinishTimeNotify(getMinTime(), getMaxTime());
+        } else {
+            setStartFinishTime(getMinTime(), getMaxTime());
+        }
+    }
+
     /**
      * @return The names' width
      */
index bb69d7ccd3f0b1586ba5890a0891f3302d753575..7393de4ec2c96fed99ce3cf2e40dcbf26a3e64c3 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************
- * Copyright (c) 2014, 2015 Ericsson
+ * Copyright (c) 2014, 2016 Ericsson
  *
  * All rights reserved. This program and the accompanying materials are
  * made available under the terms of the Eclipse Public License v1.0 which
@@ -159,6 +159,14 @@ public class TimeDataProviderCyclesConverter implements ITimeDataProviderConvert
         fProvider.resetStartFinishTime();
     }
 
+    /**
+     * @since 2.0
+     */
+    @Override
+    public void resetStartFinishTime(boolean notify) {
+        fProvider.resetStartFinishTime(notify);
+    }
+
     @Override
     public int getNameSpace() {
         return fProvider.getNameSpace();
This page took 0.028609 seconds and 5 git commands to generate.