aboutsummaryrefslogtreecommitdiff
path: root/server/src/Thermoprint/Server/Fork.hs
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/Thermoprint/Server/Fork.hs')
-rw-r--r--server/src/Thermoprint/Server/Fork.hs81
1 files changed, 81 insertions, 0 deletions
diff --git a/server/src/Thermoprint/Server/Fork.hs b/server/src/Thermoprint/Server/Fork.hs
new file mode 100644
index 0000000..402c1f8
--- /dev/null
+++ b/server/src/Thermoprint/Server/Fork.hs
@@ -0,0 +1,81 @@
1{-# LANGUAGE FlexibleContexts #-}
2
3module Thermoprint.Server.Fork
4 ( ThreadManager
5 , fork
6 , cleanup
7 , threadManager
8 ) where
9
10import Control.Monad.Reader.Class
11import Control.Monad.Trans.Class
12import Control.Monad.Trans.Reader (ReaderT, runReaderT)
13import Control.Monad.Catch
14
15import Control.Monad.IO.Class
16
17import Control.Monad
18import Control.Applicative
19import Data.Maybe
20
21import Data.Foldable
22
23import Data.Map (Map)
24import qualified Data.Map as Map
25
26import Control.Concurrent
27import Control.Concurrent.STM
28import Control.Concurrent.STM.TVar (TVar)
29import qualified Control.Concurrent.STM.TVar as T
30import Control.Concurrent.STM.TSem (TSem)
31import qualified Control.Concurrent.STM.TSem as S
32
33data ThreadManager m = ThreadManager
34 { fork :: m () -> m ThreadId
35 , cleanup :: m ()
36 }
37
38threadManager :: (MonadIO m, MonadMask m) => (m () -> m ThreadId) -> m (ThreadManager m)
39threadManager f = do
40 tVar <- newTVar Map.empty
41 return ThreadManager
42 { fork = \act -> do
43 let
44 unregisterSelf :: MonadIO m => m ()
45 unregisterSelf = do
46 tMap <- readTVar tVar
47 tId <- liftIO $ myThreadId
48 modifyTVar' tVar $ Map.delete tId
49 maybeM signalTSem $ Map.lookup tId tMap
50
51 mask $ \unmask -> do
52 tId <- f (unmask act `finally` unregisterSelf)
53 modifyTVar' tVar =<< (Map.insert tId <$> newTSem 0)
54 return tId
55 , cleanup = liftIO $
56 mapM_ (\(tId, s) -> killThread tId >> waitTSem s) . Map.toList =<< readTVar tVar
57 }
58 where
59 atomically' :: MonadIO m => STM a -> m a
60 atomically' = liftIO . atomically
61
62 newTSem :: MonadIO m => Int -> m TSem
63 newTSem = atomically' . S.newTSem
64
65 waitTSem :: MonadIO m => TSem -> m ()
66 waitTSem = atomically' . S.waitTSem
67
68 signalTSem :: MonadIO m => TSem -> m ()
69 signalTSem = atomically' . S.signalTSem
70
71 newTVar :: MonadIO m => a -> m (TVar a)
72 newTVar = atomically' . T.newTVar
73
74 readTVar :: MonadIO m => TVar a -> m a
75 readTVar = atomically' . T.readTVar
76
77 modifyTVar' :: MonadIO m => TVar a -> (a -> a) -> m ()
78 modifyTVar' t = atomically' . T.modifyTVar t
79
80maybeM :: Applicative m => (a -> m ()) -> Maybe a -> m ()
81maybeM = maybe $ pure ()