module HaskellWorks.CabalCache.Concurrent.Fork where

import Control.Monad

import qualified Control.Concurrent     as IO
import qualified Control.Concurrent.STM as STM

forkThreadsWait :: Int -> IO () -> IO ()
forkThreadsWait :: Int -> IO () -> IO ()
forkThreadsWait Int
n IO ()
f = do
  TVar Int
tDone <- STM (TVar Int) -> IO (TVar Int)
forall a. STM a -> IO a
STM.atomically (STM (TVar Int) -> IO (TVar Int))
-> STM (TVar Int) -> IO (TVar Int)
forall a b. (a -> b) -> a -> b
$ Int -> STM (TVar Int)
forall a. a -> STM (TVar a)
STM.newTVar (Int
0 :: Int)
  [Int] -> (Int -> IO ThreadId) -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [Int
1 .. Int
n] ((Int -> IO ThreadId) -> IO ()) -> (Int -> IO ThreadId) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Int
_ -> IO () -> IO ThreadId
IO.forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
forall a b. (a -> b) -> a -> b
$ do
    IO ()
f
    STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ TVar Int -> (Int -> Int) -> STM ()
forall a. TVar a -> (a -> a) -> STM ()
STM.modifyTVar TVar Int
tDone (Int -> Int -> Int
forall a. Num a => a -> a -> a
+Int
1)

  STM () -> IO ()
forall a. STM a -> IO a
STM.atomically (STM () -> IO ()) -> STM () -> IO ()
forall a b. (a -> b) -> a -> b
$ do
    Int
done <- TVar Int -> STM Int
forall a. TVar a -> STM a
STM.readTVar TVar Int
tDone
    Bool -> STM () -> STM ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
done Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Int
n) STM ()
forall a. STM a
STM.retry