Skip to content

Commit c26928d

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 4d3472a commit c26928d

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
@@ -163,7 +163,12 @@ import Prelude hiding (catch)
163163
import Control.Monad.IO.Class (liftIO)
164164
import Control.Applicative ((<$>))
165165
import Control.Monad.Reader (ask)
166-
import Control.Concurrent.MVar (newEmptyMVar, takeMVar, putMVar)
166+
import Control.Concurrent.MVar
167+
( MVar
168+
, newEmptyMVar
169+
, takeMVar
170+
, putMVar
171+
)
167172
import Control.Distributed.Static
168173
( Closure
169174
, closure
@@ -404,12 +409,22 @@ spawnChannelLocal proc = do
404409
callLocal ::
405410
Process a -- ^ Process to run
406411
-> Process a -- ^ Value returned
407-
callLocal proc = do
408-
mv <- liftIO newEmptyMVar
409-
self <- getSelfPid
410-
_ <- spawnLocal $ do
411-
link self
412-
try proc >>= liftIO . putMVar mv
413-
liftIO $ takeMVar mv >>=
414-
either (throwIO :: SomeException -> IO a) return
415-
412+
callLocal proc = mask $ \release -> do
413+
mv <- liftIO newEmptyMVar :: Process (MVar (Either SomeException a))
414+
child <- spawnLocal $ do
415+
ep <- try $ release $ proc
416+
liftIO $ putMVar mv ep
417+
liftIO (fetchResult mv) `onException`
418+
(do exit child "exception in parent process"
419+
waitForExit child)
420+
where
421+
waitForExit child = do
422+
bracket (monitor child)
423+
(unmonitor)
424+
(\mRef -> receiveWait
425+
[ matchIf (\(ProcessMonitorNotification ref _ _) -> ref == mRef)
426+
(\_ -> return ())
427+
])
428+
fetchResult mv = do
429+
rs <- takeMVar mv
430+
either throwIO return rs

0 commit comments

Comments
 (0)