diff options
author | Simon Marlow <marlowsd@gmail.com> | 2018-07-14 20:02:03 -0400 |
---|---|---|
committer | Ben Gamari <ben@smart-cactus.org> | 2018-07-14 20:02:42 -0400 |
commit | 502640c90c3d0fbb6c46257be14fdc7e3c694c6c (patch) | |
tree | 7242561a0b69807b2c2dc9d4488d12befe10e877 /rts | |
parent | 0905fec089b3270f540c7ee33959cbf8ecfcb4d7 (diff) | |
download | haskell-502640c90c3d0fbb6c46257be14fdc7e3c694c6c.tar.gz |
Optimise wakeups for STM
Avoids repeated wakeup messages being sent when a TVar is written to
multiple times. See comments for details.
Test Plan:
* Test from #15136 (will be added to stm shortly)
* existing stm tests
Reviewers: bgamari, osa1, erikd
Reviewed By: bgamari
Subscribers: rwbarton, thomie, carter
GHC Trac Issues: #15136
Differential Revision: https://phabricator.haskell.org/D4961
Diffstat (limited to 'rts')
-rw-r--r-- | rts/STM.c | 24 |
1 files changed, 23 insertions, 1 deletions
@@ -332,7 +332,29 @@ static void unpark_tso(Capability *cap, StgTSO *tso) { // queues: it's up to the thread itself to remove it from the wait queues // if it decides to do so when it is scheduled. - tryWakeupThread(cap,tso); + // Only the capability that owns this TSO may unblock it. We can + // call tryWakeupThread() which will either unblock it directly if + // it belongs to this cap, or send a message to the owning cap + // otherwise. + + // But we don't really want to send multiple messages if we write + // to the same TVar multiple times, and the owning cap hasn't yet + // woken up the thread and removed it from the TVar's watch list. + // So, we use the tso->block_info as a flag to indicate whether + // we've already done tryWakeupThread() for this thread. + + // Safety Note: we hold the TVar lock at this point, so we know + // that this thread is definitely still blocked, since the first + // thing a thread will do when it runs is remove itself from the + // TVar watch queues, and to do that it would need to lock the + // TVar. + + if (tso->block_info.closure != &stg_STM_AWOKEN_closure) { + // safe to do a non-atomic test-and-set here, because it's + // fine if we do multiple tryWakeupThread()s. + tso->block_info.closure = &stg_STM_AWOKEN_closure; + tryWakeupThread(cap,tso); + } } static void unpark_waiters_on(Capability *cap, StgTVar *s) { |