@@ -14,11 +14,10 @@ import Prelude hiding (unzip)
1414
1515import Control.Concurrent.Async
1616import Control.Concurrent.Extra
17- import Control.Concurrent.STM.Stats (STM , TVar , atomically ,
17+ import Control.Concurrent.STM.Stats (STM , atomically ,
1818 atomicallyNamed ,
1919 modifyTVar' , newTVarIO ,
20- readTVar , readTVarIO ,
21- retry )
20+ readTVarIO , retry )
2221import Control.Exception
2322import Control.Monad
2423import Control.Monad.IO.Class (MonadIO (liftIO ))
@@ -280,7 +279,7 @@ transitiveDirtySet database = flip State.execStateT mempty . traverse_ loop
280279
281280-- | A simple monad to implement cancellation on top of 'Async',
282281-- generalizing 'withAsync' to monadic scopes.
283- newtype AIO a = AIO { unAIO :: ReaderT (TVar [Async () ]) IO a }
282+ newtype AIO a = AIO { unAIO :: ReaderT (IORef [Async () ]) IO a }
284283 deriving newtype (Applicative , Functor , Monad , MonadIO )
285284
286285data AsyncParentKill = AsyncParentKill ThreadId Step
@@ -293,14 +292,11 @@ instance Exception AsyncParentKill where
293292-- | Run the monadic computation, cancelling all the spawned asyncs if an exception arises
294293runAIO :: Step -> AIO a -> IO a
295294runAIO s (AIO act) = do
296- asyncsRef <- newTVarIO []
295+ asyncsRef <- newIORef []
297296 -- Log the exact exception (including async exceptions) before cleanup,
298297 -- then rethrow to preserve previous semantics.
299298 runReaderT act asyncsRef `onException` do
300- asyncs <- atomically $ do
301- r <- readTVar asyncsRef
302- modifyTVar' asyncsRef $ const []
303- return r
299+ asyncs <- atomicModifyIORef' asyncsRef ([] ,)
304300 tid <- myThreadId
305301 cleanupAsync asyncs tid s
306302
@@ -313,7 +309,7 @@ asyncWithCleanUp act = do
313309 -- mask to make sure we keep track of the spawned async
314310 liftIO $ uninterruptibleMask $ \ restore -> do
315311 a <- async $ restore io
316- atomically $ modifyTVar' st (void a : )
312+ atomicModifyIORef'_ st (void a: )
317313 return $ wait a
318314
319315unliftAIO :: AIO a -> AIO (IO a )
0 commit comments