-- | -- Module : Streamly.Internal.Control.Concurrent -- Copyright : (c) 2017 Composewell Technologies -- License : BSD-3-Clause -- Maintainer : streamly@composewell.com -- Stability : experimental -- Portability : GHC -- -- Note: This module is primarily for abstractions related to MonadBaseControl. -- Please do not add any general routines in this. It should be renamed -- appropriately. module Streamly.Internal.Control.Concurrent ( MonadAsync , MonadRunInIO , RunInIO(..) , askRunInIO , withRunInIO , withRunInIONoRestore , restoreM ) where import Control.Monad.Catch (MonadThrow) import Streamly.Internal.Data.SVar.Type (RunInIO(..)) #ifdef USE_UNLIFTIO import Control.Monad.IO.Unlift (MonadUnliftIO(..), UnliftIO(..), askUnliftIO) #else import Control.Monad.IO.Class (MonadIO) import Control.Monad.Trans.Control (MonadBaseControl(..), control) #endif #ifdef USE_UNLIFTIO type MonadRunInIO m = MonadUnliftIO m #else type MonadRunInIO m = (MonadIO m, MonadBaseControl IO m) #endif -- | A monad that can perform concurrent or parallel IO operations. Streams -- that can be composed concurrently require the underlying monad to be -- 'MonadAsync'. -- #ifdef USE_UNLIFTIO type MonadAsync m = (MonadUnliftIO m, MonadThrow m) #else type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m) #endif -- | When we run computations concurrently, we completely isolate the state of -- the concurrent computations from the parent computation. The invariant is -- that we should never be running two concurrent computations in the same -- thread without using the runInIO function. Also, we should never be running -- a concurrent computation in the parent thread, otherwise it may affect the -- state of the parent which is against the defined semantics of concurrent -- execution. askRunInIO :: MonadRunInIO m => m (RunInIO m) #ifdef USE_UNLIFTIO askRunInIO = fmap (\(UnliftIO run) -> RunInIO run) askUnliftIO #else askRunInIO = control $ \run -> run (return $ RunInIO run) #endif #ifdef USE_UNLIFTIO withRunInIONoRestore :: MonadRunInIO m => ((forall a. m a -> IO a) -> IO b) -> m b withRunInIONoRestore = withRunInIO restoreM :: MonadRunInIO m => a -> m a restoreM = return #else withRunInIO :: MonadRunInIO m => ((forall a. m a -> IO (StM m a)) -> IO (StM m b)) -> m b withRunInIO = control withRunInIONoRestore :: MonadRunInIO m => ((forall a. m a -> IO (StM m a)) -> IO b) -> m b withRunInIONoRestore = liftBaseWith #endif