Skip to content

Commit a05ea06

Browse files
committed
Improve exception handling in callLocal.
callLocal had the following flaws: 1. It could leak the worker process if the parent process was interrupted but not killed. Linking the worker to the parent wouldn't help. 2. If the parent was interrupted, `callLocal` would return the control before the worker is terminated. This would make slightly harder to synchronize with whatever task the worker is doing. This patch fixes both issues.
1 parent db5aa53 commit a05ea06

File tree

1 file changed

+25
-10
lines changed

1 file changed

+25
-10
lines changed

src/Control/Distributed/Process.hs

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,12 @@ import Prelude hiding (catch)
162162
import Control.Monad.IO.Class (liftIO)
163163
import Control.Applicative ((<$>))
164164
import Control.Monad.Reader (ask)
165-
import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar)
165+
import Control.Concurrent.MVar
166+
( MVar
167+
, newEmptyMVar
168+
, takeMVar
169+
, putMVar
170+
)
166171
import Control.Distributed.Static
167172
( Closure
168173
, closure
@@ -402,12 +407,22 @@ spawnChannelLocal proc = do
402407
callLocal ::
403408
Process a -- ^ Process to run
404409
-> Process a -- ^ Value returned
405-
callLocal proc = do
406-
mv <- liftIO newEmptyMVar
407-
self <- getSelfPid
408-
_ <- spawnLocal $ do
409-
link self
410-
try proc >>= liftIO . putMVar mv
411-
liftIO $ takeMVar mv >>=
412-
either (throwIO :: SomeException -> IO a) return
413-
410+
callLocal proc = mask $ \release -> do
411+
mv <- liftIO newEmptyMVar :: Process (MVar (Either SomeException a))
412+
child <- spawnLocal $ do
413+
ep <- try $ release $ proc
414+
liftIO $ putMVar mv ep
415+
liftIO (fetchResult mv) `onException`
416+
(do exit child "exception in parent process"
417+
waitForExit child)
418+
where
419+
waitForExit child = do
420+
bracket (monitor child)
421+
(unmonitor)
422+
(\mRef -> receiveWait
423+
[ matchIf (\(ProcessMonitorNotification ref _ _) -> ref == mRef)
424+
(\_ -> return ())
425+
])
426+
fetchResult mv = do
427+
rs <- takeMVar mv
428+
either throwIO return rs

0 commit comments

Comments
 (0)