| ... |
... |
@@ -223,38 +223,48 @@ threadWaitWriteSTM = threadWaitSTM evtWrite |
|
223
|
223
|
{-# INLINE threadWaitWriteSTM #-}
|
|
224
|
224
|
|
|
225
|
225
|
|
|
226
|
|
--- | Retrieve the system event manager for the capability on which the
|
|
227
|
|
--- calling thread is running.
|
|
228
|
|
---
|
|
229
|
|
--- This function always returns 'Just' the current thread's event manager
|
|
230
|
|
--- when using the threaded RTS and 'Nothing' otherwise.
|
|
231
|
|
-getSystemEventManager :: IO (Maybe EventManager)
|
|
232
|
|
-getSystemEventManager = do
|
|
|
226
|
+getSystemEventManager_ :: IO EventManager
|
|
|
227
|
+getSystemEventManager_ = do
|
|
233
|
228
|
t <- myThreadId
|
|
234
|
229
|
eventManagerArray <- readIORef eventManager
|
|
235
|
230
|
let r = boundsIOArray eventManagerArray
|
|
236
|
231
|
(cap, _) <- threadCapability t
|
|
237
|
|
- -- It is possible that we've just increased the number of capabilities and the
|
|
238
|
|
- -- new EventManager has not yet been constructed by
|
|
239
|
|
- -- 'ioManagerCapabilitiesChanged'. We expect this to happen very rarely.
|
|
240
|
|
- -- T21561 exercises this.
|
|
241
|
|
- -- Two options to proceed:
|
|
242
|
|
- -- 1) return the EventManager for capability 0. This is guaranteed to exist,
|
|
243
|
|
- -- and "shouldn't" cause any correctness issues.
|
|
244
|
|
- -- 2) Busy wait, with or without a call to 'yield'. This can't deadlock,
|
|
245
|
|
- -- because we must be on a brand capability and there must be a call to
|
|
246
|
|
- -- 'ioManagerCapabilitiesChanged' pending.
|
|
|
232
|
+ -- It is possible that either:
|
|
|
233
|
+ -- 1) we've just started the RTS or done forkProcess and the EventManager
|
|
|
234
|
+ -- is still being started concurrently by 'ensureIOManagerIsRunning'.
|
|
|
235
|
+ -- This usually happens once at startup.
|
|
|
236
|
+ -- 2) we've just increased the number of capabilities and the new
|
|
|
237
|
+ -- EventManager is being started concurrently by
|
|
|
238
|
+ -- 'ioManagerCapabilitiesChanged'. We expect this to happen very rarely.
|
|
|
239
|
+ -- T21561 exercises this.
|
|
|
240
|
+ --
|
|
|
241
|
+ -- For both situations we follow the strategy to busy wait, with a call to
|
|
|
242
|
+ -- 'yield'. This can't deadlock, because there must be a call to either
|
|
|
243
|
+ -- 'ensureIOManagerIsRunning' or 'ioManagerCapabilitiesChanged' running.
|
|
247
|
244
|
--
|
|
248
|
|
- -- We take the second option, with the yield, judging it the most robust.
|
|
249
|
245
|
if not (inRange r cap)
|
|
250
|
|
- then yield >> getSystemEventManager
|
|
251
|
|
- else fmap snd `fmap` readIOArray eventManagerArray cap
|
|
|
246
|
+ then yield >> getSystemEventManager_ -- for num caps changed
|
|
|
247
|
+ else do
|
|
|
248
|
+ mem <- readIOArray eventManagerArray cap
|
|
|
249
|
+ case mem of
|
|
|
250
|
+ Just (_, em) -> return em
|
|
|
251
|
+ Nothing
|
|
|
252
|
+ | threaded -> yield >> getSystemEventManager_ -- for startup
|
|
|
253
|
+ | otherwise -> err
|
|
|
254
|
+ where
|
|
|
255
|
+ err = error "GHC.Internal.Event.Thread.getSystemEventManager: the EventManager requires linking against the threaded runtime"
|
|
252
|
256
|
|
|
253
|
|
-getSystemEventManager_ :: IO EventManager
|
|
254
|
|
-getSystemEventManager_ = do
|
|
255
|
|
- Just mgr <- getSystemEventManager
|
|
256
|
|
- return mgr
|
|
257
|
|
-{-# INLINE getSystemEventManager_ #-}
|
|
|
257
|
+
|
|
|
258
|
+-- | Retrieve the system event manager for the capability on which the
|
|
|
259
|
+-- calling thread is running.
|
|
|
260
|
+--
|
|
|
261
|
+-- This function always returns 'Just' the current thread's event
|
|
|
262
|
+-- manager when using the threaded RTS and 'Nothing' otherwise.
|
|
|
263
|
+getSystemEventManager :: IO (Maybe EventManager)
|
|
|
264
|
+getSystemEventManager
|
|
|
265
|
+ | threaded = Just `fmap` getSystemEventManager_
|
|
|
266
|
+ | otherwise = return Nothing
|
|
|
267
|
+{-# INLINE getSystemEventManager #-}
|
|
258
|
268
|
|
|
259
|
269
|
foreign import ccall unsafe "getOrSetSystemEventThreadEventManagerStore"
|
|
260
|
270
|
getOrSetSystemEventThreadEventManagerStore :: Ptr a -> IO (Ptr a)
|
| ... |
... |
@@ -299,8 +309,18 @@ ioManagerLock = unsafePerformIO $ do |
|
299
|
309
|
sharedCAF m getOrSetSystemEventThreadIOManagerThreadStore
|
|
300
|
310
|
|
|
301
|
311
|
getSystemTimerManager :: IO TM.TimerManager
|
|
302
|
|
-getSystemTimerManager =
|
|
303
|
|
- fromMaybe err `fmap` readIORef timerManager
|
|
|
312
|
+getSystemTimerManager = do
|
|
|
313
|
+ mtm <- readIORef timerManager
|
|
|
314
|
+ case mtm of
|
|
|
315
|
+ Just tm -> return tm
|
|
|
316
|
+ Nothing
|
|
|
317
|
+ -- Same logic as in getSystemEventManager: yield and try again.
|
|
|
318
|
+ -- This can't deadlock, because we must be on a brand new
|
|
|
319
|
+ -- capability (either the main cap during startup or a new cap
|
|
|
320
|
+ -- after forkProcess) and there must be a call to
|
|
|
321
|
+ -- 'ensureIOManagerIsRunning' pending.
|
|
|
322
|
+ | threaded -> yield >> getSystemTimerManager
|
|
|
323
|
+ | otherwise -> err
|
|
304
|
324
|
where
|
|
305
|
325
|
err = error "GHC.Internal.Event.Thread.getSystemTimerManager: the TimerManager requires linking against the threaded runtime"
|
|
306
|
326
|
|