summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2018-07-14 20:02:03 -0400
committerBen Gamari <ben@smart-cactus.org>2018-07-14 20:02:42 -0400
commit502640c90c3d0fbb6c46257be14fdc7e3c694c6c (patch)
tree7242561a0b69807b2c2dc9d4488d12befe10e877
parent0905fec089b3270f540c7ee33959cbf8ecfcb4d7 (diff)
downloadhaskell-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
-rw-r--r--rts/STM.c24
1 files changed, 23 insertions, 1 deletions
diff --git a/rts/STM.c b/rts/STM.c
index abb44172dd..976ad87616 100644
--- a/rts/STM.c
+++ b/rts/STM.c
@@ -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) {