fix a race where the timer signal could remain turned off, leading to deadlock
authorSimon Marlow <marlowsd@gmail.com>
Wed, 7 Jan 2009 12:06:52 +0000 (12:06 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Wed, 7 Jan 2009 12:06:52 +0000 (12:06 +0000)
rts/Schedule.c

index 7c453d7..9baf755 100644 (file)
@@ -1599,6 +1599,21 @@ delete_threads_and_gc:
     
     heap_census = scheduleNeedHeapProfile(rtsTrue);
 
+    if (recent_activity == ACTIVITY_INACTIVE && force_major)
+    {
+        // We are doing a GC because the system has been idle for a
+        // timeslice and we need to check for deadlock.  Record the
+        // fact that we've done a GC and turn off the timer signal;
+        // it will get re-enabled if we run any threads after the GC.
+        //
+        // Note: this is done before GC, because after GC there might
+        // be threads already running (GarbageCollect() releases the
+        // GC threads when it completes), so we risk turning off the
+        // timer signal when it should really be on.
+        recent_activity = ACTIVITY_DONE_GC;
+        stopTimer();
+    }
+
 #if defined(THREADED_RTS)
     debugTrace(DEBUG_sched, "doing GC");
     // reset waiting_for_gc *before* GC, so that when the GC threads
@@ -1640,16 +1655,6 @@ delete_threads_and_gc:
     balanceSparkPoolsCaps(n_capabilities, capabilities);
 #endif
 
-    if (force_major)
-    {
-        // We've just done a major GC and we don't need the timer
-        // signal turned on any more (#1623).
-        // NB. do this *before* releasing the Capabilities, to avoid
-        // deadlocks!
-        recent_activity = ACTIVITY_DONE_GC;
-        stopTimer();
-    }
-
 #if defined(THREADED_RTS)
     if (gc_type == PENDING_GC_SEQ) {
         // release our stash of capabilities.