diff options
author | Simon Marlow <marlowsd@gmail.com> | 2010-03-11 09:57:44 +0000 |
---|---|---|
committer | Simon Marlow <marlowsd@gmail.com> | 2010-03-11 09:57:44 +0000 |
commit | 7408b39235bccdcde48df2a73337ff976fbc09b7 (patch) | |
tree | cf20c372fdc5787170d53df36fc24ecf8113c89e /rts/Exception.cmm | |
parent | 12cfec943127f0c81e1ffa1ca5ce46e888e3027c (diff) | |
download | haskell-7408b39235bccdcde48df2a73337ff976fbc09b7.tar.gz |
Use message-passing to implement throwTo in the RTS
This replaces some complicated locking schemes with message-passing
in the implementation of throwTo. The benefits are
- previously it was impossible to guarantee that a throwTo from
a thread running on one CPU to a thread running on another CPU
would be noticed, and we had to rely on the GC to pick up these
forgotten exceptions. This no longer happens.
- the locking regime is simpler (though the code is about the same
size)
- threads can be unblocked from a blocked_exceptions queue without
having to traverse the whole queue now. It's a rare case, but
replaces an O(n) operation with an O(1).
- generally we move in the direction of sharing less between
Capabilities (aka HECs), which will become important with other
changes we have planned.
Also in this patch I replaced several STM-specific closure types with
a generic MUT_PRIM closure type, which allowed a lot of code in the GC
and other places to go away, hence the line-count reduction. The
message-passing changes resulted in about a net zero line-count
difference.
Diffstat (limited to 'rts/Exception.cmm')
-rw-r--r-- | rts/Exception.cmm | 43 |
1 files changed, 19 insertions, 24 deletions
diff --git a/rts/Exception.cmm b/rts/Exception.cmm index 6c887c22dc..55c79cede7 100644 --- a/rts/Exception.cmm +++ b/rts/Exception.cmm @@ -56,7 +56,7 @@ INFO_TABLE_RET( stg_unblockAsyncExceptionszh_ret, RET_SMALL ) CInt r; StgTSO_flags(CurrentTSO) = StgTSO_flags(CurrentTSO) & - ~(TSO_BLOCKEX::I32|TSO_INTERRUPTIBLE::I32); + %lobits32(~(TSO_BLOCKEX|TSO_INTERRUPTIBLE)); /* Eagerly raise a blocked exception, if there is one */ if (StgTSO_blocked_exceptions(CurrentTSO) != END_TSO_QUEUE) { @@ -99,8 +99,8 @@ INFO_TABLE_RET( stg_unblockAsyncExceptionszh_ret, RET_SMALL ) INFO_TABLE_RET( stg_blockAsyncExceptionszh_ret, RET_SMALL ) { - StgTSO_flags(CurrentTSO) = - StgTSO_flags(CurrentTSO) | TSO_BLOCKEX::I32 | TSO_INTERRUPTIBLE::I32; + StgTSO_flags(CurrentTSO) = %lobits32( + TO_W_(StgTSO_flags(CurrentTSO)) | TSO_BLOCKEX | TSO_INTERRUPTIBLE); Sp_adj(1); jump %ENTRY_CODE(Sp(0)); @@ -113,8 +113,8 @@ stg_blockAsyncExceptionszh if ((TO_W_(StgTSO_flags(CurrentTSO)) & TSO_BLOCKEX) == 0) { - StgTSO_flags(CurrentTSO) = - StgTSO_flags(CurrentTSO) | TSO_BLOCKEX::I32 | TSO_INTERRUPTIBLE::I32; + StgTSO_flags(CurrentTSO) = %lobits32( + TO_W_(StgTSO_flags(CurrentTSO)) | TSO_BLOCKEX | TSO_INTERRUPTIBLE); /* avoid growing the stack unnecessarily */ if (Sp(0) == stg_blockAsyncExceptionszh_ret_info) { @@ -142,8 +142,8 @@ stg_unblockAsyncExceptionszh /* If exceptions are already unblocked, there's nothing to do */ if ((TO_W_(StgTSO_flags(CurrentTSO)) & TSO_BLOCKEX) != 0) { - StgTSO_flags(CurrentTSO) = StgTSO_flags(CurrentTSO) & - ~(TSO_BLOCKEX::I32|TSO_INTERRUPTIBLE::I32); + StgTSO_flags(CurrentTSO) = %lobits32( + TO_W_(StgTSO_flags(CurrentTSO)) & ~(TSO_BLOCKEX|TSO_INTERRUPTIBLE)); /* avoid growing the stack unnecessarily */ if (Sp(0) == stg_unblockAsyncExceptionszh_ret_info) { @@ -252,27 +252,22 @@ stg_killThreadzh } } else { W_ out; - W_ retcode; + W_ msg; out = Sp - WDS(1); /* ok to re-use stack space here */ - (retcode) = foreign "C" throwTo(MyCapability() "ptr", - CurrentTSO "ptr", - target "ptr", - exception "ptr", - out "ptr") [R1,R2]; + (msg) = foreign "C" throwTo(MyCapability() "ptr", + CurrentTSO "ptr", + target "ptr", + exception "ptr") [R1,R2]; - switch [THROWTO_SUCCESS .. THROWTO_BLOCKED] (retcode) { - - case THROWTO_SUCCESS: { + if (msg == NULL) { jump %ENTRY_CODE(Sp(0)); - } - - case THROWTO_BLOCKED: { - R3 = W_[out]; - // we must block, and call throwToReleaseTarget() before returning + } else { + StgTSO_why_blocked(CurrentTSO) = BlockedOnMsgThrowTo; + StgTSO_block_info(CurrentTSO) = msg; + // we must block, and unlock the message before returning jump stg_block_throwto; } - } } } @@ -507,8 +502,8 @@ retry_pop_stack: /* Ensure that async excpetions are blocked when running the handler. */ - StgTSO_flags(CurrentTSO) = - StgTSO_flags(CurrentTSO) | TSO_BLOCKEX::I32 | TSO_INTERRUPTIBLE::I32; + StgTSO_flags(CurrentTSO) = %lobits32( + TO_W_(StgTSO_flags(CurrentTSO)) | TSO_BLOCKEX | TSO_INTERRUPTIBLE); /* Call the handler, passing the exception value and a realworld * token as arguments. |