X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FSchedule.c;h=978adb89c8d7d9c050499a032d812122e2a770be;hb=51cae5224f2f2f5db8b3196d0f5118ba4246701a;hp=38e3a3c2ce2d8b27cb28db93895fe1e872ebc3f5;hpb=0bff4d75254dabb2c002eace2252a4480bf8474e;p=ghc-hetmet.git diff --git a/rts/Schedule.c b/rts/Schedule.c index 38e3a3c..978adb8 100644 --- a/rts/Schedule.c +++ b/rts/Schedule.c @@ -32,6 +32,7 @@ #include "Proftimer.h" #include "ProfHeap.h" #include "GC.h" +#include "Weak.h" /* PARALLEL_HASKELL includes go here */ @@ -281,6 +282,12 @@ schedule (Capability *initialCapability, Task *task) "### NEW SCHEDULER LOOP (task: %p, cap: %p)", task, initialCapability); + if (running_finalizers) { + errorBelch("error: a C finalizer called back into Haskell.\n" + " use Foreign.Concurrent.newForeignPtr for Haskell finalizers."); + stg_exit(EXIT_FAILURE); + } + schedulePreLoop(); // ----------------------------------------------------------- @@ -1402,6 +1409,12 @@ scheduleHandleThreadFinished (Capability *cap STG_UNUSED, Task *task, StgTSO *t) debugTrace(DEBUG_sched, "--++ thread %lu (%s) finished", (unsigned long)t->id, whatNext_strs[t->what_next]); + // blocked exceptions can now complete, even if the thread was in + // blocked mode (see #2910). This unconditionally calls + // lockTSO(), which ensures that we don't miss any threads that + // are engaged in throwTo() with this thread as a target. + awakenBlockedExceptionQueue (cap, t); + // // Check whether the thread that just completed was a bound // thread, and if so return with the result. @@ -1592,6 +1605,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 @@ -1633,16 +1661,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. @@ -1976,7 +1994,10 @@ resumeThread (void *task_) debugTrace(DEBUG_sched, "thread %lu: re-entering RTS", (unsigned long)tso->id); if (tso->why_blocked == BlockedOnCCall) { - awakenBlockedExceptionQueue(cap,tso); + // avoid locking the TSO if we don't have to + if (tso->blocked_exceptions != END_TSO_QUEUE) { + awakenBlockedExceptionQueue(cap,tso); + } tso->flags &= ~(TSO_BLOCKEX | TSO_INTERRUPTIBLE); }