{-# LANGUAGE Trustworthy #-} {-# LANGUAGE CPP , NoImplicitPrelude , MagicHash , UnboxedTuples , ForeignFunctionInterface #-} {-# OPTIONS_GHC -fno-warn-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: #include "Typeable.h" -- #not-home module GHC.Conc.IO ( ensureIOManagerIsRunning -- * Waiting , threadDelay -- :: Int -> IO () , registerDelay -- :: Int -> IO (TVar Bool) , threadWaitRead -- :: Int -> IO () , threadWaitWrite -- :: Int -> IO () , closeFdWith -- :: (Fd -> IO ()) -> Fd -> IO () #ifdef mingw32_HOST_OS , asyncRead -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int) , asyncWrite -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int) , asyncDoProc -- :: FunPtr (Ptr a -> IO Int) -> Ptr a -> IO Int , asyncReadBA -- :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int, Int) , asyncWriteBA -- :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int, Int) , ConsoleEvent(..) , win32ConsoleHandler , toWin32ConsoleEvent #endif ) where import Foreign import GHC.Base import GHC.Conc.Sync as Sync import GHC.Real ( fromIntegral ) import System.Posix.Types #ifdef mingw32_HOST_OS import qualified GHC.Conc.Windows as Windows import GHC.Conc.Windows (asyncRead, asyncWrite, asyncDoProc, asyncReadBA, asyncWriteBA, ConsoleEvent(..), win32ConsoleHandler, toWin32ConsoleEvent) #else import qualified GHC.Event.Thread as Event #endif ensureIOManagerIsRunning :: IO () #ifndef mingw32_HOST_OS ensureIOManagerIsRunning = Event.ensureIOManagerIsRunning #else ensureIOManagerIsRunning = Windows.ensureIOManagerIsRunning #endif -- | Block the current thread until data is available to read on the -- given file descriptor (GHC only). -- -- This will throw an '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 #ifndef mingw32_HOST_OS | threaded = Event.threadWaitRead fd #endif | otherwise = IO $ \s -> case fromIntegral fd of { I# fd# -> case waitRead# fd# s of { s' -> (# s', () #) }} -- | Block the current thread until data can be written to the -- given file descriptor (GHC only). -- -- This will throw an '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 #ifndef mingw32_HOST_OS | threaded = Event.threadWaitWrite fd #endif | otherwise = IO $ \s -> case fromIntegral fd of { I# fd# -> case waitWrite# fd# s of { s' -> (# s', () #) }} -- | 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 close fd #ifndef mingw32_HOST_OS | threaded = Event.closeFdWith close fd #endif | otherwise = close 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 time #ifdef mingw32_HOST_OS | threaded = Windows.threadDelay time #else | threaded = Event.threadDelay time #endif | otherwise = IO $ \s -> case time of { I# time# -> case delay# time# s of { s' -> (# s', () #) }} -- | Set the value of returned TVar to True after a given number of -- microseconds. The caveats associated with threadDelay also apply. -- registerDelay :: Int -> IO (TVar Bool) registerDelay usecs #ifdef mingw32_HOST_OS | threaded = Windows.registerDelay usecs #else | threaded = Event.registerDelay usecs #endif | otherwise = error "registerDelay: requires -threaded" foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool