diff options
author | Simon Marlow <marlowsd@gmail.com> | 2018-07-12 10:13:47 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2018-07-12 15:04:20 -0400 |
commit | 7fc418df856d9b58034eeec48915646e67a7a562 (patch) | |
tree | 656a7a8ae131122c4253bb6c490fb9e7db671346 /rts/RaiseAsync.c | |
parent | 1a79270c72cfcd98d683cfe7b2c777d8dd353b78 (diff) | |
download | haskell-7fc418df856d9b58034eeec48915646e67a7a562.tar.gz |
Fix deadlock between STM and throwTo
There was a lock-order reversal between lockTSO() and the TVar lock,
see #15136 for the details.
It turns out we can fix this pretty easily by just deleting all the
locking code(!). The principle for unblocking a `BlockedOnSTM` thread
then becomes the same as for other kinds of blocking: if the TSO
belongs to this capability then we do it directly, otherwise we send a
message to the capability that owns the TSO. That is, a thread blocked
on STM is owned by its capability, as it should be.
The possible downside of this is that we might send multiple messages
to wake up a thread when the thread is on another capability. This is
safe, it's just not very efficient. I'll try to do some experiments
to see if this is a problem.
Test Plan: Test case from #15136 doesn't deadlock any more.
Reviewers: bgamari, osa1, erikd
Reviewed By: osa1
Subscribers: rwbarton, thomie, carter
GHC Trac Issues: #15136
Differential Revision: https://phabricator.haskell.org/D4956
Diffstat (limited to 'rts/RaiseAsync.c')
-rw-r--r-- | rts/RaiseAsync.c | 9 |
1 files changed, 0 insertions, 9 deletions
diff --git a/rts/RaiseAsync.c b/rts/RaiseAsync.c index f5e96a2c43..b08acc4078 100644 --- a/rts/RaiseAsync.c +++ b/rts/RaiseAsync.c @@ -416,21 +416,12 @@ check_target: } case BlockedOnSTM: - lockTSO(target); - // Unblocking BlockedOnSTM threads requires the TSO to be - // locked; see STM.c:unpark_tso(). - if (target->why_blocked != BlockedOnSTM) { - unlockTSO(target); - goto retry; - } if ((target->flags & TSO_BLOCKEX) && ((target->flags & TSO_INTERRUPTIBLE) == 0)) { blockedThrowTo(cap,target,msg); - unlockTSO(target); return THROWTO_BLOCKED; } else { raiseAsync(cap, target, msg->exception, false, NULL); - unlockTSO(target); return THROWTO_SUCCESS; } |