summaryrefslogtreecommitdiff
path: root/rts/Schedule.h
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2008-09-09 13:32:23 +0000
committerSimon Marlow <marlowsd@gmail.com>2008-09-09 13:32:23 +0000
commitd572aed64d9c40dcc38a49b09d18f301555e4efb (patch)
treef44fa2291ccc16f953a55470a375583d31a0d85f /rts/Schedule.h
parent4318aa600015f0d7b4d977cb67071f3f8e7c3b0b (diff)
downloadhaskell-d572aed64d9c40dcc38a49b09d18f301555e4efb.tar.gz
Fix race condition in wakeupThreadOnCapability() (#2574)
wakeupThreadOnCapbility() is used to signal another capability that there is a thread waiting to be added to its run queue. It adds the thread to the (locked) wakeup queue on the remote capability. In order to do this, it has to modify the TSO's link field, which has a write barrier. The write barrier might put the TSO on the mutable list, and the bug was that it was using the mutable list of the *target* capability, which we do not have exclusive access to. We should be using the current Capabilty's mutable list in this case.
Diffstat (limited to 'rts/Schedule.h')
-rw-r--r--rts/Schedule.h15
1 files changed, 10 insertions, 5 deletions
diff --git a/rts/Schedule.h b/rts/Schedule.h
index 59bdb9e999..45aa000758 100644
--- a/rts/Schedule.h
+++ b/rts/Schedule.h
@@ -237,16 +237,21 @@ appendToBlockedQueue(StgTSO *tso)
#endif
#if defined(THREADED_RTS)
+// Assumes: my_cap is owned by the current Task. We hold
+// other_cap->lock, but we do not necessarily own other_cap; another
+// Task may be running on it.
INLINE_HEADER void
-appendToWakeupQueue (Capability *cap, StgTSO *tso)
+appendToWakeupQueue (Capability *my_cap, Capability *other_cap, StgTSO *tso)
{
ASSERT(tso->_link == END_TSO_QUEUE);
- if (cap->wakeup_queue_hd == END_TSO_QUEUE) {
- cap->wakeup_queue_hd = tso;
+ if (other_cap->wakeup_queue_hd == END_TSO_QUEUE) {
+ other_cap->wakeup_queue_hd = tso;
} else {
- setTSOLink(cap, cap->wakeup_queue_tl, tso);
+ // my_cap is passed to setTSOLink() because it may need to
+ // write to the mutable list.
+ setTSOLink(my_cap, other_cap->wakeup_queue_tl, tso);
}
- cap->wakeup_queue_tl = tso;
+ other_cap->wakeup_queue_tl = tso;
}
#endif