1 {-# LANGUAGE BangPatterns, ForeignFunctionInterface, NoImplicitPrelude #-}
3 module System.Event.Thread
5 ensureIOManagerIsRunning
12 import Data.IORef (IORef, newIORef, readIORef, writeIORef)
13 import Data.Maybe (Maybe(..))
14 import Foreign.Ptr (Ptr)
16 import GHC.Conc.Sync (TVar, ThreadId, ThreadStatus(..), atomically, forkIO,
17 labelThread, modifyMVar_, newTVar, sharedCAF,
18 threadStatus, writeTVar)
19 import GHC.MVar (MVar, newEmptyMVar, newMVar, putMVar, takeMVar)
20 import GHC.Num (fromInteger)
22 import System.Event.Manager (Event, EventManager, evtRead, evtWrite, loop,
23 new, registerFd, unregisterFd_, registerTimeout)
24 import System.IO.Unsafe (unsafePerformIO)
25 import System.Posix.Types (Fd)
27 -- | Suspends the current thread for a given number of microseconds
30 -- There is no guarantee that the thread will be rescheduled promptly
31 -- when the delay has expired, but the thread will never continue to
32 -- run /earlier/ than specified.
33 threadDelay :: Int -> IO ()
34 threadDelay usecs = do
35 Just mgr <- readIORef eventManager
37 _ <- registerTimeout mgr (usecs `div` 1000) (putMVar m ())
40 -- | Set the value of returned TVar to True after a given number of
41 -- microseconds. The caveats associated with threadDelay also apply.
43 registerDelay :: Int -> IO (TVar Bool)
44 registerDelay usecs = do
45 t <- atomically $ newTVar False
46 Just mgr <- readIORef eventManager
47 _ <- registerTimeout mgr (usecs `div` 1000) . atomically $ writeTVar t True
50 -- | Block the current thread until data is available to read from the
51 -- given file descriptor.
52 threadWaitRead :: Fd -> IO ()
53 threadWaitRead = threadWait evtRead
54 {-# INLINE threadWaitRead #-}
56 -- | Block the current thread until the given file descriptor can
57 -- accept data to write.
58 threadWaitWrite :: Fd -> IO ()
59 threadWaitWrite = threadWait evtWrite
60 {-# INLINE threadWaitWrite #-}
62 threadWait :: Event -> Fd -> IO ()
63 threadWait evt fd = do
65 Just mgr <- readIORef eventManager
66 _ <- registerFd mgr (\reg _ -> unregisterFd_ mgr reg >> putMVar m ()) fd evt
69 foreign import ccall unsafe "getOrSetSystemEventThreadEventManagerStore"
70 getOrSetSystemEventThreadEventManagerStore :: Ptr a -> IO (Ptr a)
72 eventManager :: IORef (Maybe EventManager)
73 eventManager = unsafePerformIO $ do
74 em <- newIORef Nothing
75 sharedCAF em getOrSetSystemEventThreadEventManagerStore
76 {-# NOINLINE eventManager #-}
78 foreign import ccall unsafe "getOrSetSystemEventThreadIOManagerThreadStore"
79 getOrSetSystemEventThreadIOManagerThreadStore :: Ptr a -> IO (Ptr a)
81 {-# NOINLINE ioManager #-}
82 ioManager :: MVar (Maybe ThreadId)
83 ioManager = unsafePerformIO $ do
85 sharedCAF m getOrSetSystemEventThreadIOManagerThreadStore
87 ensureIOManagerIsRunning :: IO ()
88 ensureIOManagerIsRunning
89 | not threaded = return ()
90 | otherwise = modifyMVar_ ioManager $ \old -> do
93 writeIORef eventManager $ Just mgr
94 !t <- forkIO $ loop mgr
95 labelThread t "IOManager"
102 ThreadFinished -> create
106 foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool