module Control.Concurrent.Throttled
  ( Throttle
  , newThrottle
  , throttled
  )  where

--------------------------------------------------------------------------------
import Control.Monad
import Control.Exception
import Control.Concurrent
--------------------------------------------------------------------------------

newtype Throttle
  = Throttle (MVar (MVar ()))

newThrottle :: Int -> IO Throttle
newThrottle maxConcurrent = do
  mv <- newEmptyMVar
  forM_ [1..maxConcurrent] $ \_ -> forkIO . forever $ do
    m <- takeMVar mv
    putMVar m ()
    putMVar m ()
  return $ Throttle mv

throttled :: Throttle -> IO a -> IO a
throttled (Throttle mv) act = do
  m <- newEmptyMVar
  putMVar mv m
  readMVar m
  act `finally` takeMVar m