diff options
author | Simon Marlow <marlowsd@gmail.com> | 2009-01-07 14:05:07 +0000 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2009-01-07 14:05:07 +0000 |
commit | ea1ad23f58b5e45731b47a1d686c0dd73766e1b7 (patch) | |
tree | dd73d2f2e1905b23f8f8f766d78b7840f73d2d03 /rts/RaiseAsync.c | |
parent | 9fd3a4f8760c7e47eb5d4a098559c980d24a9775 (diff) | |
download | haskell-ea1ad23f58b5e45731b47a1d686c0dd73766e1b7.tar.gz |
Close the races between throwTo and thread completion
Any threads we missed were being caught by the GC (possibly the idle
GC if the system was otherwise inactive), but that's not ideal. The
fix (from Bertram Felgenhauer) is to use lockTSO to synchronise,
imposing an unconditional lockTSO on thread exit. I couldn't measure
any performance overhead from doing this, so it seems reasonable.
Diffstat (limited to 'rts/RaiseAsync.c')
-rw-r--r-- | rts/RaiseAsync.c | 19 |
1 files changed, 13 insertions, 6 deletions
diff --git a/rts/RaiseAsync.c b/rts/RaiseAsync.c index e65cea3bfd..2f072d551a 100644 --- a/rts/RaiseAsync.c +++ b/rts/RaiseAsync.c @@ -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 |