After a deadlock it was possible for the timer signal to remain off,
which meant that the next deadlock would not be detected, and the
system would hang. Spotted by conc047(threaded2).
// they are unreachable and will therefore be sent an
// exception. Any threads thus released will be immediately
// runnable.
// they are unreachable and will therefore be sent an
// exception. Any threads thus released will be immediately
// runnable.
- cap = scheduleDoGC (cap, task, rtsTrue/*force major GC*/);
+ cap = scheduleDoGC (cap, task, rtsTrue/*force major GC*/);
+ // when force_major == rtsTrue. scheduleDoGC sets
+ // recent_activity to ACTIVITY_DONE_GC and turns off the timer
+ // signal.
- recent_activity = ACTIVITY_DONE_GC;
- // disable timer signals (see #1623)
- stopTimer();
-
if ( !emptyRunQueue(cap) ) return;
#if defined(RTS_USER_SIGNALS) && !defined(THREADED_RTS)
if ( !emptyRunQueue(cap) ) return;
#if defined(RTS_USER_SIGNALS) && !defined(THREADED_RTS)
balanceSparkPoolsCaps(n_capabilities, capabilities);
#endif
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)
// release our stash of capabilities.
for (i = 0; i < n_capabilities; i++) {
#if defined(THREADED_RTS)
// release our stash of capabilities.
for (i = 0; i < n_capabilities; i++) {