module Darcs.Util.AtExit ( atexit , withAtexit ) where
import Darcs.Prelude
import Control.Concurrent.MVar
import Control.Exception ( SomeException, catch, finally )
import System.IO ( hPrint, hPutStrLn, stderr )
import System.IO.Unsafe ( unsafePerformIO )
atexitActions :: MVar (Maybe [IO ()])
atexitActions :: MVar (Maybe [IO ()])
atexitActions = IO (MVar (Maybe [IO ()])) -> MVar (Maybe [IO ()])
forall a. IO a -> a
unsafePerformIO (Maybe [IO ()] -> IO (MVar (Maybe [IO ()]))
forall a. a -> IO (MVar a)
newMVar ([IO ()] -> Maybe [IO ()]
forall a. a -> Maybe a
Just []))
{-# NOINLINE atexitActions #-}
atexit :: IO () -> IO ()
atexit :: IO () -> IO ()
atexit IO ()
action =
MVar (Maybe [IO ()])
-> (Maybe [IO ()] -> IO (Maybe [IO ()])) -> IO ()
forall a. MVar a -> (a -> IO a) -> IO ()
modifyMVar_ MVar (Maybe [IO ()])
atexitActions ((Maybe [IO ()] -> IO (Maybe [IO ()])) -> IO ())
-> (Maybe [IO ()] -> IO (Maybe [IO ()])) -> IO ()
forall a b. (a -> b) -> a -> b
$ \Maybe [IO ()]
ml ->
case Maybe [IO ()]
ml of
Just [IO ()]
l ->
Maybe [IO ()] -> IO (Maybe [IO ()])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return ([IO ()] -> Maybe [IO ()]
forall a. a -> Maybe a
Just (IO ()
action IO () -> [IO ()] -> [IO ()]
forall a. a -> [a] -> [a]
: [IO ()]
l))
Maybe [IO ()]
Nothing -> do
Handle -> String -> IO ()
hPutStrLn Handle
stderr String
"It's too late to use atexit"
Maybe [IO ()] -> IO (Maybe [IO ()])
forall a. a -> IO a
forall (m :: * -> *) a. Monad m => a -> m a
return Maybe [IO ()]
forall a. Maybe a
Nothing
withAtexit :: IO a -> IO a
withAtexit :: forall a. IO a -> IO a
withAtexit IO a
job = IO a
job IO a -> IO () -> IO a
forall a b. IO a -> IO b -> IO a
`finally` IO ()
runAtexitActions
where
runAtexitActions :: IO ()
runAtexitActions = do
Just [IO ()]
actions <- MVar (Maybe [IO ()]) -> Maybe [IO ()] -> IO (Maybe [IO ()])
forall a. MVar a -> a -> IO a
swapMVar MVar (Maybe [IO ()])
atexitActions Maybe [IO ()]
forall a. Maybe a
Nothing
(IO () -> IO ()) -> [IO ()] -> IO ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
(a -> m b) -> t a -> m ()
mapM_ IO () -> IO ()
runAction [IO ()]
actions
runAction :: IO () -> IO ()
runAction IO ()
action =
IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch IO ()
action ((SomeException -> IO ()) -> IO ())
-> (SomeException -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \(SomeException
exn :: SomeException) -> do
Handle -> String -> IO ()
hPutStrLn Handle
stderr String
"Exception thrown by an atexit registered action:"
Handle -> SomeException -> IO ()
forall a. Show a => Handle -> a -> IO ()
hPrint Handle
stderr SomeException
exn