module Darcs.Util.AtExit
(
atexit
, withAtexit
) where
import Darcs.Prelude
import Control.Concurrent.MVar
import Control.Exception
( bracket_, catch, SomeException
, mask
)
import System.IO.Unsafe (unsafePerformIO)
import System.IO ( hPutStrLn, stderr, hPrint )
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 (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 (m :: * -> *) a. Monad m => a -> m a
return Maybe [IO ()]
forall a. Maybe a
Nothing
withAtexit :: IO a -> IO a
withAtexit :: IO a -> IO a
withAtexit = IO () -> IO () -> IO a -> IO a
forall a b c. IO a -> IO b -> IO c -> IO c
bracket_ (() -> IO ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()) IO ()
exit
where
exit :: IO ()
exit = ((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall b. ((forall a. IO a -> IO a) -> IO b) -> IO b
mask (((forall a. IO a -> IO a) -> IO ()) -> IO ())
-> ((forall a. IO a -> IO a) -> IO ()) -> IO ()
forall a b. (a -> b) -> a -> b
$ \forall a. IO a -> IO a
unmask -> 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 ()) -> IO () -> IO ()
forall t. (t -> IO ()) -> t -> IO ()
runAction IO () -> IO ()
forall a. IO a -> IO a
unmask) [IO ()]
actions
runAction :: (t -> IO ()) -> t -> IO ()
runAction t -> IO ()
unmask t
action =
IO () -> (SomeException -> IO ()) -> IO ()
forall e a. Exception e => IO a -> (e -> IO a) -> IO a
catch (t -> IO ()
unmask t
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