Duncan Coutts pushed to branch wip/dcoutts/io-manager-feature-bitset at Glasgow Haskell Compiler / GHC
Commits:
-
357d3081
by Duncan Coutts at 2026-09-21T20:43:40+01:00
-
b6dbdec2
by Duncan Coutts at 2026-09-21T20:43:40+01:00
-
ca52d820
by Duncan Coutts at 2026-09-21T20:43:40+01:00
5 changed files:
- libraries/base/src/System/Timeout.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/IO.hs
- libraries/ghc-internal/src/GHC/Internal/Conc/POSIX.hs
- libraries/ghc-internal/src/GHC/Internal/Event/Thread.hs
- libraries/ghc-internal/src/GHC/Internal/IO/SubSystem.hs
Changes:
| ... | ... | @@ -23,6 +23,7 @@ import Prelude |
| 23 | 23 | import GHC.Internal.Control.Monad
|
| 24 | 24 | import GHC.Internal.Event (getSystemTimerManager,
|
| 25 | 25 | registerTimeout, unregisterTimeout)
|
| 26 | +import GHC.Internal.IO.SubSystem (iomgrInLib)
|
|
| 26 | 27 | #endif
|
| 27 | 28 | |
| 28 | 29 | import Control.Concurrent
|
| ... | ... | @@ -105,8 +106,8 @@ timeout n f |
| 105 | 106 | | n < 0 = fmap Just f
|
| 106 | 107 | | n == 0 = return Nothing
|
| 107 | 108 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 108 | - | rtsSupportsBoundThreads = do
|
|
| 109 | - -- In the threaded RTS, we use the Timer Manager to delay the
|
|
| 109 | + | iomgrInLib = do
|
|
| 110 | + -- If the Timer Manager is available then use it to delay the
|
|
| 110 | 111 | -- (fairly expensive) 'forkIO' call until the timeout has expired.
|
| 111 | 112 | --
|
| 112 | 113 | -- An additional thread is required for the actual delivery of
|
| ... | ... | @@ -71,10 +71,10 @@ import GHC.Internal.Prim (Int#, State#, RealWorld, |
| 71 | 71 | delay#, waitRead#, waitWrite#, raiseIO#)
|
| 72 | 72 | import GHC.Internal.Real ( fromIntegral )
|
| 73 | 73 | import GHC.Internal.System.Posix.Types
|
| 74 | +import GHC.Internal.IO.SubSystem
|
|
| 74 | 75 | |
| 75 | 76 | #if defined(mingw32_HOST_OS)
|
| 76 | 77 | import qualified GHC.Internal.Conc.Windows as Windows
|
| 77 | -import GHC.Internal.IO.SubSystem
|
|
| 78 | 78 | import GHC.Internal.Conc.Windows (asyncRead, asyncWrite, asyncDoProc, asyncReadBA,
|
| 79 | 79 | asyncWriteBA, ConsoleEvent(..), win32ConsoleHandler,
|
| 80 | 80 | toWin32ConsoleEvent)
|
| ... | ... | @@ -102,18 +102,18 @@ ensureIOManagerIsRunning = Windows.ensureIOManagerIsRunning |
| 102 | 102 | --
|
| 103 | 103 | -- @since base-4.15
|
| 104 | 104 | interruptIOManager :: IO ()
|
| 105 | -#if !defined(mingw32_HOST_OS)
|
|
| 106 | -interruptIOManager = return ()
|
|
| 107 | -#else
|
|
| 108 | -interruptIOManager = Windows.interruptIOManager
|
|
| 105 | +interruptIOManager
|
|
| 106 | +#if defined(mingw32_HOST_OS)
|
|
| 107 | + | iomgrInLib = Windows.interruptIOManager
|
|
| 109 | 108 | #endif
|
| 109 | + | otherwise = return ()
|
|
| 110 | 110 | |
| 111 | 111 | ioManagerCapabilitiesChanged :: IO ()
|
| 112 | +ioManagerCapabilitiesChanged
|
|
| 112 | 113 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 113 | -ioManagerCapabilitiesChanged = Event.ioManagerCapabilitiesChanged
|
|
| 114 | -#else
|
|
| 115 | -ioManagerCapabilitiesChanged = return ()
|
|
| 114 | + | iomgrInLib = Event.ioManagerCapabilitiesChanged
|
|
| 116 | 115 | #endif
|
| 116 | + | otherwise = return ()
|
|
| 117 | 117 | |
| 118 | 118 | -- | Block the current thread until data is available to read on the
|
| 119 | 119 | -- given file descriptor (GHC only).
|
| ... | ... | @@ -124,9 +124,9 @@ ioManagerCapabilitiesChanged = return () |
| 124 | 124 | threadWaitRead :: Fd -> IO ()
|
| 125 | 125 | threadWaitRead fd
|
| 126 | 126 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 127 | - | threaded = Event.threadWaitRead fd
|
|
| 127 | + | iomgrInLib = Event.threadWaitRead fd
|
|
| 128 | 128 | #endif
|
| 129 | - | otherwise = IO $ \s ->
|
|
| 129 | + | otherwise = IO $ \s ->
|
|
| 130 | 130 | case fromIntegral fd of { I# fd# ->
|
| 131 | 131 | case waitRead# fd# s of { s' -> (# s', () #)
|
| 132 | 132 | }}
|
| ... | ... | @@ -140,9 +140,9 @@ threadWaitRead fd |
| 140 | 140 | threadWaitWrite :: Fd -> IO ()
|
| 141 | 141 | threadWaitWrite fd
|
| 142 | 142 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 143 | - | threaded = Event.threadWaitWrite fd
|
|
| 143 | + | iomgrInLib = Event.threadWaitWrite fd
|
|
| 144 | 144 | #endif
|
| 145 | - | otherwise = IO $ \s ->
|
|
| 145 | + | otherwise = IO $ \s ->
|
|
| 146 | 146 | case fromIntegral fd of { I# fd# ->
|
| 147 | 147 | case waitWrite# fd# s of { s' -> (# s', () #)
|
| 148 | 148 | }}
|
| ... | ... | @@ -154,9 +154,9 @@ threadWaitWrite fd |
| 154 | 154 | threadWaitReadSTM :: Fd -> IO (STM.STM (), IO ())
|
| 155 | 155 | threadWaitReadSTM fd
|
| 156 | 156 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 157 | - | threaded = Event.threadWaitReadSTM fd
|
|
| 157 | + | iomgrInLib = Event.threadWaitReadSTM fd
|
|
| 158 | 158 | #endif
|
| 159 | - | otherwise = do
|
|
| 159 | + | otherwise = do
|
|
| 160 | 160 | m <- STM.newTVarIO False
|
| 161 | 161 | t <- Sync.forkIO $ do
|
| 162 | 162 | threadWaitRead fd
|
| ... | ... | @@ -173,9 +173,9 @@ threadWaitReadSTM fd |
| 173 | 173 | threadWaitWriteSTM :: Fd -> IO (STM.STM (), IO ())
|
| 174 | 174 | threadWaitWriteSTM fd
|
| 175 | 175 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 176 | - | threaded = Event.threadWaitWriteSTM fd
|
|
| 176 | + | iomgrInLib = Event.threadWaitWriteSTM fd
|
|
| 177 | 177 | #endif
|
| 178 | - | otherwise = do
|
|
| 178 | + | otherwise = do
|
|
| 179 | 179 | m <- STM.newTVarIO False
|
| 180 | 180 | t <- Sync.forkIO $ do
|
| 181 | 181 | threadWaitWrite fd
|
| ... | ... | @@ -206,9 +206,9 @@ closeFdWith :: (Fd -> IO ()) -- ^ Low-level action that performs the real close. |
| 206 | 206 | -> IO ()
|
| 207 | 207 | closeFdWith close fd
|
| 208 | 208 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 209 | - | threaded = Event.closeFdWith close fd
|
|
| 209 | + | iomgrInLib = Event.closeFdWith close fd
|
|
| 210 | 210 | #endif
|
| 211 | - | otherwise = close fd
|
|
| 211 | + | otherwise = close fd
|
|
| 212 | 212 | |
| 213 | 213 | -- | Suspends the current thread for a given number of microseconds
|
| 214 | 214 | -- (GHC only).
|
| ... | ... | @@ -223,12 +223,11 @@ closeFdWith close fd |
| 223 | 223 | threadDelay :: Int -> IO ()
|
| 224 | 224 | threadDelay time
|
| 225 | 225 | #if defined(mingw32_HOST_OS)
|
| 226 | - | isWindowsNativeIO = Windows.threadDelay time
|
|
| 227 | - | threaded = Windows.threadDelay time
|
|
| 226 | + | iomgrInLib = Windows.threadDelay time
|
|
| 228 | 227 | #elif defined(wasm32_HOST_ARCH)
|
| 229 | 228 | | Wasm.isJSFFIUsed = Wasm.threadDelay time
|
| 230 | 229 | #elif !defined(javascript_HOST_ARCH)
|
| 231 | - | threaded = Event.threadDelay time
|
|
| 230 | + | iomgrInLib = Event.threadDelay time
|
|
| 232 | 231 | #endif
|
| 233 | 232 | | otherwise = IO $ \s ->
|
| 234 | 233 | case time of { I# time# ->
|
| ... | ... | @@ -245,17 +244,12 @@ threadDelay time |
| 245 | 244 | registerDelay :: Int -> IO (TVar Bool)
|
| 246 | 245 | registerDelay _usecs
|
| 247 | 246 | #if defined(mingw32_HOST_OS)
|
| 248 | - | isWindowsNativeIO = Windows.registerDelay _usecs
|
|
| 249 | - | threaded = Windows.registerDelay _usecs
|
|
| 247 | + | iomgrInLib = Windows.registerDelay _usecs
|
|
| 250 | 248 | #elif !defined(javascript_HOST_ARCH)
|
| 251 | - | threaded = Event.registerDelay _usecs
|
|
| 249 | + | iomgrInLib = Event.registerDelay _usecs
|
|
| 252 | 250 | #endif
|
| 253 | 251 | | otherwise = errorWithoutStackTrace "registerDelay: requires -threaded"
|
| 254 | 252 | |
| 255 | -#if !defined(javascript_HOST_ARCH)
|
|
| 256 | -foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
|
|
| 257 | -#endif
|
|
| 258 | - |
|
| 259 | 253 | |
| 260 | 254 | -- ---------------------------------------------------------------------------
|
| 261 | 255 | -- PrimIOException
|
| ... | ... | @@ -120,7 +120,7 @@ asyncWriteBA fd isSock len off bufB = |
| 120 | 120 | --
|
| 121 | 121 | threadDelay :: Int -> IO ()
|
| 122 | 122 | threadDelay time
|
| 123 | - | threaded = waitForDelayEvent time
|
|
| 123 | + | iomgrInLib = waitForDelayEvent time
|
|
| 124 | 124 | | otherwise = IO $ \s ->
|
| 125 | 125 | case time of { I# time# ->
|
| 126 | 126 | case delay# time# s of { s' -> (# s', () #)
|
| ... | ... | @@ -134,11 +134,9 @@ threadDelay time |
| 134 | 134 | --
|
| 135 | 135 | registerDelay :: Int -> IO (TVar Bool)
|
| 136 | 136 | registerDelay usecs
|
| 137 | - | threaded = waitForDelayEventSTM usecs
|
|
| 137 | + | iomgrInLib = waitForDelayEventSTM usecs
|
|
| 138 | 138 | | otherwise = errorWithoutStackTrace "registerDelay: requires -threaded"
|
| 139 | 139 | |
| 140 | -foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
|
|
| 141 | - |
|
| 142 | 140 | waitForDelayEvent :: Int -> IO ()
|
| 143 | 141 | waitForDelayEvent usecs = do
|
| 144 | 142 | m <- newEmptyMVar
|
| ... | ... | @@ -185,7 +183,7 @@ foreign import ccall unsafe "getOrSetGHCConcWindowsIOManagerThreadStore" |
| 185 | 183 | |
| 186 | 184 | ensureIOManagerIsRunning :: IO ()
|
| 187 | 185 | ensureIOManagerIsRunning
|
| 188 | - | threaded = startIOManagerThread
|
|
| 186 | + | iomgrInLib = startIOManagerThread
|
|
| 189 | 187 | | otherwise = return ()
|
| 190 | 188 | |
| 191 | 189 | interruptIOManager :: IO ()
|
| ... | ... | @@ -49,6 +49,7 @@ import GHC.Internal.IO (mask_, uninterruptibleMask_, onException) |
| 49 | 49 | import GHC.Internal.IO.Exception (ioError)
|
| 50 | 50 | import GHC.Internal.IOArray (IOArray, newIOArray, readIOArray, writeIOArray,
|
| 51 | 51 | boundsIOArray)
|
| 52 | +import GHC.Internal.IO.SubSystem (iomgrInRTS)
|
|
| 52 | 53 | import GHC.Internal.MVar (MVar, newEmptyMVar, newMVar, putMVar, takeMVar)
|
| 53 | 54 | import GHC.Internal.Event.Control (controlWriteFd)
|
| 54 | 55 | import GHC.Internal.Event.Internal (eventIs, evtClose)
|
| ... | ... | @@ -325,7 +326,7 @@ timerManagerThreadVar = unsafePerformIO $ do |
| 325 | 326 | |
| 326 | 327 | ensureIOManagerIsRunning :: IO ()
|
| 327 | 328 | ensureIOManagerIsRunning
|
| 328 | - | not threaded = return ()
|
|
| 329 | + | iomgrInRTS = return ()
|
|
| 329 | 330 | | otherwise = do
|
| 330 | 331 | startIOManagerThreads
|
| 331 | 332 | startTimerManagerThread
|
| ... | ... | @@ -409,8 +410,6 @@ startTimerManagerThread = modifyMVar_ timerManagerThreadVar $ \old -> do |
| 409 | 410 | create
|
| 410 | 411 | _other -> return st
|
| 411 | 412 | |
| 412 | -foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
|
|
| 413 | - |
|
| 414 | 413 | ioManagerCapabilitiesChanged :: IO ()
|
| 415 | 414 | ioManagerCapabilitiesChanged =
|
| 416 | 415 | withMVar ioManagerLock $ \_ -> do
|
| ... | ... | @@ -51,6 +51,7 @@ module GHC.Internal.IO.SubSystem ( |
| 51 | 51 | -- other. This can instead now be done conditionally on the I\/O manager
|
| 52 | 52 | -- feature 'iomgrInRTS'.
|
| 53 | 53 | iomgrInRTS,
|
| 54 | + iomgrInLib,
|
|
| 54 | 55 | iomgrUsesHANDLEs,
|
| 55 | 56 | ) where
|
| 56 | 57 | |
| ... | ... | @@ -150,6 +151,11 @@ ioManagerFeatureBitmask IOMgrUsesHANDLEs = 1## `uncheckedShiftL#` 1# |
| 150 | 151 | iomgrInRTS :: Bool
|
| 151 | 152 | iomgrInRTS = ioManagerFeature IOMgrInRTS
|
| 152 | 153 | |
| 154 | +-- | The inverse of 'iomgrInRTS'. In some cases the logic may read more clearly
|
|
| 155 | +-- this way round.
|
|
| 156 | +iomgrInLib :: Bool
|
|
| 157 | +iomgrInLib = not iomgrInRTS
|
|
| 158 | + |
|
| 153 | 159 | -- | This means that the I\/O manager uses the Win32 API's HANDLE type to
|
| 154 | 160 | -- refer to open files. The inverse is that it uses Posix style fds.
|
| 155 | 161 | -- This is always false on Poisx platforms, while on Windows it is true
|