1 {-# LANGUAGE NoImplicitPrelude #-}
2 {-# OPTIONS_GHC -fno-warn-missing-signatures #-}
3 {-# OPTIONS_HADDOCK not-home #-}
5 -----------------------------------------------------------------------------
7 -- Module : GHC.Conc.Windows
8 -- Copyright : (c) The University of Glasgow, 1994-2002
9 -- License : see libraries/base/LICENSE
11 -- Maintainer : cvs-ghc@haskell.org
12 -- Stability : internal
13 -- Portability : non-portable (GHC extensions)
15 -- Windows I/O manager
17 -----------------------------------------------------------------------------
20 module GHC.Conc.Windows
21 ( ensureIOManagerIsRunning
28 , asyncRead -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
29 , asyncWrite -- :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
30 , asyncDoProc -- :: FunPtr (Ptr a -> IO Int) -> Ptr a -> IO Int
32 , asyncReadBA -- :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int, Int)
33 , asyncWriteBA -- :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int, Int)
41 import Data.Bits (shiftR)
42 import Data.Maybe (Maybe(..))
44 import Foreign.C.Error (throwErrno)
47 import GHC.Enum (Enum)
48 import GHC.IO (unsafePerformIO)
51 import GHC.Num (Num(..))
53 import GHC.Read (Read)
54 import GHC.Real (div, fromIntegral)
55 import GHC.Show (Show)
56 import GHC.Word (Word32, Word64)
58 -- ----------------------------------------------------------------------------
61 -- Note: threadWaitRead and threadWaitWrite aren't really functional
62 -- on Win32, but left in there because lib code (still) uses them (the manner
63 -- in which they're used doesn't cause problems on a Win32 platform though.)
65 asyncRead :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
66 asyncRead (I# fd) (I# isSock) (I# len) (Ptr buf) =
67 IO $ \s -> case asyncRead# fd isSock len buf s of
68 (# s', len#, err# #) -> (# s', (I# len#, I# err#) #)
70 asyncWrite :: Int -> Int -> Int -> Ptr a -> IO (Int, Int)
71 asyncWrite (I# fd) (I# isSock) (I# len) (Ptr buf) =
72 IO $ \s -> case asyncWrite# fd isSock len buf s of
73 (# s', len#, err# #) -> (# s', (I# len#, I# err#) #)
75 asyncDoProc :: FunPtr (Ptr a -> IO Int) -> Ptr a -> IO Int
76 asyncDoProc (FunPtr proc) (Ptr param) =
77 -- the 'length' value is ignored; simplifies implementation of
78 -- the async*# primops to have them all return the same result.
79 IO $ \s -> case asyncDoProc# proc param s of
80 (# s', _len#, err# #) -> (# s', I# err# #)
82 -- to aid the use of these primops by the IO Handle implementation,
83 -- provide the following convenience funs:
85 -- this better be a pinned byte array!
86 asyncReadBA :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int,Int)
87 asyncReadBA fd isSock len off bufB =
88 asyncRead fd isSock len ((Ptr (byteArrayContents# (unsafeCoerce# bufB))) `plusPtr` off)
90 asyncWriteBA :: Int -> Int -> Int -> Int -> MutableByteArray# RealWorld -> IO (Int,Int)
91 asyncWriteBA fd isSock len off bufB =
92 asyncWrite fd isSock len ((Ptr (byteArrayContents# (unsafeCoerce# bufB))) `plusPtr` off)
94 -- ----------------------------------------------------------------------------
95 -- Threaded RTS implementation of threadDelay
97 -- | Suspends the current thread for a given number of microseconds
100 -- There is no guarantee that the thread will be rescheduled promptly
101 -- when the delay has expired, but the thread will never continue to
102 -- run /earlier/ than specified.
104 threadDelay :: Int -> IO ()
106 | threaded = waitForDelayEvent time
107 | otherwise = IO $ \s ->
108 case time of { I# time# ->
109 case delay# time# s of { s' -> (# s', () #)
112 -- | Set the value of returned TVar to True after a given number of
113 -- microseconds. The caveats associated with threadDelay also apply.
115 registerDelay :: Int -> IO (TVar Bool)
117 | threaded = waitForDelayEventSTM usecs
118 | otherwise = error "registerDelay: requires -threaded"
120 foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
122 waitForDelayEvent :: Int -> IO ()
123 waitForDelayEvent usecs = do
125 target <- calculateTarget usecs
126 atomicModifyIORef pendingDelays (\xs -> (Delay target m : xs, ()))
130 -- Delays for use in STM
131 waitForDelayEventSTM :: Int -> IO (TVar Bool)
132 waitForDelayEventSTM usecs = do
133 t <- atomically $ newTVar False
134 target <- calculateTarget usecs
135 atomicModifyIORef pendingDelays (\xs -> (DelaySTM target t : xs, ()))
139 calculateTarget :: Int -> IO USecs
140 calculateTarget usecs = do
142 return $ now + (fromIntegral usecs)
145 = Delay {-# UNPACK #-} !USecs {-# UNPACK #-} !(MVar ())
146 | DelaySTM {-# UNPACK #-} !USecs {-# UNPACK #-} !(TVar Bool)
148 {-# NOINLINE pendingDelays #-}
149 pendingDelays :: IORef [DelayReq]
150 pendingDelays = unsafePerformIO $ do
152 sharedCAF m getOrSetGHCConcWindowsPendingDelaysStore
154 foreign import ccall unsafe "getOrSetGHCConcWindowsPendingDelaysStore"
155 getOrSetGHCConcWindowsPendingDelaysStore :: Ptr a -> IO (Ptr a)
157 {-# NOINLINE ioManagerThread #-}
158 ioManagerThread :: MVar (Maybe ThreadId)
159 ioManagerThread = unsafePerformIO $ do
161 sharedCAF m getOrSetGHCConcWindowsIOManagerThreadStore
163 foreign import ccall unsafe "getOrSetGHCConcWindowsIOManagerThreadStore"
164 getOrSetGHCConcWindowsIOManagerThreadStore :: Ptr a -> IO (Ptr a)
166 ensureIOManagerIsRunning :: IO ()
167 ensureIOManagerIsRunning
168 | threaded = startIOManagerThread
169 | otherwise = return ()
171 startIOManagerThread :: IO ()
172 startIOManagerThread = do
173 modifyMVar_ ioManagerThread $ \old -> do
174 let create = do t <- forkIO ioManager; return (Just t)
180 ThreadFinished -> create
182 _other -> return (Just t)
184 insertDelay :: DelayReq -> [DelayReq] -> [DelayReq]
185 insertDelay d [] = [d]
186 insertDelay d1 ds@(d2 : rest)
187 | delayTime d1 <= delayTime d2 = d1 : ds
188 | otherwise = d2 : insertDelay d1 rest
190 delayTime :: DelayReq -> USecs
191 delayTime (Delay t _) = t
192 delayTime (DelaySTM t _) = t
196 foreign import ccall unsafe "getUSecOfDay"
197 getUSecOfDay :: IO USecs
199 {-# NOINLINE prodding #-}
200 prodding :: IORef Bool
201 prodding = unsafePerformIO $ do
203 sharedCAF r getOrSetGHCConcWindowsProddingStore
205 foreign import ccall unsafe "getOrSetGHCConcWindowsProddingStore"
206 getOrSetGHCConcWindowsProddingStore :: Ptr a -> IO (Ptr a)
208 prodServiceThread :: IO ()
209 prodServiceThread = do
210 -- NB. use atomicModifyIORef here, otherwise there are race
211 -- conditions in which prodding is left at True but the server is
212 -- blocked in select().
213 was_set <- atomicModifyIORef prodding $ \b -> (True,b)
214 unless was_set wakeupIOManager
216 -- ----------------------------------------------------------------------------
217 -- Windows IO manager thread
221 wakeup <- c_getIOManagerEvent
222 service_loop wakeup []
224 service_loop :: HANDLE -- read end of pipe
225 -> [DelayReq] -- current delay requests
228 service_loop wakeup old_delays = do
229 -- pick up new delay requests
230 new_delays <- atomicModifyIORef pendingDelays (\a -> ([],a))
231 let delays = foldr insertDelay old_delays new_delays
234 (delays', timeout) <- getDelay now delays
236 r <- c_WaitForSingleObject wakeup timeout
238 0xffffffff -> do c_maperrno; throwErrno "service_loop"
240 r2 <- c_readIOManagerEvent
243 _ | r2 == io_MANAGER_WAKEUP -> return False
244 _ | r2 == io_MANAGER_DIE -> return True
245 0 -> return False -- spurious wakeup
246 _ -> do start_console_handler (r2 `shiftR` 1); return False
247 unless exit $ service_cont wakeup delays'
249 _other -> service_cont wakeup delays' -- probably timeout
251 service_cont :: HANDLE -> [DelayReq] -> IO ()
252 service_cont wakeup delays = do
253 r <- atomicModifyIORef prodding (\_ -> (False,False))
254 r `seq` return () -- avoid space leak
255 service_loop wakeup delays
257 -- must agree with rts/win32/ThrIOManager.c
258 io_MANAGER_WAKEUP, io_MANAGER_DIE :: Word32
259 io_MANAGER_WAKEUP = 0xffffffff
260 io_MANAGER_DIE = 0xfffffffe
266 -- these are sent to Services only.
269 deriving (Eq, Ord, Enum, Show, Read, Typeable)
271 start_console_handler :: Word32 -> IO ()
272 start_console_handler r =
273 case toWin32ConsoleEvent r of
274 Just x -> withMVar win32ConsoleHandler $ \handler -> do
275 _ <- forkIO (handler x)
279 toWin32ConsoleEvent :: Num a => a -> Maybe ConsoleEvent
280 toWin32ConsoleEvent ev =
282 0 {- CTRL_C_EVENT-} -> Just ControlC
283 1 {- CTRL_BREAK_EVENT-} -> Just Break
284 2 {- CTRL_CLOSE_EVENT-} -> Just Close
285 5 {- CTRL_LOGOFF_EVENT-} -> Just Logoff
286 6 {- CTRL_SHUTDOWN_EVENT-} -> Just Shutdown
289 win32ConsoleHandler :: MVar (ConsoleEvent -> IO ())
290 win32ConsoleHandler = unsafePerformIO (newMVar (error "win32ConsoleHandler"))
292 wakeupIOManager :: IO ()
293 wakeupIOManager = c_sendIOManagerEvent io_MANAGER_WAKEUP
295 -- Walk the queue of pending delays, waking up any that have passed
296 -- and return the smallest delay to wait for. The queue of pending
297 -- delays is kept ordered.
298 getDelay :: USecs -> [DelayReq] -> IO ([DelayReq], DWORD)
299 getDelay _ [] = return ([], iNFINITE)
300 getDelay now all@(d : rest)
302 Delay time m | now >= time -> do
305 DelaySTM time t | now >= time -> do
306 atomically $ writeTVar t True
309 -- delay is in millisecs for WaitForSingleObject
310 let micro_seconds = delayTime d - now
311 milli_seconds = (micro_seconds + 999) `div` 1000
312 in return (all, fromIntegral milli_seconds)
314 -- ToDo: this just duplicates part of System.Win32.Types, which isn't
315 -- available yet. We should move some Win32 functionality down here,
316 -- maybe as part of the grand reorganisation of the base package...
321 iNFINITE = 0xFFFFFFFF -- urgh
323 foreign import ccall unsafe "getIOManagerEvent" -- in the RTS (ThrIOManager.c)
324 c_getIOManagerEvent :: IO HANDLE
326 foreign import ccall unsafe "readIOManagerEvent" -- in the RTS (ThrIOManager.c)
327 c_readIOManagerEvent :: IO Word32
329 foreign import ccall unsafe "sendIOManagerEvent" -- in the RTS (ThrIOManager.c)
330 c_sendIOManagerEvent :: Word32 -> IO ()
332 foreign import ccall unsafe "maperrno" -- in Win32Utils.c
335 foreign import stdcall "WaitForSingleObject"
336 c_WaitForSingleObject :: HANDLE -> DWORD -> IO DWORD