1-- | An implementation of a pool of threads
3{-# LANGUAGE RecursiveDo #-}
4module Control.Distributed.Process.Internal.ThreadPool
11import Control.Exception
14import qualified Data.Map as Map
17-- | A pool of worker threads that execute tasks.
19-- Each worker thread is named with a key @k@. Tasks are submitted to a
20-- specific worker using its key. While the worker is busy the tasks are queued.
21-- When there are no more queued tasks the worker ceases to exist.
23-- The next time a task is submitted the worker will be respawned.
25newtype ThreadPool k w = ThreadPool (IORef (Map.Map k (Maybe (IO ()), w)))
27-- Each worker has an entry in the map with a closure that contains all
28-- queued actions fot it.
30-- No entry in the map is kept for defunct workers.
32-- | Creates a pool with no workers.
33newThreadPool :: IO (ThreadPool k w)
34newThreadPool = fmap ThreadPool $ newIORef Map.empty
36-- | @submitTask pool fork k task@ submits a task for the worker @k@.
38-- If worker @k@ is busy, then the task is queued until the worker is available.
40-- If worker @k@ does not exist, then the given @fork@ operation is used to
41-- spawn the worker. @fork@ returns whatever information is deemed useful for
42-- later retrieval via 'lookupWorker'.
47 -> k -> IO () -> IO ()
48submitTask (ThreadPool mapRef) fork k task = mdo
49 m' <- join $ atomicModifyIORef mapRef $ \m ->
50 case Map.lookup k m of
51 -- There is no worker for this key, create one.
53 , do w <- fork $ flip onException terminateWorker $ do
56 return $ Map.insert k (Nothing, w) m
58 -- Queue an action for the existing worker.
60 (m', return $ Map.insert k (Just $ maybe task (>> task) mp, w) m)
63 continue = join $ atomicModifyIORef mapRef $ \m ->
64 case Map.lookup k m of
65 -- Execute the next batch of queued actions.
66 Just (Just p, w) -> (Map.insert k (Nothing, w) m, p >> continue)
67 -- There are no more queued actions. Terminate the worker.
68 Just (Nothing, w) -> (Map.delete k m, return ())
69 -- The worker key was removed already (?)
70 Nothing -> (m, return ())
71 -- Remove the worker key regardless of whether there are more queued
73 terminateWorker = atomicModifyIORef mapRef $ \m -> (Map.delete k m, ())
75-- | Looks up a worker with the given key.
76lookupWorker :: Ord k => ThreadPool k w -> k -> IO (Maybe w)
77lookupWorker (ThreadPool mapRef) k =
78 atomicModifyIORef mapRef $ \m -> (m, fmap snd $ Map.lookup k m)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list