Duncan Coutts pushed to branch wip/dcoutts/io-manager-tidy at Glasgow Haskell Compiler / GHC

Commits:

28 changed files:

Changes:

  • libraries/ghc-internal/src/GHC/Internal/Event/Control.hs
    ... ... @@ -39,7 +39,7 @@ import GHC.Internal.Show (Show)
    39 39
     import GHC.Internal.Types (Bool(..), Int, IO)
    
    40 40
     import GHC.Internal.Word (Word8)
    
    41 41
     import GHC.Internal.Foreign.C.Error (throwErrnoIfMinus1_, throwErrno, getErrno)
    
    42
    -import GHC.Internal.Foreign.C.Types (CInt(..), CSize(..))
    
    42
    +import GHC.Internal.Foreign.C.Types (CSize(..))
    
    43 43
     import GHC.Internal.Foreign.ForeignPtr (ForeignPtr, mallocForeignPtrBytes, withForeignPtr)
    
    44 44
     import GHC.Internal.Foreign.Marshal.Alloc (alloca, allocaBytes)
    
    45 45
     import GHC.Internal.Foreign.Marshal.Array (allocaArray)
    
    ... ... @@ -51,7 +51,7 @@ import GHC.Internal.System.Posix.Types (Fd)
    51 51
     
    
    52 52
     #if defined(HAVE_EVENTFD)
    
    53 53
     import GHC.Internal.Foreign.C.Error (throwErrnoIfMinus1, eBADF)
    
    54
    -import GHC.Internal.Foreign.C.Types (CULLong(..))
    
    54
    +import GHC.Internal.Foreign.C.Types (CInt(..), CULLong(..))
    
    55 55
     #else
    
    56 56
     import GHC.Internal.Foreign.C.Error (eAGAIN, eWOULDBLOCK, eBADF)
    
    57 57
     #endif
    
    ... ... @@ -78,7 +78,10 @@ data Control = W {
    78 78
         , wakeupReadFd   :: {-# UNPACK #-} !Fd
    
    79 79
         , wakeupWriteFd  :: {-# UNPACK #-} !Fd
    
    80 80
     #endif
    
    81
    -    , didRegisterWakeupFd :: !Bool
    
    81
    +    , didRegisterWakeupFd :: !Bool -- ^ Now redundant. Always False.
    
    82
    +      --TODO: remove ^^ this redundant field.
    
    83
    +      -- Technically, removing this is an API change to base. Sigh.
    
    84
    +
    
    82 85
           -- | Have this Control's fds been cleaned up?
    
    83 86
         , controlIsDead  :: !(IORef Bool)
    
    84 87
         }
    
    ... ... @@ -91,8 +94,8 @@ wakeupReadFd = controlEventFd
    91 94
     
    
    92 95
     -- | Create the structure (usually a pipe) used for waking up the IO
    
    93 96
     -- manager thread from another thread.
    
    94
    -newControl :: Bool -> IO Control
    
    95
    -newControl shouldRegister = allocaArray 2 $ \fds -> do
    
    97
    +newControl :: IO Control
    
    98
    +newControl = allocaArray 2 $ \fds -> do
    
    96 99
       let createPipe = do
    
    97 100
             throwErrnoIfMinus1_ "pipe" $ c_pipe fds
    
    98 101
             rd <- peekElemOff fds 0
    
    ... ... @@ -108,10 +111,8 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do
    108 111
       ev <- throwErrnoIfMinus1 "eventfd" $ c_eventfd 0 0
    
    109 112
       setNonBlockingFD ev True
    
    110 113
       setCloseOnExec ev
    
    111
    -  when shouldRegister $ c_setIOManagerWakeupFd ev
    
    112 114
     #else
    
    113 115
       (wake_rd, wake_wr) <- createPipe
    
    114
    -  when shouldRegister $ c_setIOManagerWakeupFd wake_wr
    
    115 116
     #endif
    
    116 117
       isDead <- newIORef False
    
    117 118
       return W { controlReadFd  = fromIntegral ctrl_rd
    
    ... ... @@ -122,25 +123,16 @@ newControl shouldRegister = allocaArray 2 $ \fds -> do
    122 123
                , wakeupReadFd   = fromIntegral wake_rd
    
    123 124
                , wakeupWriteFd  = fromIntegral wake_wr
    
    124 125
     #endif
    
    125
    -           , didRegisterWakeupFd = shouldRegister
    
    126
    +           , didRegisterWakeupFd = False
    
    126 127
                , controlIsDead  = isDead
    
    127 128
                }
    
    128 129
     
    
    129 130
     -- | Close the control structure used by the IO manager thread.
    
    130
    --- N.B. If this Control is the Control whose wakeup file was registered with
    
    131
    --- the RTS, then *BEFORE* the wakeup file is closed, we must call
    
    132
    --- c_setIOManagerWakeupFd (-1), so that the RTS does not try to use the wakeup
    
    133
    --- file after it has been closed.
    
    134
    ---
    
    135
    --- Note, however, that even if we do the above, this function is still racy
    
    136
    --- since we do not synchronize between here and ioManagerWakeup.
    
    137
    --- ioManagerWakeup ignores failures that arise from this case.
    
    138 131
     closeControl :: Control -> IO ()
    
    139 132
     closeControl w = do
    
    140 133
       _ <- atomicSwapIORef (controlIsDead w) True
    
    141 134
       _ <- c_close . fromIntegral . controlReadFd $ w
    
    142 135
       _ <- c_close . fromIntegral . controlWriteFd $ w
    
    143
    -  when (didRegisterWakeupFd w) $ c_setIOManagerWakeupFd (-1)
    
    144 136
     #if defined(HAVE_EVENTFD)
    
    145 137
       _ <- c_close . fromIntegral . controlEventFd $ w
    
    146 138
     #else
    
    ... ... @@ -248,11 +240,3 @@ foreign import ccall unsafe "sys/eventfd.h eventfd"
    248 240
     foreign import ccall unsafe "sys/eventfd.h eventfd_write"
    
    249 241
        c_eventfd_write :: CInt -> CULLong -> IO CInt
    
    250 242
     #endif
    251
    -
    
    252
    -#if defined(wasm32_HOST_ARCH)
    
    253
    -c_setIOManagerWakeupFd :: CInt -> IO ()
    
    254
    -c_setIOManagerWakeupFd _ = return ()
    
    255
    -#else
    
    256
    -foreign import ccall unsafe "setIOManagerWakeupFd"
    
    257
    -   c_setIOManagerWakeupFd :: CInt -> IO ()
    
    258
    -#endif

  • libraries/ghc-internal/src/GHC/Internal/Event/Manager.hs
    ... ... @@ -194,7 +194,7 @@ newWith :: Backend -> IO EventManager
    194 194
     newWith be = do
    
    195 195
       iofds <- fmap (listArray (0, callbackArraySize-1)) $
    
    196 196
                replicateM callbackArraySize (newMVar =<< IT.new 8)
    
    197
    -  ctrl <- newControl False
    
    197
    +  ctrl <- newControl
    
    198 198
       state <- newIORef Created
    
    199 199
       us <- newSource
    
    200 200
       _ <- mkWeakIORef state $ do
    

  • libraries/ghc-internal/src/GHC/Internal/Event/TimerManager.hs
    ... ... @@ -126,7 +126,7 @@ new = newWith =<< newDefaultBackend
    126 126
     newWith :: Backend -> IO TimerManager
    
    127 127
     newWith be = do
    
    128 128
       timeouts <- newIORef Q.empty
    
    129
    -  ctrl <- newControl True
    
    129
    +  ctrl <- newControl
    
    130 130
       state <- newIORef Created
    
    131 131
       us <- newSource
    
    132 132
       _ <- mkWeakIORef state $ do
    

  • rts/Capability.c
    ... ... @@ -1293,6 +1293,8 @@ shutdownCapabilities(Task *task, bool safe)
    1293 1293
     static void
    
    1294 1294
     freeCapability (Capability *cap)
    
    1295 1295
     {
    
    1296
    +    freeCapabilityIOManager(cap->iomgr);
    
    1297
    +    stgFree(cap->iomgr);
    
    1296 1298
         stgFree(cap->mut_lists);
    
    1297 1299
         stgFree(cap->saved_mut_lists);
    
    1298 1300
         if (cap->current_segments) {
    

  • rts/IOManager.c
    ... ... @@ -39,7 +39,7 @@
    39 39
     #endif
    
    40 40
     
    
    41 41
     #if defined(IOMGR_ENABLED_MIO_POSIX)
    
    42
    -#include "posix/Signals.h"
    
    42
    +#include "posix/MIO.h"
    
    43 43
     #include "Prelude.h"
    
    44 44
     #endif
    
    45 45
     
    
    ... ... @@ -373,11 +373,25 @@ void initCapabilityIOManager(CapIOManager *iomgr)
    373 373
     }
    
    374 374
     
    
    375 375
     
    
    376
    +void freeCapabilityIOManager(CapIOManager *iomgr)
    
    377
    +{
    
    378
    +    switch (iomgr_type) {
    
    379
    +#if defined(IOMGR_ENABLED_POLL)
    
    380
    +        case IO_MANAGER_POLL:
    
    381
    +            freeCapabilityIOManagerPoll(iomgr);
    
    382
    +            break;
    
    383
    +#endif
    
    384
    +        default:
    
    385
    +            break;
    
    386
    +    }
    
    387
    +}
    
    388
    +
    
    389
    +
    
    376 390
     /* Called late in the RTS initialisation
    
    377 391
      */
    
    378
    -void initIOManager(void)
    
    392
    +void startIOManager(void)
    
    379 393
     {
    
    380
    -    debugTrace(DEBUG_iomanager, "initialising %s I/O manager", showIOManager());
    
    394
    +    debugTrace(DEBUG_iomanager, "starting %s I/O manager", showIOManager());
    
    381 395
     
    
    382 396
         switch (iomgr_type) {
    
    383 397
     
    
    ... ... @@ -441,7 +455,7 @@ void initIOManager(void)
    441 455
     /* Called from forkProcess in the child process on the surviving capability.
    
    442 456
      */
    
    443 457
     void
    
    444
    -initIOManagerAfterFork(CapIOManager *iomgr, Capability **pcap)
    
    458
    +restartIOManager(CapIOManager *iomgr, Capability **pcap)
    
    445 459
     {
    
    446 460
     
    
    447 461
         switch (iomgr_type) {
    
    ... ... @@ -541,42 +555,6 @@ exitIOManager(bool wait_threads)
    541 555
         }
    
    542 556
     }
    
    543 557
     
    
    544
    -/* Wakeup hook: called from the scheduler's wakeUpRts (currently only in
    
    545
    - * threaded mode).
    
    546
    - */
    
    547
    -void wakeupIOManager(void)
    
    548
    -{
    
    549
    -    switch (iomgr_type) {
    
    550
    -
    
    551
    -#if defined(IOMGR_ENABLED_MIO_POSIX)
    
    552
    -        case IO_MANAGER_MIO_POSIX:
    
    553
    -            /* MIO Posix implementation in posix/Signals.c */
    
    554
    -            ioManagerWakeup();
    
    555
    -            break;
    
    556
    -#endif
    
    557
    -#if defined(IOMGR_ENABLED_MIO_WIN32)
    
    558
    -        case IO_MANAGER_MIO_WIN32:
    
    559
    -            /* MIO Windows implementation in win32/ThrIOManager.c
    
    560
    -             * Yes, this is shared with the WinIO (threaded) impl.
    
    561
    -             */
    
    562
    -            ioManagerWakeup();
    
    563
    -            break;
    
    564
    -#endif
    
    565
    -#if defined(IOMGR_ENABLED_WINIO)
    
    566
    -        case IO_MANAGER_WINIO:
    
    567
    -#if defined(THREADED_RTS)
    
    568
    -            /* WinIO threaded implementation in win32/ThrIOManager.c
    
    569
    -             * Yes, this is shared with the MIO win32 impl.
    
    570
    -             */
    
    571
    -            ioManagerWakeup();
    
    572
    -#endif
    
    573
    -            break;
    
    574
    -#endif
    
    575
    -        default:
    
    576
    -            break;
    
    577
    -    }
    
    578
    -}
    
    579
    -
    
    580 558
     void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr)
    
    581 559
     {
    
    582 560
         switch (iomgr_type) {
    

  • rts/IOManager.h
    ... ... @@ -243,11 +243,33 @@ CapIOManager *allocCapabilityIOManager(Capability *cap);
    243 243
      */
    
    244 244
     void initCapabilityIOManager(CapIOManager *iomgr);
    
    245 245
     
    
    246
    +/* When shutting down a capability, or after forkProcess, free the resources
    
    247
    + * held by a CapIOManager to put it back into a state in which either it can be
    
    248
    + * re-initialised using initCapabilityIOManager, or the whole structure freed.
    
    249
    + *
    
    250
    + * Note that this does not free the CapIOManager structure itself, just the
    
    251
    + * contents.
    
    252
    + *
    
    253
    + * This is used during capability shutdown, during RTS shutdown. It is not used
    
    254
    + * when reducing the number of capabilities. Capabilities are disabled rather
    
    255
    + * than freed entirely: the I/O manager keeps running but threads that become
    
    256
    + * runnable are migrated away.
    
    257
    + *
    
    258
    + * It is also used after forkProcess.
    
    259
    + */
    
    260
    +void freeCapabilityIOManager(CapIOManager *iomgr);
    
    261
    +
    
    262
    +/* CapIOManager life cycle:
    
    263
    + *
    
    264
    + * alloc -> init -> free -> free struct
    
    265
    + *           ^        |
    
    266
    + *           +--------+
    
    267
    + */
    
    246 268
     
    
    247 269
     /* Init hook: called from hs_init_ghc, very late in the startup after almost
    
    248 270
      * everything else is done.
    
    249 271
      */
    
    250
    -void initIOManager(void);
    
    272
    +void startIOManager(void);
    
    251 273
     
    
    252 274
     
    
    253 275
     /* Init hook: called from forkProcess in the child process on the surviving
    
    ... ... @@ -256,8 +278,8 @@ void initIOManager(void);
    256 278
      * This is synchronous and can run Haskell code, so can change the given cap.
    
    257 279
      * TODO: it would make for a cleaner API here if this were made asynchronous.
    
    258 280
      */
    
    259
    -void initIOManagerAfterFork(CapIOManager *iomgr,
    
    260
    -                /* inout */ Capability  **pcap);
    
    281
    +void restartIOManager(CapIOManager *iomgr,
    
    282
    +          /* inout */ Capability  **pcap);
    
    261 283
     
    
    262 284
     /* TODO: rationalise initIOManager and initIOManagerAfterFork into a single
    
    263 285
              per-capability init function.
    
    ... ... @@ -284,23 +306,6 @@ void stopIOManager(void);
    284 306
     void exitIOManager(bool wait_threads);
    
    285 307
     
    
    286 308
     
    
    287
    -/* Wakeup hook: called from the scheduler's wakeUpRts (currently only in
    
    288
    - * threaded mode).
    
    289
    - *
    
    290
    - * The I/O manager can be blocked waiting on I/O or timers. Sometimes there are
    
    291
    - * other external events where we need to wake up the I/O manager and return
    
    292
    - * to the schedulr.
    
    293
    - *
    
    294
    - * At the moment, all the non-threaded I/O managers will do this automagically
    
    295
    - * since a signal will interrupt any waiting system calls, so at the moment
    
    296
    - * the implementation for the non-threaded I/O managers does nothing.
    
    297
    - *
    
    298
    - * For the I/O managers in threaded mode, this arranges to unblock the I/O
    
    299
    - * manager if it waa blocked waiting.
    
    300
    - */
    
    301
    -void wakeupIOManager(void);
    
    302
    -
    
    303
    -
    
    304 309
     /* GC hook: mark any per-capability GC roots the I/O manager uses.
    
    305 310
      */
    
    306 311
     void markCapabilityIOManager(evac_fn evac, void *user, CapIOManager *iomgr);
    

  • rts/RtsStartup.c
    ... ... @@ -427,7 +427,7 @@ hs_init_ghc(int *argc, char **argv[], RtsConfig rts_config)
    427 427
         }
    
    428 428
     #endif
    
    429 429
     
    
    430
    -    initIOManager();
    
    430
    +    startIOManager();
    
    431 431
     
    
    432 432
         x86_init_fpu();
    
    433 433
     
    

  • rts/RtsSymbols.c
    ... ... @@ -265,7 +265,6 @@ extern char **environ;
    265 265
     #define RTS_USER_SIGNALS_SYMBOLS        \
    
    266 266
        SymI_HasProto(setIOManagerControlFd) \
    
    267 267
        SymI_HasProto(setTimerManagerControlFd) \
    
    268
    -   SymI_HasProto(setIOManagerWakeupFd)  \
    
    269 268
        SymI_HasProto(blockUserSignals)      \
    
    270 269
        SymI_HasProto(unblockUserSignals)
    
    271 270
     #else
    

  • rts/Schedule.c
    ... ... @@ -175,6 +175,11 @@ static void deleteAllThreads (void);
    175 175
     static void deleteThread_(StgTSO *tso);
    
    176 176
     #endif
    
    177 177
     
    
    178
    +#if defined(FORKPROCESS_PRIMOP_SUPPORTED)
    
    179
    +static void truncateRunQueue(Capability *cap);
    
    180
    +#endif
    
    181
    +static StgTSO *popRunQueue (Capability *cap);
    
    182
    +
    
    178 183
     /* ---------------------------------------------------------------------------
    
    179 184
        Main scheduling loop.
    
    180 185
     
    
    ... ... @@ -592,38 +597,6 @@ run_thread:
    592 597
       } /* end of while() */
    
    593 598
     }
    
    594 599
     
    
    595
    -/* -----------------------------------------------------------------------------
    
    596
    - * Run queue operations
    
    597
    - * -------------------------------------------------------------------------- */
    
    598
    -
    
    599
    -static void
    
    600
    -removeFromRunQueue (Capability *cap, StgTSO *tso)
    
    601
    -{
    
    602
    -    if (tso->block_info.prev == END_TSO_QUEUE) {
    
    603
    -        ASSERT(cap->run_queue_hd == tso);
    
    604
    -        cap->run_queue_hd = tso->_link;
    
    605
    -    } else {
    
    606
    -        setTSOLink(cap, tso->block_info.prev, tso->_link);
    
    607
    -    }
    
    608
    -    if (tso->_link == END_TSO_QUEUE) {
    
    609
    -        ASSERT(cap->run_queue_tl == tso);
    
    610
    -        cap->run_queue_tl = tso->block_info.prev;
    
    611
    -    } else {
    
    612
    -        setTSOPrev(cap, tso->_link, tso->block_info.prev);
    
    613
    -    }
    
    614
    -    tso->_link = tso->block_info.prev = END_TSO_QUEUE;
    
    615
    -    cap->n_run_queue--;
    
    616
    -
    
    617
    -    IF_DEBUG(sanity, checkRunQueue(cap));
    
    618
    -}
    
    619
    -
    
    620
    -void
    
    621
    -promoteInRunQueue (Capability *cap, StgTSO *tso)
    
    622
    -{
    
    623
    -    removeFromRunQueue(cap, tso);
    
    624
    -    pushOnRunQueue(cap, tso);
    
    625
    -}
    
    626
    -
    
    627 600
     /* -----------------------------------------------------------------------------
    
    628 601
      * scheduleFindWork()
    
    629 602
      *
    
    ... ... @@ -2199,7 +2172,15 @@ forkProcess(HsStablePtr *entry
    2199 2172
                 // bound threads for which the corresponding Task does not
    
    2200 2173
                 // exist.
    
    2201 2174
                 truncateRunQueue(cap);
    
    2202
    -            cap->n_run_queue = 0;
    
    2175
    +
    
    2176
    +            // Reset and re-initialise the capability's I/O manager,
    
    2177
    +            // to get the I/O manager ready again.
    
    2178
    +            //
    
    2179
    +            // Any threads waiting on I/O or timers should have been
    
    2180
    +            // removed from I/O manager queues by deleteThread_ above.
    
    2181
    +            // TODO: but we could assert that here.
    
    2182
    +            freeCapabilityIOManager(cap->iomgr);
    
    2183
    +            initCapabilityIOManager(cap->iomgr);
    
    2203 2184
     
    
    2204 2185
                 // Any suspended C-calling Tasks are no more, their OS threads
    
    2205 2186
                 // don't exist now:
    
    ... ... @@ -2216,7 +2197,7 @@ forkProcess(HsStablePtr *entry
    2216 2197
                 cap->n_returning_tasks = 0;
    
    2217 2198
     #endif
    
    2218 2199
     
    
    2219
    -            // Release all caps except 0, we'll use that for starting
    
    2200
    +            // Release all caps except 0, we'll use that for restarting
    
    2220 2201
                 // the IO manager and running the client action below.
    
    2221 2202
                 if (cap->no != 0) {
    
    2222 2203
                     task->cap = cap;
    
    ... ... @@ -2240,7 +2221,7 @@ forkProcess(HsStablePtr *entry
    2240 2221
             // like startup event, capabilities, process info etc
    
    2241 2222
             traceTaskCreate(task, cap);
    
    2242 2223
     
    
    2243
    -        initIOManagerAfterFork(cap->iomgr, &cap);
    
    2224
    +        restartIOManager(cap->iomgr, &cap);
    
    2244 2225
     
    
    2245 2226
             // start timer after the IOManager is initialized
    
    2246 2227
             // (the idle GC may wake up the IOManager)
    
    ... ... @@ -2339,6 +2320,10 @@ setNumCapabilities (uint32_t new_n_capabilities USED_IF_THREADS)
    2339 2320
             // the capability; we don't have to worry about GC data
    
    2340 2321
             // structures, the nursery, etc.
    
    2341 2322
             //
    
    2323
    +        // This approach also handles threads blocked on I/O. Such threads
    
    2324
    +        // remain blocked, and when I/O completes and threads become runnable
    
    2325
    +        // then they are migrated away.
    
    2326
    +        //
    
    2342 2327
             for (n = new_n_capabilities; n < enabled_capabilities; n++) {
    
    2343 2328
                 getCapability(n)->disabled = true;
    
    2344 2329
                 traceCapDisable(getCapability(n));
    
    ... ... @@ -3016,7 +3001,7 @@ pushOnRunQueue (Capability *cap, StgTSO *tso)
    3016 3001
         cap->n_run_queue++;
    
    3017 3002
     }
    
    3018 3003
     
    
    3019
    -StgTSO *popRunQueue (Capability *cap)
    
    3004
    +static StgTSO *popRunQueue (Capability *cap)
    
    3020 3005
     {
    
    3021 3006
         ASSERT(cap->n_run_queue > 0);
    
    3022 3007
         StgTSO *t = cap->run_queue_hd;
    
    ... ... @@ -3036,6 +3021,45 @@ StgTSO *popRunQueue (Capability *cap)
    3036 3021
         return t;
    
    3037 3022
     }
    
    3038 3023
     
    
    3024
    +#if defined(FORKPROCESS_PRIMOP_SUPPORTED)
    
    3025
    +static void truncateRunQueue(Capability *cap)
    
    3026
    +{
    
    3027
    +    // Can only be called by the task owning the capability.
    
    3028
    +    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_hd, "truncateRunQueue");
    
    3029
    +    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_tl, "truncateRunQueue");
    
    3030
    +    TSAN_ANNOTATE_BENIGN_RACE(&cap->n_run_queue, "truncateRunQueue");
    
    3031
    +    cap->run_queue_hd = END_TSO_QUEUE;
    
    3032
    +    cap->run_queue_tl = END_TSO_QUEUE;
    
    3033
    +    cap->n_run_queue = 0;
    
    3034
    +}
    
    3035
    +#endif
    
    3036
    +
    
    3037
    +static void removeFromRunQueue (Capability *cap, StgTSO *tso)
    
    3038
    +{
    
    3039
    +    if (tso->block_info.prev == END_TSO_QUEUE) {
    
    3040
    +        ASSERT(cap->run_queue_hd == tso);
    
    3041
    +        cap->run_queue_hd = tso->_link;
    
    3042
    +    } else {
    
    3043
    +        setTSOLink(cap, tso->block_info.prev, tso->_link);
    
    3044
    +    }
    
    3045
    +    if (tso->_link == END_TSO_QUEUE) {
    
    3046
    +        ASSERT(cap->run_queue_tl == tso);
    
    3047
    +        cap->run_queue_tl = tso->block_info.prev;
    
    3048
    +    } else {
    
    3049
    +        setTSOPrev(cap, tso->_link, tso->block_info.prev);
    
    3050
    +    }
    
    3051
    +    tso->_link = tso->block_info.prev = END_TSO_QUEUE;
    
    3052
    +    cap->n_run_queue--;
    
    3053
    +
    
    3054
    +    IF_DEBUG(sanity, checkRunQueue(cap));
    
    3055
    +}
    
    3056
    +
    
    3057
    +void promoteInRunQueue (Capability *cap, StgTSO *tso)
    
    3058
    +{
    
    3059
    +    removeFromRunQueue(cap, tso);
    
    3060
    +    pushOnRunQueue(cap, tso);
    
    3061
    +}
    
    3062
    +
    
    3039 3063
     
    
    3040 3064
     /* -----------------------------------------------------------------------------
    
    3041 3065
        raiseExceptionHelper
    

  • rts/Schedule.h
    ... ... @@ -164,10 +164,6 @@ void appendToRunQueue (Capability *cap, StgTSO *tso);
    164 164
      */
    
    165 165
     void pushOnRunQueue (Capability *cap, StgTSO *tso);
    
    166 166
     
    
    167
    -/* Pop the first thread off the runnable queue.
    
    168
    - */
    
    169
    -StgTSO *popRunQueue (Capability *cap);
    
    170
    -
    
    171 167
     INLINE_HEADER StgTSO *
    
    172 168
     peekRunQueue (Capability *cap)
    
    173 169
     {
    
    ... ... @@ -184,18 +180,6 @@ emptyRunQueue(Capability *cap)
    184 180
         return cap->n_run_queue == 0;
    
    185 181
     }
    
    186 182
     
    
    187
    -INLINE_HEADER void
    
    188
    -truncateRunQueue(Capability *cap)
    
    189
    -{
    
    190
    -    // Can only be called by the task owning the capability.
    
    191
    -    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_hd, "truncateRunQueue");
    
    192
    -    TSAN_ANNOTATE_BENIGN_RACE(&cap->run_queue_tl, "truncateRunQueue");
    
    193
    -    TSAN_ANNOTATE_BENIGN_RACE(&cap->n_run_queue, "truncateRunQueue");
    
    194
    -    cap->run_queue_hd = END_TSO_QUEUE;
    
    195
    -    cap->run_queue_tl = END_TSO_QUEUE;
    
    196
    -    cap->n_run_queue = 0;
    
    197
    -}
    
    198
    -
    
    199 183
     #endif /* !IN_STG_CODE */
    
    200 184
     
    
    201 185
     #include "EndPrivate.h"

  • rts/include/rts/IOInterface.h
    ... ... @@ -33,7 +33,6 @@ void ioManagerFinished (void);
    33 33
     
    
    34 34
     void     setIOManagerControlFd   (uint32_t cap_no, int fd);
    
    35 35
     void     setTimerManagerControlFd(int fd);
    
    36
    -void     setIOManagerWakeupFd   (int fd);
    
    37 36
     
    
    38 37
     #endif
    
    39 38
     

  • rts/include/rts/storage/Closures.h
    ... ... @@ -829,11 +829,11 @@ typedef struct {
    829 829
           // here due to portability concerns for this C bitfield.
    
    830 830
         uint16_t notify_type: 2;
    
    831 831
     
    
    832
    -      // The outcome:
    
    833
    -      // 0: still in-progress, no detail
    
    834
    -      // 1: success, result field contains the result code
    
    835
    -      // 2: failed, error field contains the error code
    
    836
    -      // 3: cancelled, no detail
    
    832
    +      // The outcome (see enum IOOpOutcome):
    
    833
    +      // 0: IOOpOutcomeInFlight: still in-progress, no further detail.
    
    834
    +      // 1: IOOpOutcomeSuccess: result field contains the result code.
    
    835
    +      // 2: IOOpOutcomeFailed: error field contains the error code.
    
    836
    +      // 3: IOOpOutcomeCancelled: cancelled, no further detail.
    
    837 837
         uint16_t outcome: 2;
    
    838 838
     
    
    839 839
           // 12 bits going spare!
    

  • rts/include/rts/storage/TSO.h
    ... ... @@ -48,14 +48,16 @@ typedef union {
    48 48
       StgAsyncIOOp *aiop;
    
    49 49
       StgTimeoutQueue *timeout;
    
    50 50
     #if defined(mingw32_HOST_OS)
    
    51
    +    // Only used by the Legacy Win32 I/O manager: the async request id for the
    
    52
    +    // operation.
    
    51 53
       StgWord async_reqID;
    
    52 54
     #endif
    
    53 55
     #if !defined(THREADED_RTS)
    
    54 56
       StgWord target;
    
    55
    -    // Only for the non-threaded RTS: the target time for a thread
    
    56
    -    // blocked in threadDelay, in units of 1ms.  This is a
    
    57
    -    // compromise: we don't want to take up much space in the TSO.  If
    
    58
    -    // you want better resolution for threadDelay, use -threaded.
    
    57
    +    // Only for the legacy select I/O manager: the target time for a thread
    
    58
    +    // blocked in threadDelay, in units of 1ms.  This is a compromise: we don't
    
    59
    +    // want to take up much space in the TSO.  If you want better resolution
    
    60
    +    // for threadDelay, use *literally any* other I/O manager.
    
    59 61
     #endif
    
    60 62
     } StgTSOBlockInfo;
    
    61 63
     
    

  • rts/posix/MIO.c
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 1998-2005
    
    4
    + *
    
    5
    + * The MIO I/O manager RTS stub.
    
    6
    + *
    
    7
    + * This I/O manager lives primarily in Haskell in the ghc-internal package.
    
    8
    + * This file implementes the required subset of the RTS's internal I/O manager
    
    9
    + * API.
    
    10
    + *
    
    11
    + * ---------------------------------------------------------------------------*/
    
    12
    +
    
    13
    +#include "rts/PosixSource.h"
    
    14
    +#include "Rts.h"
    
    15
    +
    
    16
    +#include "Schedule.h"
    
    17
    +#include "RtsUtils.h"
    
    18
    +#include "Prelude.h"
    
    19
    +#include "ThreadLabels.h"
    
    20
    +
    
    21
    +#include "MIO.h"
    
    22
    +#include "IOManager.h"
    
    23
    +#include "IOManagerInternals.h"
    
    24
    +
    
    25
    +#if defined(HAVE_ERRNO_H)
    
    26
    +# include <errno.h>
    
    27
    +#endif
    
    28
    +
    
    29
    +#include <stdlib.h>
    
    30
    +#include <unistd.h>
    
    31
    +
    
    32
    +// Here's the pipe into which we will send our signals
    
    33
    +static int timer_manager_control_wr_fd = -1;
    
    34
    +// TODO: Eliminate these globals. Put then into the CapIOManager, but the
    
    35
    +// problem is these are shared across all caps, not per cap.
    
    36
    +
    
    37
    +#define IO_MANAGER_DIE    0xfe
    
    38
    +
    
    39
    +void setTimerManagerControlFd(int fd) {
    
    40
    +    RELAXED_STORE(&timer_manager_control_wr_fd, fd);
    
    41
    +}
    
    42
    +
    
    43
    +#if defined(THREADED_RTS)
    
    44
    +void timerManagerNotifySignal(int sig, siginfo_t *info)
    
    45
    +{
    
    46
    +    StgWord8 buf[sizeof(siginfo_t) + 1];
    
    47
    +    int r;
    
    48
    +
    
    49
    +    buf[0] = sig;
    
    50
    +    if (info == NULL) {
    
    51
    +        // info may be NULL on Solaris (see #3790)
    
    52
    +        memset(buf+1, 0, sizeof(siginfo_t));
    
    53
    +    } else {
    
    54
    +        memcpy(buf+1, info, sizeof(siginfo_t));
    
    55
    +    }
    
    56
    +
    
    57
    +    int timer_control_fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    58
    +    if (0 <= timer_control_fd)
    
    59
    +    {
    
    60
    +        r = write(timer_control_fd, buf, sizeof(siginfo_t)+1);
    
    61
    +        if (r == -1 && errno == EAGAIN) {
    
    62
    +            errorBelch("lost signal due to full pipe: %d\n", sig);
    
    63
    +        }
    
    64
    +    }
    
    65
    +
    
    66
    +    // If the IO manager hasn't told us what the FD of the write end
    
    67
    +    // of its pipe is, there's not much we can do here, so just ignore
    
    68
    +    // the signal..
    
    69
    +}
    
    70
    +#endif
    
    71
    +
    
    72
    +
    
    73
    +#if defined(THREADED_RTS)
    
    74
    +void
    
    75
    +ioManagerDie (void)
    
    76
    +{
    
    77
    +    StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
    
    78
    +    uint32_t i;
    
    79
    +    int r;
    
    80
    +
    
    81
    +    {
    
    82
    +        // Shut down timer manager
    
    83
    +        const int fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    84
    +        if (0 <= fd) {
    
    85
    +            r = write(fd, &byte, 1);
    
    86
    +            if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    87
    +            RELAXED_STORE(&timer_manager_control_wr_fd, -1);
    
    88
    +        }
    
    89
    +    }
    
    90
    +
    
    91
    +    {
    
    92
    +        // Shut down IO managers
    
    93
    +        for (i=0; i < getNumCapabilities(); i++) {
    
    94
    +            const int fd = RELAXED_LOAD(&getCapability(i)->iomgr->control_fd);
    
    95
    +            if (0 <= fd) {
    
    96
    +                r = write(fd, &byte, 1);
    
    97
    +                if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    98
    +                RELAXED_STORE(&getCapability(i)->iomgr->control_fd, -1);
    
    99
    +            }
    
    100
    +        }
    
    101
    +    }
    
    102
    +}
    
    103
    +
    
    104
    +void
    
    105
    +ioManagerStartCap (Capability **cap)
    
    106
    +{
    
    107
    +    rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL);
    
    108
    +}
    
    109
    +
    
    110
    +void
    
    111
    +ioManagerStart (void)
    
    112
    +{
    
    113
    +    // Make sure the IO manager thread is running
    
    114
    +    Capability *cap;
    
    115
    +    if (SEQ_CST_LOAD(&timer_manager_control_wr_fd) < 0) {
    
    116
    +        cap = rts_lock();
    
    117
    +        ioManagerStartCap(&cap);
    
    118
    +        rts_unlock(cap);
    
    119
    +    }
    
    120
    +}
    
    121
    +#endif
    
    122
    +

  • rts/posix/MIO.h
    1
    +/* -----------------------------------------------------------------------------
    
    2
    + *
    
    3
    + * (c) The GHC Team, 1998-2005
    
    4
    + *
    
    5
    + * Signal processing / handling.
    
    6
    + *
    
    7
    + * ---------------------------------------------------------------------------*/
    
    8
    +
    
    9
    +#pragma once
    
    10
    +
    
    11
    +#include "IOManager.h"
    
    12
    +
    
    13
    +#if defined(HAVE_SIGNAL_H)
    
    14
    +# include <signal.h>
    
    15
    +#endif
    
    16
    +
    
    17
    +#include "BeginPrivate.h"
    
    18
    +
    
    19
    +/* Communicating with the IO manager thread (see GHC.Conc).
    
    20
    + */
    
    21
    +#if defined(THREADED_RTS)
    
    22
    +void ioManagerDie (void);
    
    23
    +void ioManagerStart (void);
    
    24
    +void ioManagerStartCap (/* inout */ Capability **cap);
    
    25
    +
    
    26
    +void timerManagerNotifySignal(int sig, siginfo_t *info);
    
    27
    +#endif
    
    28
    +
    
    29
    +#include "EndPrivate.h"

  • rts/posix/Poll.c
    ... ... @@ -134,6 +134,14 @@ void initCapabilityIOManagerPoll(CapIOManager *iomgr)
    134 134
     }
    
    135 135
     
    
    136 136
     
    
    137
    +void freeCapabilityIOManagerPoll(CapIOManager *iomgr)
    
    138
    +{
    
    139
    +    if (iomgr->aiop_poll_table) {
    
    140
    +        stgFree(iomgr->aiop_poll_table);
    
    141
    +    }
    
    142
    +}
    
    143
    +
    
    144
    +
    
    137 145
     /* Used to implement syncIOWaitReady.
    
    138 146
      * Result is true on success, or false on allocation failure. */
    
    139 147
     bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
    
    ... ... @@ -194,6 +202,13 @@ void syncIOCancelPoll(CapIOManager *iomgr, StgTSO *tso)
    194 202
          * status, as that is done by removeFromQueues (in the throwTo* functions).
    
    195 203
          */
    
    196 204
         tso->block_info.closure = (StgClosure *)END_TSO_QUEUE;
    
    205
    +
    
    206
    +    /* We are in the TSO case, where the aiop was only reachable from the TSO
    
    207
    +     * itself, and thus it is now no longer be reachable at all.
    
    208
    +     */
    
    209
    +    IF_NONMOVING_WRITE_BARRIER_ENABLED {
    
    210
    +        updateRemembSetPushClosure(iomgr->cap, (StgClosure *)aiop);
    
    211
    +    }
    
    197 212
     }
    
    198 213
     
    
    199 214
     
    
    ... ... @@ -251,7 +266,6 @@ static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop)
    251 266
                     raiseAsync(iomgr->cap, tso,
    
    252 267
                                (StgClosure *)blockedOnBadFD_closure,
    
    253 268
                                false, NULL);
    
    254
    -                break;
    
    255 269
                 } else {
    
    256 270
                     /* We should be guaranteed that the tso is still on the same
    
    257 271
                      * cap because the tso was not on the run queue of any cap and
    
    ... ... @@ -262,6 +276,12 @@ static void notifyIOCompletion(CapIOManager *iomgr, StgAsyncIOOp *aiop)
    262 276
                     tso->_link       = END_TSO_QUEUE;
    
    263 277
                     pushOnRunQueue(iomgr->cap, tso);
    
    264 278
                 }
    
    279
    +            /* For the TSO case, the aiop was only reachable from the TSO
    
    280
    +             * itself, and thus it is now no longer be reachable at all.
    
    281
    +             */
    
    282
    +            IF_NONMOVING_WRITE_BARRIER_ENABLED {
    
    283
    +                updateRemembSetPushClosure(iomgr->cap, (StgClosure *)aiop);
    
    284
    +            }
    
    265 285
                 break;
    
    266 286
             }
    
    267 287
             case NotifyMVar:
    
    ... ... @@ -455,6 +475,9 @@ void awaitCompletedTimeoutsOrIOPoll(CapIOManager *iomgr)
    455 475
                 int ncompletions = res;
    
    456 476
                 ASSERT(ncompletions <= (int)nfds);
    
    457 477
                 processIOCompletions(iomgr, ncompletions);
    
    478
    +            // FIXME: do we also need to check for timeout completions now?
    
    479
    +            // we have a non-empty queue, but if !wait then we have also moved
    
    480
    +            // on and so we sould check for timeouts.
    
    458 481
     
    
    459 482
             } else if (errno == EINTR) {
    
    460 483
                 /* We got interrupted by a signal. In the non-threaded RTS, if the
    

  • rts/posix/Poll.h
    ... ... @@ -17,6 +17,7 @@
    17 17
     #if defined(IOMGR_ENABLED_POLL)
    
    18 18
     
    
    19 19
     void initCapabilityIOManagerPoll(CapIOManager *iomgr);
    
    20
    +void freeCapabilityIOManagerPoll(CapIOManager *iomgr);
    
    20 21
     
    
    21 22
     /* Synchronous I/O and timer operations */
    
    22 23
     bool syncIOWaitReadyPoll(CapIOManager *iomgr, StgTSO *tso,
    

  • rts/posix/Signals.c
    ... ... @@ -9,21 +9,13 @@
    9 9
     #include "rts/PosixSource.h"
    
    10 10
     #include "Rts.h"
    
    11 11
     
    
    12
    -#include "Schedule.h"
    
    13 12
     #include "RtsSignals.h"
    
    14
    -#include "Signals.h"
    
    15
    -#include "IOManager.h"
    
    16 13
     #include "RtsUtils.h"
    
    14
    +#include "Schedule.h"
    
    17 15
     #include "Prelude.h"
    
    18
    -#include "Ticker.h"
    
    19 16
     #include "ThreadLabels.h"
    
    20 17
     #include "Libdw.h"
    
    21
    -
    
    22
    -/* TODO: eliminate this include. This file should be about signals, not be
    
    23
    - * part of an I/O manager implementation. The code here that are really part
    
    24
    - * of an I/O manager should be moved into an appropriate I/O manager impl.
    
    25
    - */
    
    26
    -#include "IOManagerInternals.h"
    
    18
    +#include "MIO.h"
    
    27 19
     
    
    28 20
     #if defined(alpha_HOST_ARCH)
    
    29 21
     # if defined(linux_HOST_OS)
    
    ... ... @@ -41,19 +33,10 @@
    41 33
     # include <signal.h>
    
    42 34
     #endif
    
    43 35
     
    
    44
    -#if defined(HAVE_ERRNO_H)
    
    45
    -# include <errno.h>
    
    46
    -#endif
    
    47
    -
    
    48
    -#if defined(HAVE_EVENTFD_H)
    
    49
    -# include <sys/eventfd.h>
    
    50
    -#endif
    
    51
    -
    
    52 36
     #if defined(HAVE_TERMIOS_H)
    
    53 37
     #include <termios.h>
    
    54 38
     #endif
    
    55 39
     
    
    56
    -#include <stdlib.h>
    
    57 40
     #include <string.h>
    
    58 41
     
    
    59 42
     /* This curious flag is provided for the benefit of the Haskell binding
    
    ... ... @@ -134,110 +117,6 @@ more_handlers(int sig)
    134 117
         nHandlers = sig + 1;
    
    135 118
     }
    
    136 119
     
    
    137
    -// Here's the pipe into which we will send our signals
    
    138
    -static int io_manager_wakeup_fd = -1;
    
    139
    -static int timer_manager_control_wr_fd = -1;
    
    140
    -
    
    141
    -#define IO_MANAGER_WAKEUP 0xff
    
    142
    -#define IO_MANAGER_DIE    0xfe
    
    143
    -#define IO_MANAGER_SYNC   0xfd
    
    144
    -
    
    145
    -void setTimerManagerControlFd(int fd) {
    
    146
    -    RELAXED_STORE(&timer_manager_control_wr_fd, fd);
    
    147
    -}
    
    148
    -
    
    149
    -void
    
    150
    -setIOManagerWakeupFd (int fd)
    
    151
    -{
    
    152
    -    // only called when THREADED_RTS, but unconditionally
    
    153
    -    // compiled here because GHC.Event.Control depends on it.
    
    154
    -    SEQ_CST_STORE(&io_manager_wakeup_fd, fd);
    
    155
    -}
    
    156
    -
    
    157
    -/* -----------------------------------------------------------------------------
    
    158
    - * Wake up at least one IO or timer manager HS thread.
    
    159
    - * -------------------------------------------------------------------------- */
    
    160
    -void
    
    161
    -ioManagerWakeup (void)
    
    162
    -{
    
    163
    -    int r;
    
    164
    -    const int wakeup_fd = SEQ_CST_LOAD(&io_manager_wakeup_fd);
    
    165
    -    // Wake up the IO Manager thread by sending a byte down its pipe
    
    166
    -    if (wakeup_fd >= 0) {
    
    167
    -#if defined(HAVE_EVENTFD)
    
    168
    -        StgWord64 n = (StgWord64)IO_MANAGER_WAKEUP;
    
    169
    -        r = write(wakeup_fd, (char *) &n, 8);
    
    170
    -#else
    
    171
    -        StgWord8 byte = (StgWord8)IO_MANAGER_WAKEUP;
    
    172
    -        r = write(wakeup_fd, &byte, 1);
    
    173
    -#endif
    
    174
    -        /* N.B. If the TimerManager is shutting down as we run this
    
    175
    -         * then there is a possibility that our first read of
    
    176
    -         * io_manager_wakeup_fd is non-negative, but before we get to the
    
    177
    -         * write the file is closed. If this occurs, io_manager_wakeup_fd
    
    178
    -         * will be written into with -1 (GHC.Event.Control does this prior
    
    179
    -         * to closing), so checking this allows us to distinguish this case.
    
    180
    -         * To ensure we observe the correct ordering, we declare the
    
    181
    -         * io_manager_wakeup_fd as volatile.
    
    182
    -         * Since this is not an error condition, we do not print the error
    
    183
    -         * message in this case.
    
    184
    -         */
    
    185
    -        if (r == -1 && SEQ_CST_LOAD(&io_manager_wakeup_fd) >= 0) {
    
    186
    -            sysErrorBelch("ioManagerWakeup: write");
    
    187
    -        }
    
    188
    -    }
    
    189
    -}
    
    190
    -
    
    191
    -#if defined(THREADED_RTS)
    
    192
    -void
    
    193
    -ioManagerDie (void)
    
    194
    -{
    
    195
    -    StgWord8 byte = (StgWord8)IO_MANAGER_DIE;
    
    196
    -    uint32_t i;
    
    197
    -    int r;
    
    198
    -
    
    199
    -    {
    
    200
    -        // Shut down timer manager
    
    201
    -        const int fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    202
    -        if (0 <= fd) {
    
    203
    -            r = write(fd, &byte, 1);
    
    204
    -            if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    205
    -            RELAXED_STORE(&timer_manager_control_wr_fd, -1);
    
    206
    -        }
    
    207
    -    }
    
    208
    -
    
    209
    -    {
    
    210
    -        // Shut down IO managers
    
    211
    -        for (i=0; i < getNumCapabilities(); i++) {
    
    212
    -            const int fd = RELAXED_LOAD(&getCapability(i)->iomgr->control_fd);
    
    213
    -            if (0 <= fd) {
    
    214
    -                r = write(fd, &byte, 1);
    
    215
    -                if (r == -1) { sysErrorBelch("ioManagerDie: write"); }
    
    216
    -                RELAXED_STORE(&getCapability(i)->iomgr->control_fd, -1);
    
    217
    -            }
    
    218
    -        }
    
    219
    -    }
    
    220
    -}
    
    221
    -
    
    222
    -void
    
    223
    -ioManagerStartCap (Capability **cap)
    
    224
    -{
    
    225
    -    rts_evalIO(cap,ensureIOManagerIsRunning_closure,NULL);
    
    226
    -}
    
    227
    -
    
    228
    -void
    
    229
    -ioManagerStart (void)
    
    230
    -{
    
    231
    -    // Make sure the IO manager thread is running
    
    232
    -    Capability *cap;
    
    233
    -    if (SEQ_CST_LOAD(&timer_manager_control_wr_fd) < 0 || SEQ_CST_LOAD(&io_manager_wakeup_fd) < 0) {
    
    234
    -        cap = rts_lock();
    
    235
    -        ioManagerStartCap(&cap);
    
    236
    -        rts_unlock(cap);
    
    237
    -    }
    
    238
    -}
    
    239
    -#endif
    
    240
    -
    
    241 120
     #if !defined(THREADED_RTS)
    
    242 121
     
    
    243 122
     #define N_PENDING_HANDLERS 16
    
    ... ... @@ -260,31 +139,9 @@ generic_handler(int sig USED_IF_THREADS,
    260 139
                     void *p STG_UNUSED)
    
    261 140
     {
    
    262 141
     #if defined(THREADED_RTS)
    
    263
    -
    
    264
    -    StgWord8 buf[sizeof(siginfo_t) + 1];
    
    265
    -    int r;
    
    266
    -
    
    267
    -    buf[0] = sig;
    
    268
    -    if (info == NULL) {
    
    269
    -        // info may be NULL on Solaris (see #3790)
    
    270
    -        memset(buf+1, 0, sizeof(siginfo_t));
    
    271
    -    } else {
    
    272
    -        memcpy(buf+1, info, sizeof(siginfo_t));
    
    273
    -    }
    
    274
    -
    
    275
    -    int timer_control_fd = RELAXED_LOAD(&timer_manager_control_wr_fd);
    
    276
    -    if (0 <= timer_control_fd)
    
    277
    -    {
    
    278
    -        r = write(timer_control_fd, buf, sizeof(siginfo_t)+1);
    
    279
    -        if (r == -1 && errno == EAGAIN) {
    
    280
    -            errorBelch("lost signal due to full pipe: %d\n", sig);
    
    281
    -        }
    
    282
    -    }
    
    283
    -
    
    284
    -    // If the IO manager hasn't told us what the FD of the write end
    
    285
    -    // of its pipe is, there's not much we can do here, so just ignore
    
    286
    -    // the signal..
    
    287
    -
    
    142
    +    //TODO: This calls MIO directly. We should go via IOManager API.
    
    143
    +    // The IOManager API should be extended to cover signals.
    
    144
    +    timerManagerNotifySignal(sig, info);
    
    288 145
     #else /* not THREADED_RTS */
    
    289 146
     
    
    290 147
         /* Can't call allocate from here.  Probably can't call malloc
    

  • rts/posix/Signals.h
    ... ... @@ -25,18 +25,6 @@ extern siginfo_t *next_pending_handler;
    25 25
     void startSignalHandlers(Capability *cap);
    
    26 26
     #endif
    
    27 27
     
    
    28
    -/* Communicating with the IO manager thread (see GHC.Conc).
    
    29
    - *
    
    30
    - * TODO: these I/O manager things are not related to signals and ought to live
    
    31
    - * elsewhere, e.g. in a module specifically for the I/O manager.
    
    32
    - */
    
    33
    -void ioManagerWakeup (void);
    
    34
    -#if defined(THREADED_RTS)
    
    35
    -void ioManagerDie (void);
    
    36
    -void ioManagerStart (void);
    
    37
    -void ioManagerStartCap (/* inout */ Capability **cap);
    
    38
    -#endif
    
    39
    -
    
    40 28
     extern StgInt *signal_handlers;
    
    41 29
     
    
    42 30
     #include "EndPrivate.h"

  • rts/rts.cabal
    ... ... @@ -583,6 +583,7 @@ library
    583 583
                         posix/OSMem.c
    
    584 584
                         posix/OSThreads.c
    
    585 585
                         posix/FdWakeup.c
    
    586
    +                    posix/MIO.c
    
    586 587
                         posix/Poll.c
    
    587 588
                         posix/Select.c
    
    588 589
                         posix/Signals.c
    

  • rts/win32/AsyncMIO.h
    ... ... @@ -12,6 +12,8 @@
    12 12
     
    
    13 13
     #include "Rts.h"
    
    14 14
     
    
    15
    +#include "BeginPrivate.h"
    
    16
    +
    
    15 17
     extern unsigned int
    
    16 18
     addIORequest(int   fd,
    
    17 19
                  bool  forWriting,
    
    ... ... @@ -28,3 +30,5 @@ extern int awaitRequests(bool wait);
    28 30
     extern void abandonRequestWait(void);
    
    29 31
     extern void resetAbandonRequestWait(void);
    
    30 32
     extern HsInt rts_EINTR(void);
    
    33
    +
    
    34
    +#include "EndPrivate.h"

  • rts/win32/AsyncWinIO.h
    ... ... @@ -14,12 +14,16 @@
    14 14
     #include <stdbool.h>
    
    15 15
     #include <windows.h>
    
    16 16
     
    
    17
    -extern bool startupAsyncWinIO(void);
    
    18
    -extern void shutdownAsyncWinIO(bool wait_threads);
    
    19
    -extern void awaitAsyncRequests(bool wait);
    
    20 17
     extern void registerIOCPHandle (HANDLE port);
    
    21 18
     extern void registerAlertableWait (bool has_timeout, DWORD mssec);
    
    22
    -
    
    23 19
     extern OVERLAPPED_ENTRY* getOverlappedEntries (uint32_t *num);
    
    24 20
     extern void completeSynchronousRequest (void);
    
    21
    +
    
    22
    +#include "BeginPrivate.h"
    
    23
    +
    
    24
    +extern bool startupAsyncWinIO(void);
    
    25
    +extern void shutdownAsyncWinIO(bool wait_threads);
    
    26
    +extern void awaitAsyncRequests(bool wait);
    
    25 27
     extern bool queueIOThread(void);
    
    28
    +
    
    29
    +#include "EndPrivate.h"

  • rts/win32/AwaitEvent.h
    1 1
     #pragma once
    
    2 2
     
    
    3
    +#include "BeginPrivate.h"
    
    4
    +
    
    3 5
     void awaitCompletedTimeoutsOrIOWin32(Capability *cap, bool wait);
    
    4 6
     
    
    7
    +#include "EndPrivate.h"

  • rts/win32/ConsoleHandler.h
    ... ... @@ -7,6 +7,8 @@
    7 7
     
    
    8 8
     #pragma once
    
    9 9
     
    
    10
    +#include "BeginPrivate.h"
    
    11
    +
    
    10 12
     /*
    
    11 13
      * Console control handlers lets an application handle Ctrl+C, Ctrl+Break etc.
    
    12 14
      * in Haskell under Win32. Akin to the Unix signal SIGINT.
    
    ... ... @@ -69,3 +71,5 @@ extern int rts_waitConsoleHandlerCompletion(void);
    69 71
      * Tear down and shut down user signal processing.
    
    70 72
      */
    
    71 73
     extern void finiUserSignals(void);
    
    74
    +
    
    75
    +#include "EndPrivate.h"

  • rts/win32/MIOManager.h
    ... ... @@ -12,6 +12,8 @@
    12 12
     
    
    13 13
     #include <windows.h>
    
    14 14
     
    
    15
    +#include "BeginPrivate.h"
    
    16
    +
    
    15 17
     /*
    
    16 18
      The IOManager subsystem provides a non-blocking view
    
    17 19
      of I/O operations. It lets one (or more) OS thread(s)
    
    ... ... @@ -107,3 +109,5 @@ extern int AddProcRequest ( void* proc,
    107 109
     extern void abandonWorkRequest ( int reqID );
    
    108 110
     
    
    109 111
     extern void interruptIOManagerEvent ( void );
    
    112
    +
    
    113
    +#include "EndPrivate.h"

  • rts/win32/ThrIOManager.h
    ... ... @@ -12,7 +12,12 @@
    12 12
     
    
    13 13
     /* Communicating with the IO manager thread (see GHC.Conc).
    
    14 14
      */
    
    15
    +void ioManagerFinished (void);
    
    16
    +
    
    17
    +#include "BeginPrivate.h"
    
    18
    +
    
    15 19
     void ioManagerWakeup (void);
    
    16 20
     void ioManagerDie (void);
    
    17 21
     void ioManagerStart (void);
    
    18
    -void ioManagerFinished (void);
    22
    +
    
    23
    +#include "EndPrivate.h"

  • rts/win32/WorkQueue.h
    ... ... @@ -10,6 +10,8 @@
    10 10
     
    
    11 11
     #include <windows.h>
    
    12 12
     
    
    13
    +#include "BeginPrivate.h"
    
    14
    +
    
    13 15
     /* This is a fixed-size queue. */
    
    14 16
     #define WORKQUEUE_SIZE 16
    
    15 17
     
    
    ... ... @@ -34,3 +36,5 @@ extern HANDLE GetWorkQueueHandle ( WorkQueue* pq );
    34 36
     extern BOOL       GetWork            ( WorkQueue* pq, void** ppw );
    
    35 37
     extern BOOL       FetchWork          ( WorkQueue* pq, void** ppw );
    
    36 38
     extern int        SubmitWork         ( WorkQueue* pq, void*   pw );
    
    39
    +
    
    40
    +#include "EndPrivate.h"

  • rts/win32/veh_excn.h
    ... ... @@ -59,6 +59,8 @@
    59 59
     // simplified quite a bit.
    
    60 60
     // Using VEH also means we don't have to worry about the dynamic code generated by GHCi.
    
    61 61
     
    
    62
    +#include "BeginPrivate.h"
    
    63
    +
    
    62 64
     // Prototype of the VEH callback function.
    
    63 65
     // See https://msdn.microsoft.com/en-us/library/windows/desktop/ms681419(v=vs.85).aspx
    
    64 66
     //
    
    ... ... @@ -72,3 +74,5 @@ void __unregister_hs_exception_handler( void );
    72 74
     // prototypes for dump methods.
    
    73 75
     void generateDump(EXCEPTION_POINTERS* pExceptionPointers);
    
    74 76
     void generateStack (EXCEPTION_POINTERS* pExceptionPointers);
    
    77
    +
    
    78
    +#include "EndPrivate.h"