content: {-# LANGUAGE UnboxedTuples #-}
  
  -- |
  -- Module      : Streamly.Internal.Control.ForkIO
  -- Copyright   : (c) 2017 Composewell Technologies
  -- License     : BSD-3-Clause
  -- Maintainer  : streamly@composewell.com
  -- Stability   : experimental
  -- Portability : GHC
  
  module Streamly.Internal.Control.ForkIO
      ( rawForkIO
      , forkIOManaged
      , forkManagedWith
      )
  where
  
  import Control.Concurrent (ThreadId, forkIO, killThread)
  import Control.Monad.IO.Class (MonadIO(..))
  import GHC.Conc (ThreadId(..))
  import GHC.Exts
  import GHC.IO (IO(..))
  import System.Mem.Weak (addFinalizer)
  
  -- | Stolen from the async package. The perf improvement is modest, 2% on a
  -- thread heavy benchmark (parallel composition using noop computations).
  -- A version of forkIO that does not include the outer exception
  -- handler: saves a bit of time when we will be installing our own
  -- exception handler.
  {-# INLINE rawForkIO #-}
  rawForkIO :: IO () -> IO ThreadId
  rawForkIO (IO action) = IO $ \ s ->
     case fork# action s of (# s1, tid #) -> (# s1, ThreadId tid #)
  
  -- | Fork a thread that is automatically killed as soon as the reference to the
  -- returned threadId is garbage collected.
  --
  {-# INLINABLE forkManagedWith #-}
  forkManagedWith :: MonadIO m => (m () -> m ThreadId) -> m () -> m ThreadId
  forkManagedWith fork action = do
      tid <- fork action
      liftIO $ addFinalizer tid (killThread tid)
      return tid
  
  -- | Fork a thread that is automatically killed as soon as the reference to the
  -- returned threadId is garbage collected.
  --
  {-# INLINABLE forkIOManaged #-}
  forkIOManaged :: IO () -> IO ThreadId
  forkIOManaged = forkManagedWith forkIO
  