summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDylan Yudaken <dylany@fb.com>2019-12-10 15:05:40 +0000
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-02-08 10:17:17 -0500
commit7d452be454857549679b93a0682a3f6fedf5d7c1 (patch)
tree73bc0df8dd1370dd5f07eb6a1ac0835045b31c61
parent7755ffc2920facb7ed74efe379ad825feeaf1024 (diff)
downloadhaskell-7d452be454857549679b93a0682a3f6fedf5d7c1.tar.gz
Fix hs_try_putmvar losing track of running cap
If hs_try_putmvar was called through an unsafe import, it would lose track of the running cap causing a deadlock
-rw-r--r--rts/RtsAPI.c3
-rw-r--r--testsuite/tests/rts/T15427.hs21
-rw-r--r--testsuite/tests/rts/all.T2
3 files changed, 26 insertions, 0 deletions
diff --git a/rts/RtsAPI.c b/rts/RtsAPI.c
index 26433ac209..51a1f2b7cf 100644
--- a/rts/RtsAPI.c
+++ b/rts/RtsAPI.c
@@ -682,6 +682,7 @@ void hs_try_putmvar (/* in */ int capability,
{
Task *task = getTask();
Capability *cap;
+ Capability *task_old_cap USED_IF_THREADS;
if (capability < 0) {
capability = task->preferred_capability;
@@ -702,6 +703,7 @@ void hs_try_putmvar (/* in */ int capability,
// If the capability is free, we can perform the tryPutMVar immediately
if (cap->running_task == NULL) {
cap->running_task = task;
+ task_old_cap = task->cap;
task->cap = cap;
RELEASE_LOCK(&cap->lock);
@@ -712,6 +714,7 @@ void hs_try_putmvar (/* in */ int capability,
// Wake up the capability, which will start running the thread that we
// just awoke (if there was one).
releaseCapability(cap);
+ task->cap = task_old_cap;
} else {
PutMVar *p = stgMallocBytes(sizeof(PutMVar),"hs_try_putmvar");
// We cannot deref the StablePtr if we don't have a capability,
diff --git a/testsuite/tests/rts/T15427.hs b/testsuite/tests/rts/T15427.hs
new file mode 100644
index 0000000000..d4af150106
--- /dev/null
+++ b/testsuite/tests/rts/T15427.hs
@@ -0,0 +1,21 @@
+import Control.Concurrent.MVar
+import Control.Monad
+import Foreign.C.Types (CInt(..))
+import Foreign.StablePtr (StablePtr)
+import GHC.Conc
+
+foreign import ccall unsafe hs_try_putmvar :: CInt -> StablePtr PrimMVar -> IO ()
+
+main = do
+ mvs <- forM [0..numCapabilities] (\idx -> do
+ a <- newEmptyMVar
+ b <- newEmptyMVar
+ return $ (idx, a, b))
+ forM_ [mvs, reverse mvs] $ \mvars -> do
+ forM_ mvars $ (\(cap,a,b) -> forkOn cap $ do
+ takeMVar a
+ putMVar b ())
+ forM_ mvars $ \(cap, a, _) -> do
+ sp <- newStablePtrPrimMVar a
+ hs_try_putmvar (fromIntegral cap) sp
+ forM_ mvars $ \(_,_,b) -> takeMVar b
diff --git a/testsuite/tests/rts/all.T b/testsuite/tests/rts/all.T
index e4e2561c2e..ca0e652a48 100644
--- a/testsuite/tests/rts/all.T
+++ b/testsuite/tests/rts/all.T
@@ -417,3 +417,5 @@ test('InitEventLogging',
test('T17088',
[only_ways(['normal']), extra_run_opts('+RTS -c -A256k -RTS')],
compile_and_run, ['-rtsopts -O2'])
+
+test('T15427', normal, compile_and_run, [''])