{-# LANGUAGE Trustworthy #-}{-# LANGUAGE CPP , NoImplicitPrelude , MagicHash , UnboxedTuples #-}{-# OPTIONS_GHC -Wno-missing-signatures #-}{-# OPTIONS_HADDOCK not-home #-}------------------------------------------------------------------------------- |-- Module : GHC.Conc.IO-- Copyright : (c) The University of Glasgow, 1994-2002-- License : see libraries/base/LICENSE---- Maintainer : cvs-ghc@haskell.org-- Stability : internal-- Portability : non-portable (GHC extensions)---- Basic concurrency stuff.--------------------------------------------------------------------------------- No: #hide, because bits of this module are exposed by the stm package.-- However, we don't want this module to be the home location for the-- bits it exports, we'd rather have Control.Concurrent and the other-- higher level modules be the home. Hence: #not-homemoduleGHC.Conc.IO(ensureIOManagerIsRunning ,ioManagerCapabilitiesChanged -- * Waiting,threadDelay ,registerDelay ,threadWaitRead ,threadWaitWrite ,threadWaitReadSTM ,threadWaitWriteSTM ,closeFdWith #if defined(mingw32_HOST_OS) ,asyncRead,asyncWrite,asyncDoProc,asyncReadBA,asyncWriteBA,ConsoleEvent(..),win32ConsoleHandler,toWin32ConsoleEvent #endif )whereimportForeign importGHC.Base importGHC.Conc.Sync asSyncimportGHC.Real (fromIntegral )importSystem.Posix.Types #if defined(mingw32_HOST_OS) importqualifiedGHC.Conc.WindowsasWindowsimportGHC.Conc.Windows(asyncRead,asyncWrite,asyncDoProc,asyncReadBA,asyncWriteBA,ConsoleEvent(..),win32ConsoleHandler,toWin32ConsoleEvent) #else importqualifiedGHC.Event.Thread asEvent #endif ensureIOManagerIsRunning ::IO() #if !defined(mingw32_HOST_OS) ensureIOManagerIsRunning :: IO () ensureIOManagerIsRunning =IO () Event.ensureIOManagerIsRunning #else ensureIOManagerIsRunning=Windows.ensureIOManagerIsRunning #endif ioManagerCapabilitiesChanged ::IO() #if !defined(mingw32_HOST_OS) ioManagerCapabilitiesChanged :: IO () ioManagerCapabilitiesChanged =IO () Event.ioManagerCapabilitiesChanged #else ioManagerCapabilitiesChanged=return() #endif -- | Block the current thread until data is available to read on the-- given file descriptor (GHC only).---- This will throw an 'Prelude.IOError' if the file descriptor was closed-- while this thread was blocked. To safely close a file descriptor-- that has been used with 'threadWaitRead', use 'closeFdWith'.threadWaitRead ::Fd ->IO()threadWaitRead :: Fd -> IO () threadWaitRead Fd fd #if !defined(mingw32_HOST_OS) |Bool threaded =Fd -> IO () Event.threadWaitRead Fd fd #endif |Bool otherwise =(State# RealWorld -> (# State# RealWorld, () #)) -> IO () forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a IO((State# RealWorld -> (# State# RealWorld, () #)) -> IO ()) -> (State# RealWorld -> (# State# RealWorld, () #)) -> IO () forall a b. (a -> b) -> a -> b $ \State# RealWorld s ->caseFd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd of{I#Int# fd# ->caseInt# -> State# RealWorld -> State# RealWorld forall d. Int# -> State# d -> State# d waitRead#Int# fd# State# RealWorld s of{State# RealWorld s' ->(#State# RealWorld s' ,()#)}}-- | Block the current thread until data can be written to the-- given file descriptor (GHC only).---- This will throw an 'Prelude.IOError' if the file descriptor was closed-- while this thread was blocked. To safely close a file descriptor-- that has been used with 'threadWaitWrite', use 'closeFdWith'.threadWaitWrite ::Fd ->IO()threadWaitWrite :: Fd -> IO () threadWaitWrite Fd fd #if !defined(mingw32_HOST_OS) |Bool threaded =Fd -> IO () Event.threadWaitWrite Fd fd #endif |Bool otherwise =(State# RealWorld -> (# State# RealWorld, () #)) -> IO () forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a IO((State# RealWorld -> (# State# RealWorld, () #)) -> IO ()) -> (State# RealWorld -> (# State# RealWorld, () #)) -> IO () forall a b. (a -> b) -> a -> b $ \State# RealWorld s ->caseFd -> Int forall a b. (Integral a, Num b) => a -> b fromIntegral Fd fd of{I#Int# fd# ->caseInt# -> State# RealWorld -> State# RealWorld forall d. Int# -> State# d -> State# d waitWrite#Int# fd# State# RealWorld s of{State# RealWorld s' ->(#State# RealWorld s' ,()#)}}-- | Returns an STM action that can be used to wait for data-- to read from a file descriptor. The second returned value-- is an IO action that can be used to deregister interest-- in the file descriptor.threadWaitReadSTM ::Fd ->IO(Sync.STM (),IO())threadWaitReadSTM :: Fd -> IO (STM (), IO ()) threadWaitReadSTM Fd fd #if !defined(mingw32_HOST_OS) |Bool threaded =Fd -> IO (STM (), IO ()) Event.threadWaitReadSTM Fd fd #endif |Bool otherwise =doTVar Bool m <-Bool -> IO (TVar Bool) forall a. a -> IO (TVar a) Sync.newTVarIO Bool FalseThreadId t <-IO () -> IO ThreadId Sync.forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId forall a b. (a -> b) -> a -> b $ doFd -> IO () threadWaitRead Fd fd STM () -> IO () forall a. STM a -> IO a Sync.atomically (STM () -> IO ()) -> STM () -> IO () forall a b. (a -> b) -> a -> b $ TVar Bool -> Bool -> STM () forall a. TVar a -> a -> STM () Sync.writeTVar TVar Bool m Bool TrueletwaitAction :: STM () waitAction =doBool b <-TVar Bool -> STM Bool forall a. TVar a -> STM a Sync.readTVar TVar Bool m ifBool b then() -> STM () forall (m :: * -> *) a. Monad m => a -> m a return ()elseSTM () forall a. STM a retry letkillAction :: IO () killAction =ThreadId -> IO () Sync.killThread ThreadId t (STM (), IO ()) -> IO (STM (), IO ()) forall (m :: * -> *) a. Monad m => a -> m a return (STM () waitAction ,IO () killAction )-- | Returns an STM action that can be used to wait until data-- can be written to a file descriptor. The second returned value-- is an IO action that can be used to deregister interest-- in the file descriptor.threadWaitWriteSTM ::Fd ->IO(Sync.STM (),IO())threadWaitWriteSTM :: Fd -> IO (STM (), IO ()) threadWaitWriteSTM Fd fd #if !defined(mingw32_HOST_OS) |Bool threaded =Fd -> IO (STM (), IO ()) Event.threadWaitWriteSTM Fd fd #endif |Bool otherwise =doTVar Bool m <-Bool -> IO (TVar Bool) forall a. a -> IO (TVar a) Sync.newTVarIO Bool FalseThreadId t <-IO () -> IO ThreadId Sync.forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId forall a b. (a -> b) -> a -> b $ doFd -> IO () threadWaitWrite Fd fd STM () -> IO () forall a. STM a -> IO a Sync.atomically (STM () -> IO ()) -> STM () -> IO () forall a b. (a -> b) -> a -> b $ TVar Bool -> Bool -> STM () forall a. TVar a -> a -> STM () Sync.writeTVar TVar Bool m Bool TrueletwaitAction :: STM () waitAction =doBool b <-TVar Bool -> STM Bool forall a. TVar a -> STM a Sync.readTVar TVar Bool m ifBool b then() -> STM () forall (m :: * -> *) a. Monad m => a -> m a return ()elseSTM () forall a. STM a retry letkillAction :: IO () killAction =ThreadId -> IO () Sync.killThread ThreadId t (STM (), IO ()) -> IO (STM (), IO ()) forall (m :: * -> *) a. Monad m => a -> m a return (STM () waitAction ,IO () killAction )-- | Close a file descriptor in a concurrency-safe way (GHC only). If-- you are using 'threadWaitRead' or 'threadWaitWrite' to perform-- blocking I\/O, you /must/ use this function to close file-- descriptors, or blocked threads may not be woken.---- Any threads that are blocked on the file descriptor via-- 'threadWaitRead' or 'threadWaitWrite' will be unblocked by having-- IO exceptions thrown.closeFdWith ::(Fd ->IO())-- ^ Low-level action that performs the real close.->Fd -- ^ File descriptor to close.->IO()closeFdWith :: (Fd -> IO ()) -> Fd -> IO () closeFdWith Fd -> IO () close Fd fd #if !defined(mingw32_HOST_OS) |Bool threaded =(Fd -> IO ()) -> Fd -> IO () Event.closeFdWith Fd -> IO () close Fd fd #endif |Bool otherwise =Fd -> IO () close Fd fd -- | Suspends the current thread for a given number of microseconds-- (GHC only).---- There is no guarantee that the thread will be rescheduled promptly-- when the delay has expired, but the thread will never continue to-- run /earlier/ than specified.--threadDelay ::Int->IO()threadDelay :: Int -> IO () threadDelay Int time #if defined(mingw32_HOST_OS) |threaded=Windows.threadDelaytime #else |Bool threaded =Int -> IO () Event.threadDelay Int time #endif |Bool otherwise =(State# RealWorld -> (# State# RealWorld, () #)) -> IO () forall a. (State# RealWorld -> (# State# RealWorld, a #)) -> IO a IO((State# RealWorld -> (# State# RealWorld, () #)) -> IO ()) -> (State# RealWorld -> (# State# RealWorld, () #)) -> IO () forall a b. (a -> b) -> a -> b $ \State# RealWorld s ->caseInt time of{I#Int# time# ->caseInt# -> State# RealWorld -> State# RealWorld forall d. Int# -> State# d -> State# d delay#Int# time# State# RealWorld s of{State# RealWorld s' ->(#State# RealWorld s' ,()#)}}-- | Switch the value of returned 'TVar' from initial value 'False' to 'True'-- after a given number of microseconds. The caveats associated with-- 'threadDelay' also apply.--registerDelay ::Int->IO(TVar Bool)registerDelay :: Int -> IO (TVar Bool) registerDelay Int usecs #if defined(mingw32_HOST_OS) |threaded=Windows.registerDelayusecs #else |Bool threaded =Int -> IO (TVar Bool) Event.registerDelay Int usecs #endif |Bool otherwise =[Char] -> IO (TVar Bool) forall a. [Char] -> a errorWithoutStackTrace [Char] "registerDelay: requires -threaded"foreignimportccallunsafe"rtsSupportsBoundThreads"threaded ::Bool