mirror of
https://github.com/barrucadu/dejafu.git
synced 2024-12-20 03:51:39 +03:00
Make MonadMask a requirement for MonadConc
This commit is contained in:
parent
8faee29b27
commit
f18209f2e0
@ -1,4 +1,5 @@
|
|||||||
{-# LANGUAGE FlexibleContexts #-}
|
{-# LANGUAGE FlexibleContexts #-}
|
||||||
|
{-# LANGUAGE RankNTypes #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
-- | This module captures in a typeclass the interface of concurrency
|
-- | This module captures in a typeclass the interface of concurrency
|
||||||
@ -7,17 +8,19 @@ module Control.Monad.Conc.Class
|
|||||||
( MonadConc(..)
|
( MonadConc(..)
|
||||||
-- * Utilities
|
-- * Utilities
|
||||||
, spawn
|
, spawn
|
||||||
|
, forkFinally
|
||||||
, killThread
|
, killThread
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Concurrent (forkIO)
|
import Control.Concurrent (forkIO)
|
||||||
import Control.Concurrent.MVar (MVar, readMVar, newEmptyMVar, putMVar, tryPutMVar, takeMVar, tryTakeMVar)
|
import Control.Concurrent.MVar (MVar, readMVar, newEmptyMVar, putMVar, tryPutMVar, takeMVar, tryTakeMVar)
|
||||||
import Control.Exception (Exception, AsyncException(ThreadKilled))
|
import Control.Exception (Exception, AsyncException(ThreadKilled), SomeException)
|
||||||
import Control.Monad (unless)
|
import Control.Monad (unless)
|
||||||
import Control.Monad.Catch (MonadCatch, MonadThrow, catch, throwM)
|
import Control.Monad.Catch (MonadCatch, MonadThrow, MonadMask)
|
||||||
import Control.Monad.STM (STM)
|
import Control.Monad.STM (STM)
|
||||||
import Control.Monad.STM.Class (MonadSTM)
|
import Control.Monad.STM.Class (MonadSTM)
|
||||||
|
|
||||||
|
import qualified Control.Monad.Catch as Ca
|
||||||
import qualified Control.Concurrent as C
|
import qualified Control.Concurrent as C
|
||||||
import qualified Control.Monad.STM as S
|
import qualified Control.Monad.STM as S
|
||||||
|
|
||||||
@ -44,7 +47,7 @@ import qualified Control.Monad.STM as S
|
|||||||
-- 'takeCVar' and 'putCVar', however, are very inefficient, and should
|
-- 'takeCVar' and 'putCVar', however, are very inefficient, and should
|
||||||
-- probably always be overridden to make use of
|
-- probably always be overridden to make use of
|
||||||
-- implementation-specific blocking functionality.
|
-- implementation-specific blocking functionality.
|
||||||
class ( Monad m, MonadCatch m, MonadThrow m
|
class ( Monad m, MonadCatch m, MonadThrow m, MonadMask m
|
||||||
, MonadSTM (STMLike m)
|
, MonadSTM (STMLike m)
|
||||||
, Eq (ThreadId m), Show (ThreadId m)) => MonadConc m where
|
, Eq (ThreadId m), Show (ThreadId m)) => MonadConc m where
|
||||||
-- | The associated 'MonadSTM' for this class.
|
-- | The associated 'MonadSTM' for this class.
|
||||||
@ -63,6 +66,10 @@ class ( Monad m, MonadCatch m, MonadThrow m
|
|||||||
-- happen over @CVar@s.
|
-- happen over @CVar@s.
|
||||||
fork :: m () -> m (ThreadId m)
|
fork :: m () -> m (ThreadId m)
|
||||||
|
|
||||||
|
-- | Like 'fork', but the child thread is passed a function that can
|
||||||
|
-- be used to unmask asynchronous exceptions.
|
||||||
|
forkWithUnmask :: ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
|
||||||
|
|
||||||
-- | Get the @ThreadId@ of the current thread.
|
-- | Get the @ThreadId@ of the current thread.
|
||||||
myThreadId :: m (ThreadId m)
|
myThreadId :: m (ThreadId m)
|
||||||
|
|
||||||
@ -107,22 +114,52 @@ class ( Monad m, MonadCatch m, MonadThrow m
|
|||||||
-- exception handler capable of dealing with it and, if one is not
|
-- exception handler capable of dealing with it and, if one is not
|
||||||
-- found, the thread is killed.
|
-- found, the thread is killed.
|
||||||
--
|
--
|
||||||
-- > throw = throwM
|
-- > throw = Control.Monad.Catch.throwM
|
||||||
throw :: Exception e => e -> m a
|
throw :: Exception e => e -> m a
|
||||||
throw = throwM
|
throw = Ca.throwM
|
||||||
|
|
||||||
-- | Catch an exception. This is only required to be able to catch
|
-- | Catch an exception. This is only required to be able to catch
|
||||||
-- exceptions raised by 'throw', unlike the more general
|
-- exceptions raised by 'throw', unlike the more general
|
||||||
-- Control.Exception.catch function. If you need to be able to catch
|
-- Control.Exception.catch function. If you need to be able to catch
|
||||||
-- /all/ errors, you will have to use 'IO'.
|
-- /all/ errors, you will have to use 'IO'.
|
||||||
|
--
|
||||||
|
-- > catch = Control.Monad.Catch.catch
|
||||||
catch :: Exception e => m a -> (e -> m a) -> m a
|
catch :: Exception e => m a -> (e -> m a) -> m a
|
||||||
catch = Control.Monad.Catch.catch
|
catch = Ca.catch
|
||||||
|
|
||||||
-- | Throw an exception to the target thread. This blocks until the
|
-- | Throw an exception to the target thread. This blocks until the
|
||||||
-- exception is delivered, and it is just as if the target thread
|
-- exception is delivered, and it is just as if the target thread
|
||||||
-- had raised it with 'throw'. This can interrupt a blocked action.
|
-- had raised it with 'throw'. This can interrupt a blocked action.
|
||||||
throwTo :: Exception e => ThreadId m => e -> m ()
|
throwTo :: Exception e => ThreadId m => e -> m ()
|
||||||
|
|
||||||
|
-- | Executes a computation with asynchronous exceptions
|
||||||
|
-- /masked/. That is, any thread which attempts to raise an
|
||||||
|
-- exception in the current thread with 'throwTo' will be blocked
|
||||||
|
-- until asynchronous exceptions are unmasked again.
|
||||||
|
--
|
||||||
|
-- The argument passed to mask is a function that takes as its
|
||||||
|
-- argument another function, which can be used to restore the
|
||||||
|
-- prevailing masking state within the context of the masked
|
||||||
|
-- computation.
|
||||||
|
--
|
||||||
|
-- > mask = Control.Monad.Catch.mask
|
||||||
|
mask :: ((forall a. m a -> m a) -> m b) -> m b
|
||||||
|
mask = Ca.mask
|
||||||
|
|
||||||
|
-- | Like 'mask', but the masked computation is not
|
||||||
|
-- interruptible. THIS SHOULD BE USED WITH GREAT CARE, because if a
|
||||||
|
-- thread executing in 'uninterruptibleMask' blocks for any reason,
|
||||||
|
-- then the thread (and possibly the program, if this is the main
|
||||||
|
-- thread) will be unresponsive and unkillable. This function should
|
||||||
|
-- only be necessary if you need to mask exceptions around an
|
||||||
|
-- interruptible operation, and you can guarantee that the
|
||||||
|
-- interruptible operation will only block for a short period of
|
||||||
|
-- time.
|
||||||
|
--
|
||||||
|
-- > uninterruptibleMask = Control.Monad.Catch.uninterruptibleMask
|
||||||
|
uninterruptibleMask :: ((forall a. m a -> m a) -> m b) -> m b
|
||||||
|
uninterruptibleMask = Ca.uninterruptibleMask
|
||||||
|
|
||||||
-- | Runs its argument, just as if the @_concNoTest@ weren't there.
|
-- | Runs its argument, just as if the @_concNoTest@ weren't there.
|
||||||
--
|
--
|
||||||
-- > _concNoTest x = x
|
-- > _concNoTest x = x
|
||||||
@ -151,6 +188,7 @@ instance MonadConc IO where
|
|||||||
|
|
||||||
readCVar = readMVar
|
readCVar = readMVar
|
||||||
fork = forkIO
|
fork = forkIO
|
||||||
|
forkWithUnmask = C.forkIOWithUnmask
|
||||||
myThreadId = C.myThreadId
|
myThreadId = C.myThreadId
|
||||||
throwTo = C.throwTo
|
throwTo = C.throwTo
|
||||||
newEmptyCVar = newEmptyMVar
|
newEmptyCVar = newEmptyMVar
|
||||||
@ -168,6 +206,17 @@ spawn ma = do
|
|||||||
_ <- fork $ ma >>= putCVar cvar
|
_ <- fork $ ma >>= putCVar cvar
|
||||||
return cvar
|
return cvar
|
||||||
|
|
||||||
|
-- | Fork a thread and call the supplied function when the thread is
|
||||||
|
-- about to terminate, with an exception or a returned value. The
|
||||||
|
-- function is called with asynchronous exceptions masked.
|
||||||
|
--
|
||||||
|
-- This function is useful for informing the parent when a child
|
||||||
|
-- terminates, for example.
|
||||||
|
forkFinally :: MonadConc m => m a -> (Either SomeException a -> m ()) -> m (ThreadId m)
|
||||||
|
forkFinally action and_then =
|
||||||
|
mask $ \restore ->
|
||||||
|
fork $ Ca.try (restore action) >>= and_then
|
||||||
|
|
||||||
-- | Raise the 'ThreadKilled' exception in the target thread. Note
|
-- | Raise the 'ThreadKilled' exception in the target thread. Note
|
||||||
-- that if the thread is prepared to catch this exception, it won't
|
-- that if the thread is prepared to catch this exception, it won't
|
||||||
-- actually kill it.
|
-- actually kill it.
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Rank2Types #-}
|
{-# LANGUAGE RankNTypes #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
-- | Deterministic traced execution of concurrent computations which
|
-- | Deterministic traced execution of concurrent computations which
|
||||||
@ -14,6 +14,8 @@ module Test.DejaFu.Deterministic
|
|||||||
, Failure(..)
|
, Failure(..)
|
||||||
, runConc
|
, runConc
|
||||||
, fork
|
, fork
|
||||||
|
, forkFinally
|
||||||
|
, forkWithUnmask
|
||||||
, myThreadId
|
, myThreadId
|
||||||
, spawn
|
, spawn
|
||||||
, atomically
|
, atomically
|
||||||
@ -21,6 +23,8 @@ module Test.DejaFu.Deterministic
|
|||||||
, throwTo
|
, throwTo
|
||||||
, killThread
|
, killThread
|
||||||
, catch
|
, catch
|
||||||
|
, mask
|
||||||
|
, uninterruptibleMask
|
||||||
|
|
||||||
-- * Communication: CVars
|
-- * Communication: CVars
|
||||||
, CVar
|
, CVar
|
||||||
@ -70,12 +74,17 @@ instance Ca.MonadCatch (Conc t) where
|
|||||||
instance Ca.MonadThrow (Conc t) where
|
instance Ca.MonadThrow (Conc t) where
|
||||||
throwM = throw
|
throwM = throw
|
||||||
|
|
||||||
|
instance Ca.MonadMask (Conc t) where
|
||||||
|
mask = mask
|
||||||
|
uninterruptibleMask = uninterruptibleMask
|
||||||
|
|
||||||
instance C.MonadConc (Conc t) where
|
instance C.MonadConc (Conc t) where
|
||||||
type CVar (Conc t) = CVar t
|
type CVar (Conc t) = CVar t
|
||||||
type STMLike (Conc t) = STMLike t (ST t) (STRef t)
|
type STMLike (Conc t) = STMLike t (ST t) (STRef t)
|
||||||
type ThreadId (Conc t) = Int
|
type ThreadId (Conc t) = Int
|
||||||
|
|
||||||
fork = fork
|
fork = fork
|
||||||
|
forkWithUnmask = forkWithUnmask
|
||||||
myThreadId = myThreadId
|
myThreadId = myThreadId
|
||||||
throwTo = throwTo
|
throwTo = throwTo
|
||||||
newEmptyCVar = newEmptyCVar
|
newEmptyCVar = newEmptyCVar
|
||||||
@ -170,6 +179,45 @@ killThread = C.killThread
|
|||||||
catch :: Exception e => Conc t a -> (e -> Conc t a) -> Conc t a
|
catch :: Exception e => Conc t a -> (e -> Conc t a) -> Conc t a
|
||||||
catch ma h = C $ cont $ ACatching (unC . h) (unC ma)
|
catch ma h = C $ cont $ ACatching (unC . h) (unC ma)
|
||||||
|
|
||||||
|
-- | Fork a thread and call the supplied function when the thread is
|
||||||
|
-- about to terminate, with an exception or a returned value. The
|
||||||
|
-- function is called with asynchronous exceptions masked.
|
||||||
|
--
|
||||||
|
-- This function is useful for informing the parent when a child
|
||||||
|
-- terminates, for example.
|
||||||
|
forkFinally :: Conc t a -> (Either SomeException a -> Conc t ()) -> Conc t ThreadId
|
||||||
|
forkFinally action and_then =
|
||||||
|
mask $ \restore ->
|
||||||
|
fork $ Ca.try (restore action) >>= and_then
|
||||||
|
|
||||||
|
-- | Like 'fork', but the child thread is passed a function that can
|
||||||
|
-- be used to unmask asynchronous exceptions.
|
||||||
|
forkWithUnmask :: ((forall a. Conc t a -> Conc t a) -> Conc t ()) -> Conc t ThreadId
|
||||||
|
forkWithUnmask = error "'forkWithUnmask' not yet implemented for 'Conc'"
|
||||||
|
|
||||||
|
-- | Executes a computation with asynchronous exceptions
|
||||||
|
-- /masked/. That is, any thread which attempts to raise an exception
|
||||||
|
-- in the current thread with 'throwTo' will be blocked until
|
||||||
|
-- asynchronous exceptions are unmasked again.
|
||||||
|
--
|
||||||
|
-- The argument passed to mask is a function that takes as its
|
||||||
|
-- argument another function, which can be used to restore the
|
||||||
|
-- prevailing masking state within the context of the masked
|
||||||
|
-- computation.
|
||||||
|
mask :: ((forall a. Conc t a -> Conc t a) -> Conc t b) -> Conc t b
|
||||||
|
mask = error "'mask' not yet implemented for 'Conc'"
|
||||||
|
|
||||||
|
-- | Like 'mask', but the masked computation is not
|
||||||
|
-- interruptible. THIS SHOULD BE USED WITH GREAT CARE, because if a
|
||||||
|
-- thread executing in 'uninterruptibleMask' blocks for any reason,
|
||||||
|
-- then the thread (and possibly the program, if this is the main
|
||||||
|
-- thread) will be unresponsive and unkillable. This function should
|
||||||
|
-- only be necessary if you need to mask exceptions around an
|
||||||
|
-- interruptible operation, and you can guarantee that the
|
||||||
|
-- interruptible operation will only block for a short period of time.
|
||||||
|
uninterruptibleMask :: ((forall a. Conc t a -> Conc t a) -> Conc t b) -> Conc t b
|
||||||
|
uninterruptibleMask = error "'uninterruptibleMask' not yet implemented for 'Conc'"
|
||||||
|
|
||||||
-- | Run the argument in one step. If the argument fails, the whole
|
-- | Run the argument in one step. If the argument fails, the whole
|
||||||
-- computation will fail.
|
-- computation will fail.
|
||||||
_concNoTest :: Conc t a -> Conc t a
|
_concNoTest :: Conc t a -> Conc t a
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
|
||||||
{-# LANGUAGE Rank2Types #-}
|
{-# LANGUAGE RankNTypes #-}
|
||||||
{-# LANGUAGE TypeFamilies #-}
|
{-# LANGUAGE TypeFamilies #-}
|
||||||
|
|
||||||
-- | Deterministic traced execution of concurrent computations which
|
-- | Deterministic traced execution of concurrent computations which
|
||||||
@ -18,6 +18,8 @@ module Test.DejaFu.Deterministic.IO
|
|||||||
, runConcIO
|
, runConcIO
|
||||||
, liftIO
|
, liftIO
|
||||||
, fork
|
, fork
|
||||||
|
, forkFinally
|
||||||
|
, forkWithUnmask
|
||||||
, myThreadId
|
, myThreadId
|
||||||
, spawn
|
, spawn
|
||||||
, atomically
|
, atomically
|
||||||
@ -25,6 +27,8 @@ module Test.DejaFu.Deterministic.IO
|
|||||||
, throwTo
|
, throwTo
|
||||||
, killThread
|
, killThread
|
||||||
, catch
|
, catch
|
||||||
|
, mask
|
||||||
|
, uninterruptibleMask
|
||||||
|
|
||||||
-- * Communication: CVars
|
-- * Communication: CVars
|
||||||
, CVar
|
, CVar
|
||||||
@ -71,6 +75,10 @@ instance Ca.MonadCatch (ConcIO t) where
|
|||||||
instance Ca.MonadThrow (ConcIO t) where
|
instance Ca.MonadThrow (ConcIO t) where
|
||||||
throwM = throw
|
throwM = throw
|
||||||
|
|
||||||
|
instance Ca.MonadMask (ConcIO t) where
|
||||||
|
mask = mask
|
||||||
|
uninterruptibleMask = uninterruptibleMask
|
||||||
|
|
||||||
instance IO.MonadIO (ConcIO t) where
|
instance IO.MonadIO (ConcIO t) where
|
||||||
liftIO = liftIO
|
liftIO = liftIO
|
||||||
|
|
||||||
@ -80,6 +88,7 @@ instance C.MonadConc (ConcIO t) where
|
|||||||
type ThreadId (ConcIO t) = Int
|
type ThreadId (ConcIO t) = Int
|
||||||
|
|
||||||
fork = fork
|
fork = fork
|
||||||
|
forkWithUnmask = forkWithUnmask
|
||||||
myThreadId = myThreadId
|
myThreadId = myThreadId
|
||||||
throwTo = throwTo
|
throwTo = throwTo
|
||||||
newEmptyCVar = newEmptyCVar
|
newEmptyCVar = newEmptyCVar
|
||||||
@ -175,6 +184,45 @@ killThread = C.killThread
|
|||||||
catch :: Exception e => ConcIO t a -> (e -> ConcIO t a) -> ConcIO t a
|
catch :: Exception e => ConcIO t a -> (e -> ConcIO t a) -> ConcIO t a
|
||||||
catch ma h = C $ cont $ ACatching (unC . h) (unC ma)
|
catch ma h = C $ cont $ ACatching (unC . h) (unC ma)
|
||||||
|
|
||||||
|
-- | Fork a thread and call the supplied function when the thread is
|
||||||
|
-- about to terminate, with an exception or a returned value. The
|
||||||
|
-- function is called with asynchronous exceptions masked.
|
||||||
|
--
|
||||||
|
-- This function is useful for informing the parent when a child
|
||||||
|
-- terminates, for example.
|
||||||
|
forkFinally :: ConcIO t a -> (Either SomeException a -> ConcIO t ()) -> ConcIO t ThreadId
|
||||||
|
forkFinally action and_then =
|
||||||
|
mask $ \restore ->
|
||||||
|
fork $ Ca.try (restore action) >>= and_then
|
||||||
|
|
||||||
|
-- | Like 'fork', but the child thread is passed a function that can
|
||||||
|
-- be used to unmask asynchronous exceptions.
|
||||||
|
forkWithUnmask :: ((forall a. ConcIO t a -> ConcIO t a) -> ConcIO t ()) -> ConcIO t ThreadId
|
||||||
|
forkWithUnmask = error "'forkWithUnmask' not yet implemented for 'ConcIO'"
|
||||||
|
|
||||||
|
-- | Executes a computation with asynchronous exceptions
|
||||||
|
-- /masked/. That is, any thread which attempts to raise an exception
|
||||||
|
-- in the current thread with 'throwTo' will be blocked until
|
||||||
|
-- asynchronous exceptions are unmasked again.
|
||||||
|
--
|
||||||
|
-- The argument passed to mask is a function that takes as its
|
||||||
|
-- argument another function, which can be used to restore the
|
||||||
|
-- prevailing masking state within the context of the masked
|
||||||
|
-- computation.
|
||||||
|
mask :: ((forall a. ConcIO t a -> ConcIO t a) -> ConcIO t b) -> ConcIO t b
|
||||||
|
mask = error "'mask' not yet implemented for 'ConcIO'"
|
||||||
|
|
||||||
|
-- | Like 'mask', but the masked computation is not
|
||||||
|
-- interruptible. THIS SHOULD BE USED WITH GREAT CARE, because if a
|
||||||
|
-- thread executing in 'uninterruptibleMask' blocks for any reason,
|
||||||
|
-- then the thread (and possibly the program, if this is the main
|
||||||
|
-- thread) will be unresponsive and unkillable. This function should
|
||||||
|
-- only be necessary if you need to mask exceptions around an
|
||||||
|
-- interruptible operation, and you can guarantee that the
|
||||||
|
-- interruptible operation will only block for a short period of time.
|
||||||
|
uninterruptibleMask :: ((forall a. ConcIO t a -> ConcIO t a) -> ConcIO t b) -> ConcIO t b
|
||||||
|
uninterruptibleMask = error "'uninterruptibleMask' not yet implemented for 'ConcIO'"
|
||||||
|
|
||||||
-- | Run the argument in one step. If the argument fails, the whole
|
-- | Run the argument in one step. If the argument fails, the whole
|
||||||
-- computation will fail.
|
-- computation will fail.
|
||||||
_concNoTest :: ConcIO t a -> ConcIO t a
|
_concNoTest :: ConcIO t a -> ConcIO t a
|
||||||
|
Loading…
Reference in New Issue
Block a user