Skip to content

Commit cd9dff2

Browse files
committed
Improve exception handling in callLocal.
callLocal had few flaws, 1. it could leak worker process in parent process received an exception but handles it. Then process was not killed, so linking worker to parent didn't help 2. A parent process could exit `callLocal` while child process is still alive. This this patch both things are solved alltogether.
1 parent db5aa53 commit cd9dff2

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_ $ do
411+
mv <- liftIO newEmptyMVar :: Process (MVar (Either SomeException a))
412+
child <- spawnLocal $ mask $ \release -> 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+
liftIO $ either throwIO return rs

0 commit comments

Comments
 (0)