git.iko.soy/distributed-process
on master help sign in
Avoid racy blocking behavior in closeLocalNode.
1e1636fFacundo Domínguez
src/Control/Distributed/Process/Node.hs+13−9
@@ -326,16 +326,20 @@ startServiceProcesses node = do
326-- | Force-close a local node, killing all processes on that node.
326-- | Force-close a local node, killing all processes on that node.
327closeLocalNode :: LocalNode -> IO ()
327closeLocalNode :: LocalNode -> IO ()
328closeLocalNode node = do
328closeLocalNode node = do
329+ -- Kill processes after refilling the mvar. Otherwise, there is potential for
330+ -- deadlock as a dying process tries to get the mvar while masking exceptions
331+ -- uninterruptibly.
329− modifyMVar_ (localState node) $ \st -> case st of
332+ join $ modifyMVar (localState node) $ \st -> case st of
330 LocalNodeValid vst -> do
333 LocalNodeValid vst -> do
334+ return ( LocalNodeClosed
331− forM_ (vst ^. localProcesses) $ \lproc ->
335+ , forM_ (vst ^. localProcesses) $ \lproc ->
332− -- Semantics of 'throwTo' guarantee that target thread will get
336+ -- Semantics of 'throwTo' guarantee that target thread will get
333− -- delivered an exception. Therefore, target thread will be killed
337+ -- delivered an exception. Therefore, target thread will be
334− -- eventually and that's as good as we can do. No need to wait for
338+ -- killed eventually and that's as good as we can do. No need
335− -- thread to actually finish dying.
339+ -- to wait for thread to actually finish dying.
336− killThread (processThread lproc)
340+ killThread (processThread lproc)
337− return LocalNodeClosed
341+ )
338− LocalNodeClosed -> return LocalNodeClosed
342+ LocalNodeClosed -> return (LocalNodeClosed, return ())
339 -- This call will have the effect of shutting down the NC as well (see
343 -- This call will have the effect of shutting down the NC as well (see
340 -- 'createBareLocalNode').
344 -- 'createBareLocalNode').
341 NT.closeEndPoint (localEndPoint node)
345 NT.closeEndPoint (localEndPoint node)