{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ConstraintKinds #-}
-- | Allocate resources which are guaranteed to be released.
--
-- For more information, see <https://github.com/snoyberg/conduit/tree/master/resourcet#readme>.
--
-- One point to note: all register cleanup actions live in the @IO@ monad, not
-- the main monad. This allows both more efficient code, and for monads to be
-- transformed.
module Control.Monad.Trans.Resource
    ( -- * Data types
      ResourceT
    , ResIO
    , ReleaseKey
      -- * Unwrap
    , runResourceT
      -- ** Check cleanup exceptions
    , runResourceTChecked
    , ResourceCleanupException (..)
      -- * Special actions
    , resourceForkWith
    , resourceForkIO
      -- * Monad transformation
    , transResourceT
    , joinResourceT
      -- * Registering/releasing
    , allocate
    , allocate_
    , register
    , release
    , unprotect
    , resourceMask
      -- * Type class/associated types
    , MonadResource (..)
    , MonadResourceBase
      -- ** Low-level
    , InvalidAccess (..)
      -- * Re-exports
    , MonadUnliftIO
      -- * Internal state
      -- $internalState
    , InternalState
    , getInternalState
    , runInternalState
    , withInternalState
    , createInternalState
    , closeInternalState
      -- * Reexport
    , MonadThrow (..)
    ) where

import qualified Data.IntMap as IntMap
import qualified Data.IORef as I
import Control.Monad.IO.Unlift (MonadIO (..), MonadUnliftIO, withRunInIO)
import qualified Control.Exception as E

import Control.Monad.Trans.Resource.Internal

import Control.Concurrent (ThreadId, forkIO)

import Control.Monad.Catch (MonadThrow, throwM)
import Data.Acquire.Internal (ReleaseType (..))



-- | Register some action that will be called precisely once, either when
-- 'runResourceT' is called, or when the 'ReleaseKey' is passed to 'release'.
--
-- Since 0.3.0
register :: MonadResource m => IO () -> m ReleaseKey
register :: IO () -> m ReleaseKey
register = ResourceT IO ReleaseKey -> m ReleaseKey
forall (m :: * -> *) a. MonadResource m => ResourceT IO a -> m a
liftResourceT (ResourceT IO ReleaseKey -> m ReleaseKey)
-> (IO () -> ResourceT IO ReleaseKey) -> IO () -> m ReleaseKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> ResourceT IO ReleaseKey
registerRIO

-- | Call a release action early, and deregister it from the list of cleanup
-- actions to be performed.
--
-- Since 0.3.0
release :: MonadIO m => ReleaseKey -> m ()
release :: ReleaseKey -> m ()
release (ReleaseKey IORef ReleaseMap
istate Int
rk) = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> IO () -> m ()
forall a b. (a -> b) -> a -> b
$ IORef ReleaseMap -> Int -> (Maybe (IO ()) -> IO ()) -> IO ()
forall a.
IORef ReleaseMap -> Int -> (Maybe (IO ()) -> IO a) -> IO a
release' IORef ReleaseMap
istate Int
rk
    (IO () -> (IO () -> IO ()) -> Maybe (IO ()) -> IO ()
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) IO () -> IO ()
forall a. a -> a
id)

-- | Unprotect resource from cleanup actions; this allows you to send
-- resource into another resourcet process and reregister it there.
-- It returns a release action that should be run in order to clean
-- resource or Nothing in case if resource is already freed.
--
-- Since 0.4.5
unprotect :: MonadIO m => ReleaseKey -> m (Maybe (IO ()))
unprotect :: ReleaseKey -> m (Maybe (IO ()))
unprotect (ReleaseKey IORef ReleaseMap
istate Int
rk) = IO (Maybe (IO ())) -> m (Maybe (IO ()))
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Maybe (IO ())) -> m (Maybe (IO ())))
-> IO (Maybe (IO ())) -> m (Maybe (IO ()))
forall a b. (a -> b) -> a -> b
$ IORef ReleaseMap
-> Int
-> (Maybe (IO ()) -> IO (Maybe (IO ())))
-> IO (Maybe (IO ()))
forall a.
IORef ReleaseMap -> Int -> (Maybe (IO ()) -> IO a) -> IO a
release' IORef ReleaseMap
istate Int
rk Maybe (IO ()) -> IO (Maybe (IO ()))
forall (m :: * -> *) a. Monad m => a -> m a
return

-- | Perform some allocation, and automatically register a cleanup action.
--
-- This is almost identical to calling the allocation and then
-- @register@ing the release action, but this properly handles masking of
-- asynchronous exceptions.
--
-- Since 0.3.0
allocate :: MonadResource m
         => IO a -- ^ allocate
         -> (a -> IO ()) -- ^ free resource
         -> m (ReleaseKey, a)
allocate :: IO a -> (a -> IO ()) -> m (ReleaseKey, a)
allocate IO a
a = ResourceT IO (ReleaseKey, a) -> m (ReleaseKey, a)
forall (m :: * -> *) a. MonadResource m => ResourceT IO a -> m a
liftResourceT (ResourceT IO (ReleaseKey, a) -> m (ReleaseKey, a))
-> ((a -> IO ()) -> ResourceT IO (ReleaseKey, a))
-> (a -> IO ())
-> m (ReleaseKey, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> (a -> IO ()) -> ResourceT IO (ReleaseKey, a)
forall a. IO a -> (a -> IO ()) -> ResourceT IO (ReleaseKey, a)
allocateRIO IO a
a

-- | Perform some allocation where the return value is not required, and
-- automatically register a cleanup action.
--
-- @allocate_@ is to @allocate@ as @bracket_@ is to @bracket@
--
-- This is almost identical to calling the allocation and then
-- @register@ing the release action, but this properly handles masking of
-- asynchronous exceptions.
--
-- @since 1.2.4
allocate_ :: MonadResource m
          => IO a -- ^ allocate
          -> IO () -- ^ free resource
          -> m ReleaseKey
allocate_ :: IO a -> IO () -> m ReleaseKey
allocate_ IO a
a = ((ReleaseKey, a) -> ReleaseKey)
-> m (ReleaseKey, a) -> m ReleaseKey
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ReleaseKey, a) -> ReleaseKey
forall a b. (a, b) -> a
fst (m (ReleaseKey, a) -> m ReleaseKey)
-> (IO () -> m (ReleaseKey, a)) -> IO () -> m ReleaseKey
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> (a -> IO ()) -> m (ReleaseKey, a)
forall (m :: * -> *) a.
MonadResource m =>
IO a -> (a -> IO ()) -> m (ReleaseKey, a)
allocate IO a
a ((a -> IO ()) -> m (ReleaseKey, a))
-> (IO () -> a -> IO ()) -> IO () -> m (ReleaseKey, a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO () -> a -> IO ()
forall a b. a -> b -> a
const

-- | Perform asynchronous exception masking.
--
-- This is more general then @Control.Exception.mask@, yet more efficient
-- than @Control.Exception.Lifted.mask@.
--
-- Since 0.3.0
resourceMask :: MonadResource m => ((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b) -> m b
resourceMask :: ((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b)
-> m b
resourceMask (forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b
r = ResourceT IO b -> m b
forall (m :: * -> *) a. MonadResource m => ResourceT IO a -> m a
liftResourceT (((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b)
-> ResourceT IO b
forall b.
((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b)
-> ResourceT IO b
resourceMaskRIO (forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b
r)

allocateRIO :: IO a -> (a -> IO ()) -> ResourceT IO (ReleaseKey, a)
allocateRIO :: IO a -> (a -> IO ()) -> ResourceT IO (ReleaseKey, a)
allocateRIO IO a
acquire a -> IO ()
rel = (IORef ReleaseMap -> IO (ReleaseKey, a))
-> ResourceT IO (ReleaseKey, a)
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT ((IORef ReleaseMap -> IO (ReleaseKey, a))
 -> ResourceT IO (ReleaseKey, a))
-> (IORef ReleaseMap -> IO (ReleaseKey, a))
-> ResourceT IO (ReleaseKey, a)
forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
istate -> IO (ReleaseKey, a) -> IO (ReleaseKey, a)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (ReleaseKey, a) -> IO (ReleaseKey, a))
-> IO (ReleaseKey, a) -> IO (ReleaseKey, a)
forall a b. (a -> b) -> a -> b
$ IO (ReleaseKey, a) -> IO (ReleaseKey, a)
forall a. IO a -> IO a
E.mask_ (IO (ReleaseKey, a) -> IO (ReleaseKey, a))
-> IO (ReleaseKey, a) -> IO (ReleaseKey, a)
forall a b. (a -> b) -> a -> b
$ do
    a
a <- IO a
acquire
    ReleaseKey
key <- IORef ReleaseMap -> IO () -> IO ReleaseKey
register' IORef ReleaseMap
istate (IO () -> IO ReleaseKey) -> IO () -> IO ReleaseKey
forall a b. (a -> b) -> a -> b
$ a -> IO ()
rel a
a
    (ReleaseKey, a) -> IO (ReleaseKey, a)
forall (m :: * -> *) a. Monad m => a -> m a
return (ReleaseKey
key, a
a)

registerRIO :: IO () -> ResourceT IO ReleaseKey
registerRIO :: IO () -> ResourceT IO ReleaseKey
registerRIO IO ()
rel = (IORef ReleaseMap -> IO ReleaseKey) -> ResourceT IO ReleaseKey
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT ((IORef ReleaseMap -> IO ReleaseKey) -> ResourceT IO ReleaseKey)
-> (IORef ReleaseMap -> IO ReleaseKey) -> ResourceT IO ReleaseKey
forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
istate -> IO ReleaseKey -> IO ReleaseKey
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO ReleaseKey -> IO ReleaseKey) -> IO ReleaseKey -> IO ReleaseKey
forall a b. (a -> b) -> a -> b
$ IORef ReleaseMap -> IO () -> IO ReleaseKey
register' IORef ReleaseMap
istate IO ()
rel

resourceMaskRIO :: ((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b) -> ResourceT IO b
resourceMaskRIO :: ((forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b)
-> ResourceT IO b
resourceMaskRIO (forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b
f = (IORef ReleaseMap -> IO b) -> ResourceT IO b
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT ((IORef ReleaseMap -> IO b) -> ResourceT IO b)
-> (IORef ReleaseMap -> IO b) -> ResourceT IO b
forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
istate -> IO b -> IO b
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO b -> IO b) -> IO b -> IO b
forall a b. (a -> b) -> a -> b
$ ((forall a. IO a -> IO a) -> IO b) -> IO b
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
E.mask (((forall a. IO a -> IO a) -> IO b) -> IO b)
-> ((forall a. IO a -> IO a) -> IO b) -> IO b
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore ->
    let ResourceT IORef ReleaseMap -> IO b
f' = (forall a. ResourceT IO a -> ResourceT IO a) -> ResourceT IO b
f ((forall a. IO a -> IO a)
-> forall a. ResourceT IO a -> ResourceT IO a
go forall a. IO a -> IO a
restore)
     in IORef ReleaseMap -> IO b
f' IORef ReleaseMap
istate
  where
    go :: (forall a. IO a -> IO a) -> (forall a. ResourceT IO a -> ResourceT IO a)
    go :: (forall a. IO a -> IO a)
-> forall a. ResourceT IO a -> ResourceT IO a
go forall a. IO a -> IO a
r (ResourceT IORef ReleaseMap -> IO a
g) = (IORef ReleaseMap -> IO a) -> ResourceT IO a
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT (\IORef ReleaseMap
i -> IO a -> IO a
forall a. IO a -> IO a
r (IORef ReleaseMap -> IO a
g IORef ReleaseMap
i))



release' :: I.IORef ReleaseMap
         -> Int
         -> (Maybe (IO ()) -> IO a)
         -> IO a
release' :: IORef ReleaseMap -> Int -> (Maybe (IO ()) -> IO a) -> IO a
release' IORef ReleaseMap
istate Int
key Maybe (IO ()) -> IO a
act = IO a -> IO a
forall a. IO a -> IO a
E.mask_ (IO a -> IO a) -> IO a -> IO a
forall a b. (a -> b) -> a -> b
$ do
    Maybe (IO ())
maction <- IORef ReleaseMap
-> (ReleaseMap -> (ReleaseMap, Maybe (IO ())))
-> IO (Maybe (IO ()))
forall a b. IORef a -> (a -> (a, b)) -> IO b
I.atomicModifyIORef IORef ReleaseMap
istate ReleaseMap -> (ReleaseMap, Maybe (IO ()))
lookupAction
    Maybe (IO ()) -> IO a
act Maybe (IO ())
maction
  where
    lookupAction :: ReleaseMap -> (ReleaseMap, Maybe (IO ()))
lookupAction rm :: ReleaseMap
rm@(ReleaseMap Int
next RefCount
rf IntMap (ReleaseType -> IO ())
m) =
        case Int
-> IntMap (ReleaseType -> IO ()) -> Maybe (ReleaseType -> IO ())
forall a. Int -> IntMap a -> Maybe a
IntMap.lookup Int
key IntMap (ReleaseType -> IO ())
m of
            Maybe (ReleaseType -> IO ())
Nothing -> (ReleaseMap
rm, Maybe (IO ())
forall a. Maybe a
Nothing)
            Just ReleaseType -> IO ()
action ->
                ( Int -> RefCount -> IntMap (ReleaseType -> IO ()) -> ReleaseMap
ReleaseMap Int
next RefCount
rf (IntMap (ReleaseType -> IO ()) -> ReleaseMap)
-> IntMap (ReleaseType -> IO ()) -> ReleaseMap
forall a b. (a -> b) -> a -> b
$ Int
-> IntMap (ReleaseType -> IO ()) -> IntMap (ReleaseType -> IO ())
forall a. Int -> IntMap a -> IntMap a
IntMap.delete Int
key IntMap (ReleaseType -> IO ())
m
                , IO () -> Maybe (IO ())
forall a. a -> Maybe a
Just (ReleaseType -> IO ()
action ReleaseType
ReleaseEarly)
                )
    -- We tried to call release, but since the state is already closed, we
    -- can assume that the release action was already called. Previously,
    -- this threw an exception, though given that @release@ can be called
    -- from outside the context of a @ResourceT@ starting with version
    -- 0.4.4, it's no longer a library misuse or a library bug.
    lookupAction ReleaseMap
ReleaseMapClosed = (ReleaseMap
ReleaseMapClosed, Maybe (IO ())
forall a. Maybe a
Nothing)



-- | Unwrap a 'ResourceT' transformer, and call all registered release actions.
--
-- Note that there is some reference counting involved due to 'resourceForkIO'.
-- If multiple threads are sharing the same collection of resources, only the
-- last call to @runResourceT@ will deallocate the resources.
--
-- /NOTE/ Since version 1.2.0, this function will throw a
-- 'ResourceCleanupException' if any of the cleanup functions throw an
-- exception.
--
-- @since 0.3.0
runResourceT :: MonadUnliftIO m => ResourceT m a -> m a
runResourceT :: ResourceT m a -> m a
runResourceT (ResourceT IORef ReleaseMap -> m a
r) = ((forall a. m a -> IO a) -> IO a) -> m a
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. m a -> IO a) -> IO a) -> m a)
-> ((forall a. m a -> IO a) -> IO a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> IO a
run -> do
    IORef ReleaseMap
istate <- IO (IORef ReleaseMap)
forall (m :: * -> *). MonadIO m => m (IORef ReleaseMap)
createInternalState
    ((forall a. IO a -> IO a) -> IO a) -> IO a
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
E.mask (((forall a. IO a -> IO a) -> IO a) -> IO a)
-> ((forall a. IO a -> IO a) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
        a
res <- IO a -> IO a
forall a. IO a -> IO a
restore (m a -> IO a
forall a. m a -> IO a
run (IORef ReleaseMap -> m a
r IORef ReleaseMap
istate)) IO a -> (SomeException -> IO a) -> IO a
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`E.catch` \SomeException
e -> do
            Maybe SomeException -> IORef ReleaseMap -> IO ()
stateCleanupChecked (SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just SomeException
e) IORef ReleaseMap
istate
            SomeException -> IO a
forall e a. Exception e => e -> IO a
E.throwIO SomeException
e
        Maybe SomeException -> IORef ReleaseMap -> IO ()
stateCleanupChecked Maybe SomeException
forall a. Maybe a
Nothing IORef ReleaseMap
istate
        a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
res

-- | Backwards compatible alias for 'runResourceT'.
--
-- @since 1.1.11
runResourceTChecked :: MonadUnliftIO m => ResourceT m a -> m a
runResourceTChecked :: ResourceT m a -> m a
runResourceTChecked = ResourceT m a -> m a
forall (m :: * -> *) a. MonadUnliftIO m => ResourceT m a -> m a
runResourceT
{-# INLINE runResourceTChecked #-}

bracket_ :: MonadUnliftIO m
         => IO () -- ^ allocate
         -> IO () -- ^ normal cleanup
         -> IO () -- ^ exceptional cleanup
         -> m a
         -> m a
bracket_ :: IO () -> IO () -> IO () -> m a -> m a
bracket_ IO ()
alloc IO ()
cleanupNormal IO ()
cleanupExc m a
inside =
    ((forall a. m a -> IO a) -> IO a) -> m a
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. m a -> IO a) -> IO a) -> m a)
-> ((forall a. m a -> IO a) -> IO a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> IO a
run -> ((forall a. IO a -> IO a) -> IO a) -> IO a
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
E.mask (((forall a. IO a -> IO a) -> IO a) -> IO a)
-> ((forall a. IO a -> IO a) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore -> do
        IO ()
alloc
        a
res <- IO a -> IO a
forall a. IO a -> IO a
restore (m a -> IO a
forall a. m a -> IO a
run m a
inside) IO a -> IO () -> IO a
forall a b. IO a -> IO b -> IO a
`E.onException` IO ()
cleanupExc
        IO ()
cleanupNormal
        a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return a
res

-- | This function mirrors @join@ at the transformer level: it will collapse
-- two levels of @ResourceT@ into a single @ResourceT@.
--
-- Since 0.4.6
joinResourceT :: ResourceT (ResourceT m) a
              -> ResourceT m a
joinResourceT :: ResourceT (ResourceT m) a -> ResourceT m a
joinResourceT (ResourceT IORef ReleaseMap -> ResourceT m a
f) = (IORef ReleaseMap -> m a) -> ResourceT m a
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT ((IORef ReleaseMap -> m a) -> ResourceT m a)
-> (IORef ReleaseMap -> m a) -> ResourceT m a
forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
r -> ResourceT m a -> IORef ReleaseMap -> m a
forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
unResourceT (IORef ReleaseMap -> ResourceT m a
f IORef ReleaseMap
r) IORef ReleaseMap
r

-- | Introduce a reference-counting scheme to allow a resource context to be
-- shared by multiple threads. Once the last thread exits, all remaining
-- resources will be released.
--
-- The first parameter is a function which will be used to create the
-- thread, such as @forkIO@ or @async@.
--
-- Note that abuse of this function will greatly delay the deallocation of
-- registered resources. This function should be used with care. A general
-- guideline:
--
-- If you are allocating a resource that should be shared by multiple threads,
-- and will be held for a long time, you should allocate it at the beginning of
-- a new @ResourceT@ block and then call @resourceForkWith@ from there.
--
-- @since 1.1.9
resourceForkWith
  :: MonadUnliftIO m
  => (IO () -> IO a)
  -> ResourceT m ()
  -> ResourceT m a
resourceForkWith :: (IO () -> IO a) -> ResourceT m () -> ResourceT m a
resourceForkWith IO () -> IO a
g (ResourceT IORef ReleaseMap -> m ()
f) =
  (IORef ReleaseMap -> m a) -> ResourceT m a
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT ((IORef ReleaseMap -> m a) -> ResourceT m a)
-> (IORef ReleaseMap -> m a) -> ResourceT m a
forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
r -> ((forall a. m a -> IO a) -> IO a) -> m a
forall (m :: * -> *) b.
MonadUnliftIO m =>
((forall a. m a -> IO a) -> IO b) -> m b
withRunInIO (((forall a. m a -> IO a) -> IO a) -> m a)
-> ((forall a. m a -> IO a) -> IO a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> IO a
run -> ((forall a. IO a -> IO a) -> IO a) -> IO a
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
E.mask (((forall a. IO a -> IO a) -> IO a) -> IO a)
-> ((forall a. IO a -> IO a) -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
restore ->
    -- We need to make sure the counter is incremented before this call
    -- returns. Otherwise, the parent thread may call runResourceT before
    -- the child thread increments, and all resources will be freed
    -- before the child gets called.
    IO () -> IO () -> IO () -> IO a -> IO a
forall (m :: * -> *) a.
MonadUnliftIO m =>
IO () -> IO () -> IO () -> m a -> m a
bracket_
        (IORef ReleaseMap -> IO ()
stateAlloc IORef ReleaseMap
r)
        (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
        (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
        (IO () -> IO a
g (IO () -> IO a) -> IO () -> IO a
forall a b. (a -> b) -> a -> b
$ IO () -> IO () -> IO () -> IO () -> IO ()
forall (m :: * -> *) a.
MonadUnliftIO m =>
IO () -> IO () -> IO () -> m a -> m a
bracket_
            (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ())
            (ReleaseType -> IORef ReleaseMap -> IO ()
stateCleanup ReleaseType
ReleaseNormal IORef ReleaseMap
r)
            (ReleaseType -> IORef ReleaseMap -> IO ()
stateCleanup ReleaseType
ReleaseException IORef ReleaseMap
r)
            (IO () -> IO ()
forall a. IO a -> IO a
restore (IO () -> IO ()) -> IO () -> IO ()
forall a b. (a -> b) -> a -> b
$ m () -> IO ()
forall a. m a -> IO a
run (m () -> IO ()) -> m () -> IO ()
forall a b. (a -> b) -> a -> b
$ IORef ReleaseMap -> m ()
f IORef ReleaseMap
r))

-- | Launch a new reference counted resource context using @forkIO@.
--
-- This is defined as @resourceForkWith forkIO@.
--
-- Note: Using regular 'forkIO' inside of a 'ResourceT' is inherently unsafe,
-- since the forked thread may try access the resources of the parent after they are cleaned up.
-- When you use 'resourceForkIO' or 'resourceForkWith', 'ResourceT' is made aware of the new thread, and will only cleanup resources when all threads finish.
-- Other concurrency mechanisms, like 'concurrently' or 'race', are safe to use.
--
-- If you encounter 'InvalidAccess' exceptions ("The mutable state is being accessed after cleanup"),
-- use of 'forkIO' is a possible culprit.
--
-- @since 0.3.0
resourceForkIO :: MonadUnliftIO m => ResourceT m () -> ResourceT m ThreadId
resourceForkIO :: ResourceT m () -> ResourceT m ThreadId
resourceForkIO = (IO () -> IO ThreadId) -> ResourceT m () -> ResourceT m ThreadId
forall (m :: * -> *) a.
MonadUnliftIO m =>
(IO () -> IO a) -> ResourceT m () -> ResourceT m a
resourceForkWith IO () -> IO ThreadId
forkIO

-- | Just use 'MonadUnliftIO' directly now, legacy explanation continues:
--
-- A @Monad@ which can be used as a base for a @ResourceT@.
--
-- A @ResourceT@ has some restrictions on its base monad:
--
-- * @runResourceT@ requires an instance of @MonadUnliftIO@.
-- * @MonadResource@ requires an instance of @MonadIO@
--
-- Note that earlier versions of @conduit@ had a typeclass @ResourceIO@. This
-- fulfills much the same role.
--
-- Since 0.3.2
type MonadResourceBase = MonadUnliftIO
{-# DEPRECATED MonadResourceBase "Use MonadUnliftIO directly instead" #-}

-- $internalState
--
-- A @ResourceT@ internally is a modified @ReaderT@ monad transformer holding
-- onto a mutable reference to all of the release actions still remaining to be
-- performed. If you are building up a custom application monad, it may be more
-- efficient to embed this @ReaderT@ functionality directly in your own monad
-- instead of wrapping around @ResourceT@ itself. This section provides you the
-- means of doing so.

-- | Create a new internal state. This state must be closed with
-- @closeInternalState@. It is your responsibility to ensure exception safety.
-- Caveat emptor!
--
-- Since 0.4.9
createInternalState :: MonadIO m => m InternalState
createInternalState :: m (IORef ReleaseMap)
createInternalState = IO (IORef ReleaseMap) -> m (IORef ReleaseMap)
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO
                    (IO (IORef ReleaseMap) -> m (IORef ReleaseMap))
-> IO (IORef ReleaseMap) -> m (IORef ReleaseMap)
forall a b. (a -> b) -> a -> b
$ ReleaseMap -> IO (IORef ReleaseMap)
forall a. a -> IO (IORef a)
I.newIORef
                    (ReleaseMap -> IO (IORef ReleaseMap))
-> ReleaseMap -> IO (IORef ReleaseMap)
forall a b. (a -> b) -> a -> b
$ Int -> RefCount -> IntMap (ReleaseType -> IO ()) -> ReleaseMap
ReleaseMap Int
forall a. Bounded a => a
maxBound (RefCount
forall a. Bounded a => a
minBound RefCount -> RefCount -> RefCount
forall a. Num a => a -> a -> a
+ RefCount
1) IntMap (ReleaseType -> IO ())
forall a. IntMap a
IntMap.empty

-- | Close an internal state created by @createInternalState@.
--
-- Since 0.4.9
closeInternalState :: MonadIO m => InternalState -> m ()
closeInternalState :: IORef ReleaseMap -> m ()
closeInternalState = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ())
-> (IORef ReleaseMap -> IO ()) -> IORef ReleaseMap -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ReleaseType -> IORef ReleaseMap -> IO ()
stateCleanup ReleaseType
ReleaseNormal

-- | Get the internal state of the current @ResourceT@.
--
-- Since 0.4.6
getInternalState :: Monad m => ResourceT m InternalState
getInternalState :: ResourceT m (IORef ReleaseMap)
getInternalState = (IORef ReleaseMap -> m (IORef ReleaseMap))
-> ResourceT m (IORef ReleaseMap)
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT IORef ReleaseMap -> m (IORef ReleaseMap)
forall (m :: * -> *) a. Monad m => a -> m a
return

-- | The internal state held by a @ResourceT@ transformer.
--
-- Since 0.4.6
type InternalState = I.IORef ReleaseMap

-- | Unwrap a @ResourceT@ using the given @InternalState@.
--
-- Since 0.4.6
runInternalState :: ResourceT m a -> InternalState -> m a
runInternalState :: ResourceT m a -> IORef ReleaseMap -> m a
runInternalState = ResourceT m a -> IORef ReleaseMap -> m a
forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
unResourceT

-- | Run an action in the underlying monad, providing it the @InternalState@.
--
-- Since 0.4.6
withInternalState :: (InternalState -> m a) -> ResourceT m a
withInternalState :: (IORef ReleaseMap -> m a) -> ResourceT m a
withInternalState = (IORef ReleaseMap -> m a) -> ResourceT m a
forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT