Duncan Coutts pushed to branch wip/dcoutts/io-manager-feature-bitset at Glasgow Haskell Compiler / GHC
Commits:
-
2abd3dd2
by Duncan Coutts at 2026-09-22T09:36:27+01:00
-
4b8339e3
by Duncan Coutts at 2026-09-22T09:36:27+01:00
-
01b5c5e8
by Duncan Coutts at 2026-09-22T09:36:27+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
|
| ... | ... | @@ -72,9 +72,12 @@ import GHC.Internal.Prim (Int#, State#, RealWorld, |
| 72 | 72 | import GHC.Internal.Real ( fromIntegral )
|
| 73 | 73 | import GHC.Internal.System.Posix.Types
|
| 74 | 74 | |
| 75 | +#if !defined(javascript_HOST_ARCH)
|
|
| 76 | +import GHC.Internal.IO.SubSystem
|
|
| 77 | +#endif
|
|
| 78 | + |
|
| 75 | 79 | #if defined(mingw32_HOST_OS)
|
| 76 | 80 | import qualified GHC.Internal.Conc.Windows as Windows
|
| 77 | -import GHC.Internal.IO.SubSystem
|
|
| 78 | 81 | import GHC.Internal.Conc.Windows (asyncRead, asyncWrite, asyncDoProc, asyncReadBA,
|
| 79 | 82 | asyncWriteBA, ConsoleEvent(..), win32ConsoleHandler,
|
| 80 | 83 | toWin32ConsoleEvent)
|
| ... | ... | @@ -102,18 +105,18 @@ ensureIOManagerIsRunning = Windows.ensureIOManagerIsRunning |
| 102 | 105 | --
|
| 103 | 106 | -- @since base-4.15
|
| 104 | 107 | interruptIOManager :: IO ()
|
| 105 | -#if !defined(mingw32_HOST_OS)
|
|
| 106 | -interruptIOManager = return ()
|
|
| 107 | -#else
|
|
| 108 | -interruptIOManager = Windows.interruptIOManager
|
|
| 108 | +interruptIOManager
|
|
| 109 | +#if defined(mingw32_HOST_OS)
|
|
| 110 | + | iomgrInLib = Windows.interruptIOManager
|
|
| 109 | 111 | #endif
|
| 112 | + | otherwise = return ()
|
|
| 110 | 113 | |
| 111 | 114 | ioManagerCapabilitiesChanged :: IO ()
|
| 115 | +ioManagerCapabilitiesChanged
|
|
| 112 | 116 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 113 | -ioManagerCapabilitiesChanged = Event.ioManagerCapabilitiesChanged
|
|
| 114 | -#else
|
|
| 115 | -ioManagerCapabilitiesChanged = return ()
|
|
| 117 | + | iomgrInLib = Event.ioManagerCapabilitiesChanged
|
|
| 116 | 118 | #endif
|
| 119 | + | otherwise = return ()
|
|
| 117 | 120 | |
| 118 | 121 | -- | Block the current thread until data is available to read on the
|
| 119 | 122 | -- given file descriptor (GHC only).
|
| ... | ... | @@ -124,9 +127,9 @@ ioManagerCapabilitiesChanged = return () |
| 124 | 127 | threadWaitRead :: Fd -> IO ()
|
| 125 | 128 | threadWaitRead fd
|
| 126 | 129 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 127 | - | threaded = Event.threadWaitRead fd
|
|
| 130 | + | iomgrInLib = Event.threadWaitRead fd
|
|
| 128 | 131 | #endif
|
| 129 | - | otherwise = IO $ \s ->
|
|
| 132 | + | otherwise = IO $ \s ->
|
|
| 130 | 133 | case fromIntegral fd of { I# fd# ->
|
| 131 | 134 | case waitRead# fd# s of { s' -> (# s', () #)
|
| 132 | 135 | }}
|
| ... | ... | @@ -140,9 +143,9 @@ threadWaitRead fd |
| 140 | 143 | threadWaitWrite :: Fd -> IO ()
|
| 141 | 144 | threadWaitWrite fd
|
| 142 | 145 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 143 | - | threaded = Event.threadWaitWrite fd
|
|
| 146 | + | iomgrInLib = Event.threadWaitWrite fd
|
|
| 144 | 147 | #endif
|
| 145 | - | otherwise = IO $ \s ->
|
|
| 148 | + | otherwise = IO $ \s ->
|
|
| 146 | 149 | case fromIntegral fd of { I# fd# ->
|
| 147 | 150 | case waitWrite# fd# s of { s' -> (# s', () #)
|
| 148 | 151 | }}
|
| ... | ... | @@ -154,9 +157,9 @@ threadWaitWrite fd |
| 154 | 157 | threadWaitReadSTM :: Fd -> IO (STM.STM (), IO ())
|
| 155 | 158 | threadWaitReadSTM fd
|
| 156 | 159 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 157 | - | threaded = Event.threadWaitReadSTM fd
|
|
| 160 | + | iomgrInLib = Event.threadWaitReadSTM fd
|
|
| 158 | 161 | #endif
|
| 159 | - | otherwise = do
|
|
| 162 | + | otherwise = do
|
|
| 160 | 163 | m <- STM.newTVarIO False
|
| 161 | 164 | t <- Sync.forkIO $ do
|
| 162 | 165 | threadWaitRead fd
|
| ... | ... | @@ -173,9 +176,9 @@ threadWaitReadSTM fd |
| 173 | 176 | threadWaitWriteSTM :: Fd -> IO (STM.STM (), IO ())
|
| 174 | 177 | threadWaitWriteSTM fd
|
| 175 | 178 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 176 | - | threaded = Event.threadWaitWriteSTM fd
|
|
| 179 | + | iomgrInLib = Event.threadWaitWriteSTM fd
|
|
| 177 | 180 | #endif
|
| 178 | - | otherwise = do
|
|
| 181 | + | otherwise = do
|
|
| 179 | 182 | m <- STM.newTVarIO False
|
| 180 | 183 | t <- Sync.forkIO $ do
|
| 181 | 184 | threadWaitWrite fd
|
| ... | ... | @@ -206,9 +209,9 @@ closeFdWith :: (Fd -> IO ()) -- ^ Low-level action that performs the real close. |
| 206 | 209 | -> IO ()
|
| 207 | 210 | closeFdWith close fd
|
| 208 | 211 | #if !defined(mingw32_HOST_OS) && !defined(javascript_HOST_ARCH)
|
| 209 | - | threaded = Event.closeFdWith close fd
|
|
| 212 | + | iomgrInLib = Event.closeFdWith close fd
|
|
| 210 | 213 | #endif
|
| 211 | - | otherwise = close fd
|
|
| 214 | + | otherwise = close fd
|
|
| 212 | 215 | |
| 213 | 216 | -- | Suspends the current thread for a given number of microseconds
|
| 214 | 217 | -- (GHC only).
|
| ... | ... | @@ -223,12 +226,11 @@ closeFdWith close fd |
| 223 | 226 | threadDelay :: Int -> IO ()
|
| 224 | 227 | threadDelay time
|
| 225 | 228 | #if defined(mingw32_HOST_OS)
|
| 226 | - | isWindowsNativeIO = Windows.threadDelay time
|
|
| 227 | - | threaded = Windows.threadDelay time
|
|
| 229 | + | iomgrInLib = Windows.threadDelay time
|
|
| 228 | 230 | #elif defined(wasm32_HOST_ARCH)
|
| 229 | 231 | | Wasm.isJSFFIUsed = Wasm.threadDelay time
|
| 230 | 232 | #elif !defined(javascript_HOST_ARCH)
|
| 231 | - | threaded = Event.threadDelay time
|
|
| 233 | + | iomgrInLib = Event.threadDelay time
|
|
| 232 | 234 | #endif
|
| 233 | 235 | | otherwise = IO $ \s ->
|
| 234 | 236 | case time of { I# time# ->
|
| ... | ... | @@ -245,17 +247,12 @@ threadDelay time |
| 245 | 247 | registerDelay :: Int -> IO (TVar Bool)
|
| 246 | 248 | registerDelay _usecs
|
| 247 | 249 | #if defined(mingw32_HOST_OS)
|
| 248 | - | isWindowsNativeIO = Windows.registerDelay _usecs
|
|
| 249 | - | threaded = Windows.registerDelay _usecs
|
|
| 250 | + | iomgrInLib = Windows.registerDelay _usecs
|
|
| 250 | 251 | #elif !defined(javascript_HOST_ARCH)
|
| 251 | - | threaded = Event.registerDelay _usecs
|
|
| 252 | + | iomgrInLib = Event.registerDelay _usecs
|
|
| 252 | 253 | #endif
|
| 253 | 254 | | otherwise = errorWithoutStackTrace "registerDelay: requires -threaded"
|
| 254 | 255 | |
| 255 | -#if !defined(javascript_HOST_ARCH)
|
|
| 256 | -foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
|
|
| 257 | -#endif
|
|
| 258 | - |
|
| 259 | 256 | |
| 260 | 257 | -- ---------------------------------------------------------------------------
|
| 261 | 258 | -- PrimIOException
|
| ... | ... | @@ -55,6 +55,7 @@ import GHC.Internal.Data.Maybe (Maybe(..)) |
| 55 | 55 | import GHC.Internal.Err (errorWithoutStackTrace)
|
| 56 | 56 | import GHC.Internal.Event.Windows.ConsoleEvent
|
| 57 | 57 | import GHC.Internal.IO (unsafePerformIO)
|
| 58 | +import GHC.Internal.IO.SubSystem (iomgrInLib)
|
|
| 58 | 59 | import GHC.Internal.IORef
|
| 59 | 60 | import GHC.Internal.MVar
|
| 60 | 61 | import GHC.Internal.Num (Num(..))
|
| ... | ... | @@ -120,7 +121,7 @@ asyncWriteBA fd isSock len off bufB = |
| 120 | 121 | --
|
| 121 | 122 | threadDelay :: Int -> IO ()
|
| 122 | 123 | threadDelay time
|
| 123 | - | threaded = waitForDelayEvent time
|
|
| 124 | + | iomgrInLib = waitForDelayEvent time
|
|
| 124 | 125 | | otherwise = IO $ \s ->
|
| 125 | 126 | case time of { I# time# ->
|
| 126 | 127 | case delay# time# s of { s' -> (# s', () #)
|
| ... | ... | @@ -134,11 +135,9 @@ threadDelay time |
| 134 | 135 | --
|
| 135 | 136 | registerDelay :: Int -> IO (TVar Bool)
|
| 136 | 137 | registerDelay usecs
|
| 137 | - | threaded = waitForDelayEventSTM usecs
|
|
| 138 | + | iomgrInLib = waitForDelayEventSTM usecs
|
|
| 138 | 139 | | otherwise = errorWithoutStackTrace "registerDelay: requires -threaded"
|
| 139 | 140 | |
| 140 | -foreign import ccall unsafe "rtsSupportsBoundThreads" threaded :: Bool
|
|
| 141 | - |
|
| 142 | 141 | waitForDelayEvent :: Int -> IO ()
|
| 143 | 142 | waitForDelayEvent usecs = do
|
| 144 | 143 | m <- newEmptyMVar
|
| ... | ... | @@ -185,7 +184,7 @@ foreign import ccall unsafe "getOrSetGHCConcWindowsIOManagerThreadStore" |
| 185 | 184 | |
| 186 | 185 | ensureIOManagerIsRunning :: IO ()
|
| 187 | 186 | ensureIOManagerIsRunning
|
| 188 | - | threaded = startIOManagerThread
|
|
| 187 | + | iomgrInLib = startIOManagerThread
|
|
| 189 | 188 | | otherwise = return ()
|
| 190 | 189 | |
| 191 | 190 | 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
|