summaryrefslogtreecommitdiff
path: root/rts/Capability.h
diff options
context:
space:
mode:
authorSimon Marlow <marlowsd@gmail.com>2015-06-19 15:12:24 +0100
committerSimon Marlow <marlowsd@gmail.com>2015-06-26 09:32:23 +0100
commit111ba4beda4ffc48381723da12e5b237d7f9ac59 (patch)
tree84ec683a20ea340bd60877daa8ab962e5eebaa2e /rts/Capability.h
parentbe0ce8718ea40b091e69dd48fe6bc62b6b551154 (diff)
downloadhaskell-111ba4beda4ffc48381723da12e5b237d7f9ac59.tar.gz
Fix deadlock (#10545)
yieldCapability() was not prepared to be called by a Task that is not either a worker or a bound Task. This could happen if we ended up in yieldCapability via this call stack: performGC() scheduleDoGC() requestSync() yieldCapability() and there were a few other ways this could happen via requestSync. The fix is to handle this case in yieldCapability(): when the Task is not a worker or a bound Task, we put it on the returning_workers queue, where it will be woken up again. Summary of changes: * `yieldCapability`: factored out subroutine waitForWorkerCapability` * `waitForReturnCapability` renamed to `waitForCapability`, and factored out subroutine `waitForReturnCapability` * `releaseCapabilityAndQueue` worker renamed to `enqueueWorker`, does not take a lock and no longer tests if `!isBoundTask()` * `yieldCapability` adjusted for refactorings, only change in behavior is when it is not a worker or bound task. Test Plan: * new test concurrent/should_run/performGC * validate Reviewers: niteria, austin, ezyang, bgamari Subscribers: thomie, bgamari Differential Revision: https://phabricator.haskell.org/D997 GHC Trac Issues: #10545
Diffstat (limited to 'rts/Capability.h')
-rw-r--r--rts/Capability.h8
1 files changed, 1 insertions, 7 deletions
diff --git a/rts/Capability.h b/rts/Capability.h
index 420bfd5c80..fb9f0aa181 100644
--- a/rts/Capability.h
+++ b/rts/Capability.h
@@ -248,7 +248,7 @@ extern volatile StgWord pending_sync;
//
// On return, *cap is non-NULL, and points to the Capability acquired.
//
-void waitForReturnCapability (Capability **cap/*in/out*/, Task *task);
+void waitForCapability (Capability **cap/*in/out*/, Task *task);
EXTERN_INLINE void recordMutableCap (StgClosure *p, Capability *cap, nat gen);
@@ -269,12 +269,6 @@ EXTERN_INLINE void recordClosureMutated (Capability *cap, StgClosure *p);
//
rtsBool yieldCapability (Capability** pCap, Task *task, rtsBool gcAllowed);
-// Acquires a capability for doing some work.
-//
-// On return: pCap points to the capability.
-//
-void waitForCapability (Task *task, Mutex *mutex, Capability **pCap);
-
// Wakes up a worker thread on just one Capability, used when we
// need to service some global event.
//