@@ -281,7 +281,7 @@ module Streamly.Internal.Data.Stream.StreamD
281 -- * Exceptions
281 -- * Exceptions
282 , newFinalizedIORef
282 , newFinalizedIORef
283 , runIORefFinalizer
283 , runIORefFinalizer
284− , clearIORefFinalizer
284+ , withIORefFinalizer
285 , gbracket_
285 , gbracket_
286 , gbracket
286 , gbracket
@@ -313,7 +313,7 @@ import Control.Monad.IO.Class (MonadIO(..))
313import Control.Monad.Trans.Reader (ReaderT)
313import Control.Monad.Trans.Reader (ReaderT)
314import Control.Monad.Trans.State.Strict (StateT)
314import Control.Monad.Trans.State.Strict (StateT)
315import Control.Monad.Trans.Class (MonadTrans(lift))
315import Control.Monad.Trans.Class (MonadTrans(lift))
316−import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
316+import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_, control)
317import Data.Bits (shiftR, shiftL, (.|.), (.&.))
317import Data.Bits (shiftR, shiftL, (.|.), (.&.))
318import Data.Functor.Identity (Identity(..))
318import Data.Functor.Identity (Identity(..))
319import Data.Int (Int64)
319import Data.Int (Int64)
@@ -3224,10 +3224,15 @@ runIORefFinalizer ref = liftIO $ do
3224 writeIORef ref Nothing
3224 writeIORef ref Nothing
3227−-- | Deactivate the finalizer stored in an IORef without running it.
3227+-- | Run an action clearing the finalizer IORef atomically wrt async
3228−--
3228+-- exceptions. The action is run with async exceptions masked.
3229+withIORefFinalizer :: MonadBaseControl IO m
3229−clearIORefFinalizer :: MonadIO m => IORef (Maybe (IO ())) -> m ()
3230+ => IORef (Maybe (IO ())) -> m a -> m a
3231+withIORefFinalizer ref action = do
3232+ control $ \runinio ->
3230−clearIORefFinalizer ref = liftIO $ writeIORef ref Nothing
3234+ writeIORef ref Nothing
3232------------------------------------------------------------------------------
3237------------------------------------------------------------------------------
@@ -3251,7 +3256,7 @@ gbracket
3251 => m c -- ^ before
3256 => m c -- ^ before
3252 -> (forall s. m s -> m (Either e s)) -- ^ try (exception handling)
3257 -> (forall s. m s -> m (Either e s)) -- ^ try (exception handling)
3253 -> (c -> m d) -- ^ after, on normal stop or GC
3258 -> (c -> m d) -- ^ after, on normal stop or GC
3254− -> (c -> e -> Stream m b -> Stream m b) -- ^ on exception
3259+ -> (c -> e -> Stream m b -> m (Stream m b)) -- ^ on exception
3255 -> (c -> Stream m b) -- ^ stream generator
3260 -> (c -> Stream m b) -- ^ stream generator
3256 -> Stream m b
3261 -> Stream m b
3257gbracket bef exc aft fexc fnormal =
3262gbracket bef exc aft fexc fnormal =
@@ -3286,8 +3291,12 @@ gbracket bef exc aft fexc fnormal =
3286 runIORefFinalizer ref
3291 runIORefFinalizer ref
3287 return Stop
3292 return Stop
3288 Left e -> do
3293 Left e -> do
3289− clearIORefFinalizer ref
3294+ -- Clearing of finalizer and running of exception handler must
3295+ -- be atomic wrt async exceptions. Otherwise if we have cleared
3296+ -- the finalizer and have not run the exception handler then we
3297+ -- may leak the resource.
3290− return $ Skip (GBracketIOException (fexc v e (UnStream step1 st)))
3298+ stream <- withIORefFinalizer ref (fexc v e (UnStream step1 st))
3299+ return $ Skip (GBracketIOException stream)
3291 step gst (GBracketIOException (UnStream step1 st)) = do
3300 step gst (GBracketIOException (UnStream step1 st)) = do
3292 res <- step1 gst st
3301 res <- step1 gst st
3293 case res of
3302 case res of
@@ -3404,7 +3413,7 @@ bracket :: (MonadAsync m, MonadCatch m)
3404 => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
3413 => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
3405bracket bef aft bet =
3414bracket bef aft bet =
3406 gbracket bef MC.try aft
3415 gbracket bef MC.try aft
3407− (\a (e :: SomeException) _ -> nilM (aft a >> MC.throwM e)) bet
3416+ (\a (e :: SomeException) _ -> aft a >> return (nilM (MC.throwM e))) bet
3409data BracketState s v = BracketInit | BracketRun s v
3418data BracketState s v = BracketInit | BracketRun s v