    {-# OPTIONS_GHC -XNoImplicitPrelude #-}
    {-# 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 System.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