@@ -33,6 +33,7 @@ module Troupe.Process
3333 exit ,
3434 isProcessAlive ,
3535 spawnWithOptions ,
36+ kindaUnlift ,
3637 SpawnOptions (.. ),
3738 ThreadAffinity (.. ),
3839 WithMonitor (.. ),
@@ -46,7 +47,7 @@ module Troupe.Process
4647where
4748
4849import Control.Applicative (Alternative , (<|>) )
49- import Control.Concurrent (throwTo )
50+ import Control.Concurrent (threadDelay , throwTo )
5051import Control.Concurrent.Async
5152 ( async ,
5253 asyncThreadId ,
@@ -100,7 +101,7 @@ import Control.Exception.Safe
100101 uninterruptibleMask_ ,
101102 withException ,
102103 )
103- import Control.Monad (MonadPlus , forM , unless , when )
104+ import Control.Monad (MonadPlus , forever , forM , unless , when )
104105import Control.Monad.Error.Class (MonadError )
105106import Control.Monad.Fix (MonadFix )
106107import Control.Monad.IO.Class (MonadIO , liftIO )
@@ -583,17 +584,7 @@ data ThreadAffinity
583584-- 'Troupe.spawn', 'Troupe.spawnLink' and 'Troupe.spawnMonitor' are specialized
584585-- versions of this function.
585586spawnWithOptions :: (MonadProcess r m , MonadIO m ) => SpawnOptions t -> Process r a -> m t
586- spawnWithOptions ! options process = do
587- let cb pid = do
588- when (spawnOptionsLink options) $
589- linkSTM pid
590- case spawnOptionsMonitor options of
591- WithoutMonitor -> pure pid
592- WithMonitor -> do
593- ref <- monitorSTM pid
594- pure (pid, ref)
595-
596- spawnImpl (spawnOptionsAffinity options) cb process
587+ spawnWithOptions options = spawnImpl (spawnOptionsAffinity options) (mkCallback options)
597588{-# SPECIALIZE spawnWithOptions :: SpawnOptions t -> Process r a -> Process r t #-}
598589
599590data SendOptions = SendOptions
@@ -719,22 +710,43 @@ after ::
719710after = MatchAfter
720711{-# INLINE after #-}
721712
713+ kindaUnlift :: (MonadProcess r m , MonadIO io ) => ((ThreadAffinity -> Process r a -> io () ) -> m b ) -> m b
714+ kindaUnlift foreignSpawner = do
715+ env <- getProcessEnv
716+ foreignSpawner $ \ affinity action -> do
717+ _pid <- spawnImplWith env affinity pure action -- XXX: does it make sense to link/monitor a wrapped process?
718+ -- TODO: spawnImplWith should have a blocking version
719+ liftIO . forever $
720+ threadDelay 10000000
721+
722+ mkCallback :: SpawnOptions r -> ProcessId -> ReaderT (ProcessEnv a ) STM r
723+ mkCallback ! options pid = do
724+ when (spawnOptionsLink options) $
725+ linkSTM pid
726+ case spawnOptionsMonitor options of
727+ WithoutMonitor -> pure pid
728+ WithMonitor -> do
729+ ref <- monitorSTM pid
730+ pure (pid, ref)
731+
722732spawnImpl :: (MonadProcess r m , MonadIO m ) => ThreadAffinity -> (ProcessId -> ReaderT (ProcessEnv r ) STM t ) -> Process r a -> m t
723733spawnImpl affinity cb process = do
724734 currentEnv <- getProcessEnv
735+ spawnImplWith currentEnv affinity cb process
725736
726- liftIO $ do
727- processContext <- newProcessContext (processEnvNodeContext currentEnv)
728- let processEnv = currentEnv {processEnvProcessContext = processContext}
737+ spawnImplWith :: MonadIO m => ProcessEnv r -> ThreadAffinity -> (ProcessId -> ReaderT (ProcessEnv r ) STM t ) -> Process r a -> m t
738+ spawnImplWith currentEnv affinity cb process = liftIO $ do
739+ processContext <- newProcessContext (processEnvNodeContext currentEnv)
740+ let processEnv = currentEnv {processEnvProcessContext = processContext}
729741
730- m <- newEmptyTMVarIO
742+ m <- newEmptyTMVarIO
731743
732- bracketOnError
733- (run currentEnv processEnv m)
734- uninterruptibleCancel
735- (wrapup m)
744+ bracketOnError
745+ (run processEnv m)
746+ uninterruptibleCancel
747+ (wrapup m)
736748 where
737- run currentEnv processEnv m = mask_ $ async $ do
749+ run processEnv m = mask_ $ async $ do
738750 c <- newEmptyTMVarIO
739751 let act restore = atomically (readTMVar c) >>= \ () -> restore (runProcess process processEnv)
740752
0 commit comments