module GHC.Event.Thread
( getSystemEventManager
, ensureIOManagerIsRunning
, threadWaitRead
, threadWaitWrite
, closeFdWith
, threadDelay
, registerDelay
) where
import Data.IORef (IORef, newIORef, readIORef, writeIORef)
import Data.Maybe (Maybe(..))
import Foreign.C.Error (eBADF, errnoToIOError)
import Foreign.Ptr (Ptr)
import GHC.Base
import GHC.Conc.Sync (TVar, ThreadId, ThreadStatus(..), atomically, forkIO,
labelThread, modifyMVar_, newTVar, sharedCAF,
threadStatus, writeTVar)
import GHC.IO (mask_, onException)
import GHC.IO.Exception (ioError)
import GHC.MVar (MVar, newEmptyMVar, newMVar, putMVar, takeMVar)
import GHC.Event.Internal (eventIs, evtClose)
import GHC.Event.Manager (Event, EventManager, evtRead, evtWrite, loop,
new, registerFd, unregisterFd_, registerTimeout)
import qualified GHC.Event.Manager as M
import System.IO.Unsafe (unsafePerformIO)
import System.Posix.Types (Fd)
threadDelay :: Int -> IO ()
threadDelay usecs = mask_ $ do
Just mgr <- getSystemEventManager
m <- newEmptyMVar
reg <- registerTimeout mgr usecs (putMVar m ())
takeMVar m `onException` M.unregisterTimeout mgr reg
registerDelay :: Int -> IO (TVar Bool)
registerDelay usecs = do
t <- atomically $ newTVar False
Just mgr <- getSystemEventManager
_ <- registerTimeout mgr usecs . atomically $ writeTVar t True
return t
threadWaitRead :: Fd -> IO ()
threadWaitRead = threadWait evtRead
threadWaitWrite :: Fd -> IO ()
threadWaitWrite = threadWait evtWrite
closeFdWith :: (Fd -> IO ())
-> Fd
-> IO ()
closeFdWith close fd = do
Just mgr <- getSystemEventManager
M.closeFd mgr close fd
threadWait :: Event -> Fd -> IO ()
threadWait evt fd = mask_ $ do
m <- newEmptyMVar
Just mgr <- getSystemEventManager
reg <- registerFd mgr (\reg e -> unregisterFd_ mgr reg >> putMVar m e) fd evt
evt' <- takeMVar m `onException` unregisterFd_ mgr reg
if evt' `eventIs` evtClose
then ioError $ errnoToIOError "threadWait" eBADF Nothing Nothing
else return ()
getSystemEventManager :: IO (Maybe EventManager)
getSystemEventManager = readIORef eventManager
foreign import ccall unsafe "getOrSetSystemEventThreadEventManagerStore"
getOrSetSystemEventThreadEventManagerStore :: Ptr a -> IO (Ptr a)
eventManager :: IORef (Maybe EventManager)
eventManager = unsafePerformIO $ do
em <- newIORef Nothing
sharedCAF em getOrSetSystemEventThreadEventManagerStore
foreign import ccall unsafe "getOrSetSystemEventThreadIOManagerThreadStore"
getOrSetSystemEventThreadIOManagerThreadStore :: Ptr a -> IO (Ptr a)
ioManager :: MVar (Maybe ThreadId)
ioManager = unsafePerformIO $ do
m <- newMVar Nothing
sharedCAF m getOrSetSystemEventThreadIOManagerThreadStore
ensureIOManagerIsRunning :: IO ()
ensureIOManagerIsRunning
| not threaded = return ()
| otherwise = do
startIOManagerThread
startIOManagerThread :: IO ()
startIOManagerThread = modifyMVar_ ioManager $ \old -> do
let create = do
!mgr <- new
writeIORef eventManager $ Just mgr
!t <- forkIO $ loop mgr
labelThread t "IOManager"
return $ Just t
case old of
Nothing -> create
st@(Just t) -> do
s <- threadStatus t
case s of
ThreadFinished -> create
ThreadDied -> do
mem <- readIORef eventManager
_ <- case mem of
Nothing -> return ()
Just em -> M.cleanup em
create
_other -> return st
foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool