Duncan Coutts pushed to branch wip/dcoutts/issue-26717 at Glasgow Haskell Compiler / GHC

Commits:

10 changed files:

Changes:

  • rts/IOManager.c
    ... ... @@ -772,11 +772,12 @@ bool syncIOWaitReady(Capability *cap,
    772 772
     #if defined(IOMGR_ENABLED_SELECT)
    
    773 773
             case IO_MANAGER_SELECT:
    
    774 774
             {
    
    775
    -            StgWord why_blocked = (rw == IORead ? BlockedOnRead : BlockedOnWrite)
    
    776
    -                                | BlockInfoForceNonClosure;
    
    775
    +            unsigned int why_blocked = (rw == IORead ? BlockedOnRead
    
    776
    +                                                     : BlockedOnWrite)
    
    777
    +                                     | BlockInfoForceNonClosure;
    
    777 778
                 tso->block_info.fd = fd;
    
    778
    -            RELEASE_STORE(&tso->why_blocked, why_blocked);
    
    779 779
                 appendToIOBlockedQueue(cap, tso);
    
    780
    +            RELEASE_STORE(&tso->why_blocked, why_blocked);
    
    780 781
                 return true;
    
    781 782
             }
    
    782 783
     #endif
    
    ... ... @@ -833,8 +834,8 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
    833 834
             {
    
    834 835
                 LowResTime target = getDelayTarget(us_delay);
    
    835 836
                 tso->block_info.target = target;
    
    836
    -            RELEASE_STORE(&tso->why_blocked, BlockedOnDelay | BlockInfoForceNonClosure);
    
    837 837
                 insertIntoSleepingQueue(cap, tso, target);
    
    838
    +            RELEASE_STORE(&tso->why_blocked, BlockedOnDelay | BlockInfoForceNonClosure);
    
    838 839
                 return true;
    
    839 840
             }
    
    840 841
     #endif
    
    ... ... @@ -854,8 +855,8 @@ bool syncDelay(Capability *cap, StgTSO *tso, HsInt us_delay)
    854 855
                  * simplifies matters, so set the status to OnDoProc and put the
    
    855 856
                  * delayed thread on the blocked_queue.
    
    856 857
                  */
    
    857
    -            RELEASE_STORE(&tso->why_blocked, BlockedOnDoProc);
    
    858 858
                 appendToIOBlockedQueue(cap, tso);
    
    859
    +            RELEASE_STORE(&tso->why_blocked, BlockedOnDoProc);
    
    859 860
                 return true;
    
    860 861
             }
    
    861 862
     #endif
    

  • rts/RaiseAsync.c
    ... ... @@ -233,7 +233,6 @@ throwTo (Capability *cap, // the Capability we hold
    233 233
     uint32_t
    
    234 234
     throwToMsg (Capability *cap, MessageThrowTo *msg)
    
    235 235
     {
    
    236
    -    StgWord status;
    
    237 236
         StgTSO *target = ACQUIRE_LOAD(&msg->target);
    
    238 237
         Capability *target_cap;
    
    239 238
     
    
    ... ... @@ -268,9 +267,9 @@ check_target:
    268 267
             return THROWTO_BLOCKED;
    
    269 268
         }
    
    270 269
     
    
    271
    -    status = ACQUIRE_LOAD(&target->why_blocked);
    
    270
    +    unsigned int why_blocked = ACQUIRE_LOAD(&target->why_blocked);
    
    272 271
     
    
    273
    -    switch (UntagWhyBlocked(status)) {
    
    272
    +    switch (UntagWhyBlocked(why_blocked)) {
    
    274 273
         case NotBlocked:
    
    275 274
         {
    
    276 275
             if ((target->flags & TSO_BLOCKEX) == 0) {
    
    ... ... @@ -370,8 +369,9 @@ check_target:
    370 369
     
    
    371 370
             // we have the MVar, let's check whether the thread
    
    372 371
             // is still blocked on the same MVar.
    
    373
    -        if ((target->why_blocked != BlockedOnMVar
    
    374
    -             && target->why_blocked != BlockedOnMVarRead)
    
    372
    +        unsigned int why_blocked_still = ACQUIRE_LOAD(&target->why_blocked);
    
    373
    +        if ((   why_blocked_still != BlockedOnMVar
    
    374
    +             && why_blocked_still != BlockedOnMVarRead)
    
    375 375
                 || target->block_info.mvar != mvar) {
    
    376 376
                 unlockClosure((StgClosure *)mvar, info);
    
    377 377
                 goto retry;
    
    ... ... @@ -490,7 +490,7 @@ check_target:
    490 490
             goto retry;
    
    491 491
     
    
    492 492
         default:
    
    493
    -        barf("throwTo: unrecognised why_blocked (%d)", target->why_blocked);
    
    493
    +        barf("throwTo: unrecognised why_blocked (%d)", why_blocked);
    
    494 494
         }
    
    495 495
         barf("throwTo");
    
    496 496
     }
    
    ... ... @@ -667,7 +667,7 @@ removeFromMVarBlockedQueue (StgTSO *tso)
    667 667
     static void
    
    668 668
     removeFromQueues(Capability *cap, StgTSO *tso)
    
    669 669
     {
    
    670
    -  switch (UntagWhyBlocked(tso->why_blocked)) {
    
    670
    +  switch (UntagWhyBlocked(ACQUIRE_LOAD(&tso->why_blocked))) {
    
    671 671
     
    
    672 672
       case NotBlocked:
    
    673 673
       case ThreadMigrating:
    
    ... ... @@ -721,8 +721,8 @@ removeFromQueues(Capability *cap, StgTSO *tso)
    721 721
       }
    
    722 722
     
    
    723 723
      done:
    
    724
    -  RELAXED_STORE(&tso->why_blocked, NotBlocked);
    
    725 724
       appendToRunQueue(cap, tso);
    
    725
    +  RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    726 726
     }
    
    727 727
     
    
    728 728
     /* -----------------------------------------------------------------------------
    
    ... ... @@ -1105,9 +1105,9 @@ done:
    1105 1105
         IF_DEBUG(sanity, checkTSO(tso));
    
    1106 1106
     
    
    1107 1107
         // wake it up
    
    1108
    -    if (tso->why_blocked != NotBlocked) {
    
    1109
    -        tso->why_blocked = NotBlocked;
    
    1108
    +    if (RELAXED_LOAD(&tso->why_blocked) != NotBlocked) {
    
    1110 1109
             appendToRunQueue(cap,tso);
    
    1110
    +        RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    1111 1111
         }
    
    1112 1112
     
    
    1113 1113
         return tso;
    

  • rts/Schedule.c
    ... ... @@ -524,7 +524,7 @@ run_thread:
    524 524
     #endif
    
    525 525
     
    
    526 526
         if (ret == ThreadBlocked) {
    
    527
    -        StgWord why_blocked = ACQUIRE_LOAD(&t->why_blocked);
    
    527
    +        unsigned int why_blocked = ACQUIRE_LOAD(&t->why_blocked);
    
    528 528
             if (why_blocked == BlockedOnBlackHole) {
    
    529 529
                 StgTSO *owner = blackHoleOwner(t->block_info.bh->bh);
    
    530 530
                 traceEventStopThread(cap, t, eventlogStopStatus(why_blocked),
    
    ... ... @@ -1098,7 +1098,7 @@ schedulePostRunThread (Capability *cap, StgTSO *t)
    1098 1098
         //
    
    1099 1099
         // and a is never equal to b given a consistent view of memory.
    
    1100 1100
         //
    
    1101
    -    if (t -> trec != NO_TREC && t -> why_blocked == NotBlocked) {
    
    1101
    +    if (t -> trec != NO_TREC && RELAXED_LOAD(&t->why_blocked) == NotBlocked) {
    
    1102 1102
             if (!stmValidateNestOfTransactions(cap, t -> trec, true)) {
    
    1103 1103
                 debugTrace(DEBUG_sched | DEBUG_stm,
    
    1104 1104
                            "trec %p found wasting its time", t);
    
    ... ... @@ -2523,9 +2523,9 @@ suspendThread (StgRegTable *reg, bool interruptible)
    2523 2523
     
    
    2524 2524
       tso->block_info.unused = END_TSO_QUEUE;
    
    2525 2525
       if (interruptible) {
    
    2526
    -    tso->why_blocked = BlockedOnCCall_Interruptible;
    
    2526
    +    RELEASE_STORE(&tso->why_blocked, BlockedOnCCall_Interruptible);
    
    2527 2527
       } else {
    
    2528
    -    tso->why_blocked = BlockedOnCCall;
    
    2528
    +    RELEASE_STORE(&tso->why_blocked, BlockedOnCCall);
    
    2529 2529
       }
    
    2530 2530
     
    
    2531 2531
       // Hand back capability
    
    ... ... @@ -2583,16 +2583,25 @@ resumeThread (void *task_)
    2583 2583
         tso = incall->suspended_tso;
    
    2584 2584
         incall->suspended_tso = NULL;
    
    2585 2585
         incall->suspended_cap = NULL;
    
    2586
    +
    
    2587
    +    // we set why_blocked previously in suspendThread
    
    2588
    +    ASSERT(tso->why_blocked == BlockedOnCCall ||
    
    2589
    +           tso->why_blocked == BlockedOnCCall_Interruptible);
    
    2590
    +
    
    2586 2591
         // we will modify tso->_link
    
    2587 2592
         IF_NONMOVING_WRITE_BARRIER_ENABLED {
    
    2588 2593
             updateRemembSetPushClosure(cap, (StgClosure *)tso->_link);
    
    2589 2594
         }
    
    2590 2595
         tso->_link = END_TSO_QUEUE;
    
    2596
    +    // but no need to modify tso->block_info.prev as coincidentally
    
    2597
    +    // it has the value we want already (since in suspendThread we set
    
    2598
    +    // tso->block_info.unused to END_TSO_QUEUE for BlockedOnCCall).
    
    2599
    +    ASSERT(tso->block_info.prev == END_TSO_QUEUE);
    
    2591 2600
     
    
    2592 2601
         traceEventRunThread(cap, tso);
    
    2593 2602
     
    
    2594 2603
         /* Reset blocking status */
    
    2595
    -    tso->why_blocked  = NotBlocked;
    
    2604
    +    RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    2596 2605
     
    
    2597 2606
         if ((tso->flags & TSO_BLOCKEX) == 0) {
    
    2598 2607
             // avoid locking the TSO if we don't have to
    
    ... ... @@ -2944,8 +2953,9 @@ deleteThread (StgTSO *tso)
    2944 2953
         // The TSO must be on the run queue of the Capability we own, or
    
    2945 2954
         // we must own all Capabilities.
    
    2946 2955
     
    
    2947
    -    if (tso->why_blocked != BlockedOnCCall &&
    
    2948
    -        tso->why_blocked != BlockedOnCCall_Interruptible) {
    
    2956
    +    unsigned int why_blocked = RELAXED_LOAD(&tso->why_blocked);
    
    2957
    +    if (why_blocked != BlockedOnCCall &&
    
    2958
    +        why_blocked != BlockedOnCCall_Interruptible) {
    
    2949 2959
             throwToSingleThreaded(tso->cap,tso,NULL);
    
    2950 2960
         }
    
    2951 2961
     }
    
    ... ... @@ -2956,10 +2966,12 @@ deleteThread_(StgTSO *tso)
    2956 2966
     { // for forkProcess only:
    
    2957 2967
       // like deleteThread(), but we delete threads in foreign calls, too.
    
    2958 2968
     
    
    2959
    -    if (tso->why_blocked == BlockedOnCCall ||
    
    2960
    -        tso->why_blocked == BlockedOnCCall_Interruptible) {
    
    2969
    +    unsigned int why_blocked = RELAXED_LOAD(&tso->why_blocked);
    
    2970
    +    if (why_blocked == BlockedOnCCall ||
    
    2971
    +        why_blocked == BlockedOnCCall_Interruptible) {
    
    2961 2972
             tso->what_next = ThreadKilled;
    
    2962 2973
             appendToRunQueue(tso->cap, tso);
    
    2974
    +        RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    2963 2975
         } else {
    
    2964 2976
             deleteThread(tso);
    
    2965 2977
         }
    
    ... ... @@ -3310,7 +3322,7 @@ resurrectThreads (StgTSO *threads)
    3310 3322
             // Wake up the thread on the Capability it was last on
    
    3311 3323
             cap = tso->cap;
    
    3312 3324
     
    
    3313
    -        switch (tso->why_blocked) {
    
    3325
    +        switch (RELAXED_LOAD(&tso->why_blocked)) {
    
    3314 3326
             case BlockedOnMVar:
    
    3315 3327
             case BlockedOnMVarRead:
    
    3316 3328
                 /* Called by GC - sched_mutex lock is currently held. */
    

  • rts/Threads.c
    ... ... @@ -335,8 +335,8 @@ tryWakeupThread (Capability *cap, StgTSO *tso)
    335 335
     unblock:
    
    336 336
         // just run the thread now, if the BH is not really available,
    
    337 337
         // we'll block again.
    
    338
    -    tso->why_blocked = NotBlocked;
    
    339 338
         appendToRunQueue(cap,tso);
    
    339
    +    RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    340 340
     
    
    341 341
         // We used to set the context switch flag here, which would
    
    342 342
         // trigger a context switch a short time in the future (at the end
    
    ... ... @@ -368,7 +368,7 @@ migrateThread (Capability *from, StgTSO *tso, Capability *to)
    368 368
         // ThreadMigrating tells the target cap that it needs to be added to
    
    369 369
         // the run queue when it receives the MSG_TRY_WAKEUP.
    
    370 370
         tso->block_info.unused = END_TSO_QUEUE;
    
    371
    -    tso->why_blocked = ThreadMigrating;
    
    371
    +    RELEASE_STORE(&tso->why_blocked, ThreadMigrating);
    
    372 372
         tso->cap = to;
    
    373 373
         tryWakeupThread(from, tso);
    
    374 374
     }
    
    ... ... @@ -847,7 +847,7 @@ loop:
    847 847
     
    
    848 848
         // save why_blocked here, because waking up the thread destroys
    
    849 849
         // this information
    
    850
    -    StgWord why_blocked = ACQUIRE_LOAD(&tso->why_blocked);
    
    850
    +    unsigned int why_blocked = ACQUIRE_LOAD(&tso->why_blocked);
    
    851 851
         ASSERT(why_blocked == BlockedOnMVarRead || why_blocked == BlockedOnMVar);
    
    852 852
         ASSERT(tso->block_info.mvar == mvar);
    
    853 853
     
    
    ... ... @@ -1017,7 +1017,7 @@ printAllThreads(void)
    1017 1017
       debugBelch("other threads:\n");
    
    1018 1018
       for (g = 0; g < RtsFlags.GcFlags.generations; g++) {
    
    1019 1019
         for (t = generations[g].threads; t != END_TSO_QUEUE; t = next) {
    
    1020
    -      if (t->why_blocked != NotBlocked) {
    
    1020
    +      if (RELAXED_LOAD(&t->why_blocked) != NotBlocked) {
    
    1021 1021
               printThreadStatus(t);
    
    1022 1022
           }
    
    1023 1023
           next = t->global_link;
    

  • rts/TraverseHeap.c
    ... ... @@ -1243,7 +1243,7 @@ inner_loop:
    1243 1243
             traversePushClosure(ts, (StgClosure *) tso->bq, c, sep, child_data);
    
    1244 1244
             traversePushClosure(ts, (StgClosure *) tso->trec, c, sep, child_data);
    
    1245 1245
     
    
    1246
    -        StgWord why_blocked = ACQUIRE_LOAD(&tso->why_blocked);
    
    1246
    +        unsigned int why_blocked = ACQUIRE_LOAD(&tso->why_blocked);
    
    1247 1247
             if (IsBlockInfoClosure(why_blocked) && why_blocked != NotBlocked) {
    
    1248 1248
                 // The NotBlocked case uses block_info.prev as a TSO back link.
    
    1249 1249
                 // Do not follow in that case or we'll get into a loop.
    

  • rts/posix/Poll.c
    ... ... @@ -146,8 +146,9 @@ bool syncIOWaitReadyPoll(Capability *cap, StgTSO *tso,
    146 146
         aiop->notify.tso     = tso;
    
    147 147
         aiop->notify_type    = NotifyTSO;
    
    148 148
         aiop->live           = &stg_ASYNCIO_LIVE0_closure;
    
    149
    -    tso->why_blocked     = rw == IORead ? BlockedOnRead : BlockedOnWrite;
    
    150 149
         tso->block_info.aiop = aiop;
    
    150
    +    RELEASE_STORE(&tso->why_blocked, rw == IORead ? BlockedOnRead
    
    151
    +                                                  : BlockedOnWrite);
    
    151 152
         return asyncIOWaitReadyPoll(cap, aiop, rw, fd);
    
    152 153
     }
    
    153 154
     
    
    ... ... @@ -258,10 +259,9 @@ static void notifyIOCompletion(Capability *cap, StgAsyncIOOp *aiop)
    258 259
                      * cap because the tso was not on the run queue of any cap and
    
    259 260
                      * so is not subject to thread migration.
    
    260 261
                      */
    
    261
    -                StgTSO *tso      = aiop->notify.tso;
    
    262
    -                tso->why_blocked = NotBlocked;
    
    263
    -                tso->_link       = END_TSO_QUEUE;
    
    262
    +                StgTSO *tso = aiop->notify.tso;
    
    264 263
                     pushOnRunQueue(cap, tso);
    
    264
    +                RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    265 265
                 }
    
    266 266
                 break;
    
    267 267
             }
    

  • rts/posix/Select.c
    ... ... @@ -105,11 +105,10 @@ static bool wakeUpSleepingThreads (Capability *cap, LowResTime now)
    105 105
                 break;
    
    106 106
             }
    
    107 107
             iomgr->sleeping_queue = tso->_link;
    
    108
    -        RELAXED_STORE(&tso->why_blocked, NotBlocked);
    
    109
    -        tso->_link = END_TSO_QUEUE;
    
    110 108
             IF_DEBUG(scheduler, debugBelch("Waking up sleeping thread %"
    
    111 109
                                            FMT_StgThreadID "\n", tso->id));
    
    112 110
             pushOnRunQueue(cap,tso);
    
    111
    +        RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    113 112
             flag = true;
    
    114 113
         }
    
    115 114
         return flag;
    
    ... ... @@ -397,7 +396,7 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
    397 396
                   int fd;
    
    398 397
                   enum FdState fd_state = RTS_FD_IS_BLOCKING;
    
    399 398
     
    
    400
    -              switch (UntagWhyBlocked(tso->why_blocked)) {
    
    399
    +              switch (UntagWhyBlocked(ACQUIRE_LOAD(&tso->why_blocked))) {
    
    401 400
                   case BlockedOnRead:
    
    402 401
                       fd = tso->block_info.fd;
    
    403 402
     
    
    ... ... @@ -436,9 +435,8 @@ awaitCompletedTimeoutsOrIOSelect(Capability *cap, bool wait)
    436 435
                       IF_DEBUG(scheduler,
    
    437 436
                           debugBelch("Waking up blocked thread %" FMT_StgThreadID "\n",
    
    438 437
                                      tso->id));
    
    439
    -                  tso->why_blocked = NotBlocked;
    
    440
    -                  tso->_link = END_TSO_QUEUE;
    
    441 438
                       pushOnRunQueue(cap,tso);
    
    439
    +                  RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    442 440
                       break;
    
    443 441
                   case RTS_FD_IS_BLOCKING:
    
    444 442
                       if (prev == NULL)
    

  • rts/posix/Timeout.c
    ... ... @@ -48,8 +48,8 @@ bool syncDelayTimeout(Capability *cap, StgTSO *tso, HsInt us_delay)
    48 48
         initElemTimeoutQueue(timeout, notify, NotifyTSO, cap->r.rCCCS);
    
    49 49
     
    
    50 50
         ASSERT(tso->why_blocked == NotBlocked);
    
    51
    -    tso->why_blocked = BlockedOnDelay;
    
    52 51
         tso->block_info.timeout = timeout;
    
    52
    +    RELEASE_STORE(&tso->why_blocked, BlockedOnDelay);
    
    53 53
     
    
    54 54
         insertTimeoutQueue(&cap->iomgr->timeout_queue, timeout, target);
    
    55 55
     
    
    ... ... @@ -118,10 +118,10 @@ static void notifyTimeoutCompletion(Capability *cap, StgTimeout *timeout)
    118 118
         switch (timeout->notify_type) {
    
    119 119
             case NotifyTSO:
    
    120 120
             {
    
    121
    -            StgTSO *tso      = timeout->notify.tso;
    
    122
    -            tso->why_blocked = NotBlocked;
    
    123
    -            tso->_link       = END_TSO_QUEUE;
    
    121
    +            StgTSO *tso = timeout->notify.tso;
    
    122
    +            tso->_link  = END_TSO_QUEUE;
    
    124 123
                 pushOnRunQueue(cap, tso);
    
    124
    +            RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    125 125
                 break;
    
    126 126
             }
    
    127 127
             case NotifyMVar:
    

  • rts/sm/Sanity.c
    ... ... @@ -779,7 +779,7 @@ checkTSO(StgTSO *tso)
    779 779
                info == &stg_WHITEHOLE_info); // used to happen due to STM doing
    
    780 780
                                              // lockTSO(), might not happen now
    
    781 781
     
    
    782
    -    unsigned why_blocked = ACQUIRE_LOAD(&tso->why_blocked);
    
    782
    +    unsigned int why_blocked = ACQUIRE_LOAD(&tso->why_blocked);
    
    783 783
         switch (why_blocked) {
    
    784 784
         case NotBlocked:
    
    785 785
         case BlockedOnMVar:
    

  • rts/win32/AsyncMIO.c
    ... ... @@ -318,8 +318,6 @@ start:
    318 318
                             }
    
    319 319
     
    
    320 320
                             // Terminates the run queue + this inner for-loop.
    
    321
    -                        tso->_link = END_TSO_QUEUE;
    
    322
    -                        tso->why_blocked = NotBlocked;
    
    323 321
                             // For stg_block_async frames (read/write/doProc),
    
    324 322
                             // write len and errCode directly to the stack.
    
    325 323
                             // For stg_block_noregs frames (delay), nothing
    
    ... ... @@ -329,14 +327,14 @@ start:
    329 327
                                 tso->stackobj->sp[2] = (W_)errCode;
    
    330 328
                             }
    
    331 329
                             pushOnRunQueue(&MainCapability, tso);
    
    330
    +                        RELEASE_STORE(&tso->why_blocked, NotBlocked);
    
    332 331
                             break;
    
    333 332
                         }
    
    334 333
                         break;
    
    335
    -                default:
    
    336
    -                    if (tso->why_blocked != NotBlocked) {
    
    337
    -                        barf("awaitRequests: odd thread state");
    
    338
    -                    }
    
    334
    +                case NotBlocked:
    
    339 335
                         break;
    
    336
    +                default:
    
    337
    +                    barf("awaitRequests: odd thread state");
    
    340 338
                     }
    
    341 339
     
    
    342 340
                     prev = tso;