git.iko.soy/distributed-process
on master help sign in
Workaround race in callLocal.

Since processes spawned with spawnLocal do not inherit the masking state of the caller, it is possible for the child to be killed before filling the mvar from which the caller wants to grab the result. With this patch, when the parent is interrupted, it waits for the child to die.

commit87bb129af70540048688e401063b17aad94fce3d authorFacundo Domínguez <facundo.dominguez@tweag.io> dateWed 9 Sep 2015, 16:54 (11 years ago) parentd9b3631
1 file changed+17−3
src/Control/Distributed/Process.hs+17−3
src/Control/Distributed/Process.hs+17−3
@@ -415,7 +415,21 @@ spawnChannelLocal proc = do
415415callLocal :: Process a -> Process a
416416callLocal proc = mask $ \release -> do
417417 mv <- liftIO newEmptyMVar :: Process (MVar (Either SomeException a))
418− child <- spawnLocal $ try (release proc) >>= liftIO . putMVar mv
419− rs <- liftIO (takeMVar mv) `onException`
420− (kill child "exception in parent process" >> liftIO (takeMVar mv))
418+ child <- spawnLocal $ mask_ $ try (release proc) >>= liftIO . putMVar mv
419+ ref <- monitor child
420+ rs <- liftIO (takeMVar mv)
421+ `onException`
422+ (do kill child "exception in parent process"
423+ waitFor ref
424+ )
421425 either throw return rs
426+ where
427+ -- TODO: when processes spawned with spawnLocal inherit the masking state of
428+ -- the parent, this can be simplified to simply reading the MVar.
429+ --
430+ -- At the time of this writing, the spawned process is unmasked and can be
431+ -- killed before the MVar is filled.
432+ waitFor ref = receiveWait
433+ [ matchIf (\(ProcessMonitorNotification ref' _ _) -> ref == ref')
434+ (\_ -> return ())
435+ ]