X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=rts%2FRaiseAsync.c;h=c8a38565afcd9aa9af2c506cbc695803562e63f7;hb=21146fa414558ee31b08b14792feed71778bccdf;hp=e65cea3bfd99ccac1705bec5e7ef8d43a789f2a2;hpb=9fd3a4f8760c7e47eb5d4a098559c980d24a9775;p=ghc-hetmet.git diff --git a/rts/RaiseAsync.c b/rts/RaiseAsync.c index e65cea3..c8a3856 100644 --- a/rts/RaiseAsync.c +++ b/rts/RaiseAsync.c @@ -8,15 +8,15 @@ #include "PosixSource.h" #include "Rts.h" + +#include "sm/Storage.h" #include "Threads.h" #include "Trace.h" #include "RaiseAsync.h" -#include "SMP.h" #include "Schedule.h" -#include "LdvProfile.h" #include "Updates.h" #include "STM.h" -#include "Sanity.h" +#include "sm/Sanity.h" #include "Profiling.h" #if defined(mingw32_HOST_OS) #include "win32/IOManager.h" @@ -150,6 +150,8 @@ throwTo (Capability *cap, // the Capability we hold { StgWord status; + ASSERT(target != END_TSO_QUEUE); + // follow ThreadRelocated links in the target first while (target->what_next == ThreadRelocated) { target = target->_link; @@ -161,11 +163,7 @@ throwTo (Capability *cap, // the Capability we hold (unsigned long)source->id, (unsigned long)target->id); #ifdef DEBUG - if (traceClass(DEBUG_sched)) { - debugTraceBegin("throwTo: target"); - printThreadStatus(target); - debugTraceEnd(); - } + traceThreadStatus(DEBUG_sched, target); #endif goto check_target; @@ -173,6 +171,8 @@ retry: debugTrace(DEBUG_sched, "throwTo: retrying..."); check_target: + ASSERT(target != END_TSO_QUEUE); + // Thread already dead? if (target->what_next == ThreadComplete || target->what_next == ThreadKilled) { @@ -264,6 +264,15 @@ check_target: target = target->_link; goto retry; } + // check again for ThreadComplete and ThreadKilled. This + // cooperates with scheduleHandleThreadFinished to ensure + // that we never miss any threads that are throwing an + // exception to a thread in the process of terminating. + if (target->what_next == ThreadComplete + || target->what_next == ThreadKilled) { + unlockTSO(target); + return THROWTO_SUCCESS; + } blockedThrowTo(cap,source,target); *out = target; return THROWTO_BLOCKED; @@ -564,12 +573,10 @@ maybePerformBlockedException (Capability *cap, StgTSO *tso) void awakenBlockedExceptionQueue (Capability *cap, StgTSO *tso) { - if (tso->blocked_exceptions != END_TSO_QUEUE) { - lockTSO(tso); - awakenBlockedQueue(cap, tso->blocked_exceptions); - tso->blocked_exceptions = END_TSO_QUEUE; - unlockTSO(tso); - } + lockTSO(tso); + awakenBlockedQueue(cap, tso->blocked_exceptions); + tso->blocked_exceptions = END_TSO_QUEUE; + unlockTSO(tso); } static void @@ -665,16 +672,7 @@ removeFromQueues(Capability *cap, StgTSO *tso) } done: - tso->_link = END_TSO_QUEUE; // no write barrier reqd - tso->why_blocked = NotBlocked; - tso->block_info.closure = NULL; - appendToRunQueue(cap,tso); - - // We might have just migrated this TSO to our Capability: - if (tso->bound) { - tso->bound->cap = cap; - } - tso->cap = cap; + unblockOne(cap, tso); } /* ----------------------------------------------------------------------------- @@ -729,7 +727,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, #if defined(PROFILING) /* * Debugging tool: on raising an exception, show where we are. - * See also Exception.cmm:raisezh_fast. + * See also Exception.cmm:stg_raisezh. * This wasn't done for asynchronous exceptions originally; see #1450 */ if (RtsFlags.ProfFlags.showCCSOnException) @@ -798,7 +796,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, // fun field. // words = frame - sp - 1; - ap = (StgAP_STACK *)allocateLocal(cap,AP_STACK_sizeW(words)); + ap = (StgAP_STACK *)allocate(cap,AP_STACK_sizeW(words)); ap->size = words; ap->fun = (StgClosure *)sp[0]; @@ -862,7 +860,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, // we've got an exception to raise, so let's pass it to the // handler in this frame. // - raise = (StgThunk *)allocateLocal(cap,sizeofW(StgThunk)+1); + raise = (StgThunk *)allocate(cap,sizeofW(StgThunk)+1); TICK_ALLOC_SE_THK(1,0); SET_HDR(raise,&stg_raise_info,cf->header.prof.ccs); raise->payload[0] = exception; @@ -890,9 +888,19 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, case ATOMICALLY_FRAME: if (stop_at_atomically) { - ASSERT(stmGetEnclosingTRec(tso->trec) == NO_TREC); + ASSERT(tso->trec->enclosing_trec == NO_TREC); stmCondemnTransaction(cap, tso -> trec); - tso->sp = frame; + tso->sp = frame - 2; + // The ATOMICALLY_FRAME expects to be returned a + // result from the transaction, which it stores in the + // stack frame. Hence we arrange to return a dummy + // result, so that the GC doesn't get upset (#3578). + // Perhaps a better way would be to have a different + // ATOMICALLY_FRAME instance for condemned + // transactions, but I don't fully understand the + // interaction with STM invariants. + tso->sp[1] = (W_)&stg_NO_TREC_closure; + tso->sp[0] = (W_)&stg_gc_unpt_r1_info; tso->what_next = ThreadRunGHC; return; } @@ -910,7 +918,7 @@ raiseAsync(Capability *cap, StgTSO *tso, StgClosure *exception, { StgTRecHeader *trec = tso -> trec; - StgTRecHeader *outer = stmGetEnclosingTRec(trec); + StgTRecHeader *outer = trec -> enclosing_trec; debugTrace(DEBUG_stm, "found atomically block delivering async exception"); stmAbortTransaction(cap, trec);