Marge Bot pushed to branch master at Glasgow Haskell Compiler / GHC

Commits:

8 changed files:

Changes:

  • rts/CloneStack.c
    ... ... @@ -88,6 +88,7 @@ void sendCloneStackMessage(StgTSO *tso, HsStablePtr mvar) {
    88 88
     void handleCloneStackMessage(Capability *cap, MessageCloneStack *msg){
    
    89 89
       // We must check that the current owner of the thread we want to clone the stack for
    
    90 90
       // is still this capability.
    
    91
    +  // See Note [TSO owner may change in between Msg being sent and received]
    
    91 92
       Capability *owner = RELAXED_LOAD(&msg->tso->cap);
    
    92 93
       if (owner != cap) {
    
    93 94
         // The target TSO may have migrated after the message was queued on the old
    

  • rts/Interpreter.c
    ... ... @@ -416,22 +416,14 @@ void rts_disableStopNextBreakpointAll(void)
    416 416
     
    
    417 417
     void rts_enableStopNextBreakpoint(StgTSO* tso)
    
    418 418
     {
    
    419
    -#if defined(THREADED_RTS)
    
    420 419
       Capability* cap = rts_unsafeGetMyCapability();
    
    421 420
       setThreadFlag(cap, tso, TSO_STOP_NEXT_BREAKPOINT);
    
    422
    -#else
    
    423
    -  tso->flags |= TSO_STOP_NEXT_BREAKPOINT;
    
    424
    -#endif
    
    425 421
     }
    
    426 422
     
    
    427 423
     void rts_disableStopNextBreakpoint(StgTSO* tso)
    
    428 424
     {
    
    429
    -#if defined(THREADED_RTS)
    
    430 425
       Capability* cap = rts_unsafeGetMyCapability();
    
    431 426
       unsetThreadFlag(cap, tso, TSO_STOP_NEXT_BREAKPOINT);
    
    432
    -#else
    
    433
    -  tso->flags &= ~TSO_STOP_NEXT_BREAKPOINT;
    
    434
    -#endif
    
    435 427
     }
    
    436 428
     
    
    437 429
     /* ---------------------------------------------------------------------------
    
    ... ... @@ -440,22 +432,14 @@ void rts_disableStopNextBreakpoint(StgTSO* tso)
    440 432
     
    
    441 433
     void rts_enableStopAfterReturn(StgTSO* tso)
    
    442 434
     {
    
    443
    -#if defined(THREADED_RTS)
    
    444 435
       Capability* cap = rts_unsafeGetMyCapability();
    
    445 436
       setThreadFlag(cap, tso, TSO_STOP_AFTER_RETURN);
    
    446
    -#else
    
    447
    -  tso->flags |= TSO_STOP_AFTER_RETURN;
    
    448
    -#endif
    
    449 437
     }
    
    450 438
     
    
    451 439
     void rts_disableStopAfterReturn(StgTSO* tso)
    
    452 440
     {
    
    453
    -#if defined(THREADED_RTS)
    
    454 441
       Capability* cap = rts_unsafeGetMyCapability();
    
    455 442
       unsetThreadFlag(cap, tso, TSO_STOP_AFTER_RETURN);
    
    456
    -#else
    
    457
    -  tso->flags &= ~TSO_STOP_AFTER_RETURN;
    
    458
    -#endif
    
    459 443
     }
    
    460 444
     
    
    461 445
     /*
    

  • rts/Messages.c
    ... ... @@ -36,8 +36,7 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg)
    36 36
                 i != &stg_IND_info && // can happen if a MSG_BLACKHOLE is revoked
    
    37 37
                 i != &stg_WHITEHOLE_info &&
    
    38 38
                 i != &stg_MSG_CLONE_STACK_info &&
    
    39
    -            i != &stg_MSG_SET_TSO_FLAG_info &&
    
    40
    -            i != &stg_MSG_UNSET_TSO_FLAG_info) {
    
    39
    +            i != &stg_MSG_UPD_TSO_FLAG_info) {
    
    41 40
                 barf("sendMessage: %p", i);
    
    42 41
             }
    
    43 42
         }
    
    ... ... @@ -67,6 +66,62 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg)
    67 66
        Handle a message
    
    68 67
        ------------------------------------------------------------------------- */
    
    69 68
     
    
    69
    +/*
    
    70
    +Note [TSO owner may change in between Msg being sent and received]
    
    71
    +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    
    72
    +When a message is sent from Capability (C1) to a target TSO (T2) (e.g.
    
    73
    +MessageUpdTSOFlag, MessageCloneStack, ...), it is queued on the TSO's owner
    
    74
    +Capability (C3) inbox (inboxes are owned by Capabilities, not TSOs).
    
    75
    +
    
    76
    +At a later point, the Capability (C3) will process its inbox. Upon receiving
    
    77
    +the message meant for a specific TSO (T2), it must first always check that the
    
    78
    +TSO's owner is *still* itself (C3).
    
    79
    +
    
    80
    +The target TSO (T2) may have migrated after the message was queued on its old
    
    81
    +capability (C3). In that case we must forward the request to the new owner
    
    82
    +(say, C4); otherwise the Capability C3 could be modifying a TSO it no longer
    
    83
    +owns, racing with its actual owner mutating it, since it is no longer the owner.
    
    84
    +
    
    85
    +The message meant for a TSO should only be executed when the receiving
    
    86
    +Capability is still the owner of that TSO. Otherwise, it must be forwarded to
    
    87
    +the new owner.
    
    88
    +
    
    89
    +The general pattern is one where there's a top-level function which assumes it
    
    90
    +can be called by capabilities other than the TSO's owner. The function checks
    
    91
    +whether the current capability is the TSO owner. If yes, execute the action. If
    
    92
    +not, then it sends a message to the current TSO's owner. On receiving the
    
    93
    +message, the new capability will just call that top-level function, which will
    
    94
    +ensure the message is forwarded again if the TSO owner changed.
    
    95
    +It will look something like:
    
    96
    +
    
    97
    +  runMyMsg(Capability *from, StgTSO *target, ...) {
    
    98
    +
    
    99
    +#if defined(THREADED_RTS)
    
    100
    +    Capability *owner = RELAXED_LOAD(&target->cap)
    
    101
    +    if (owner != from) {
    
    102
    +      MessageMyMsg* msg = ...
    
    103
    +      sendMessage(cap, owner, msg)
    
    104
    +      return
    
    105
    +    }
    
    106
    +#endif
    
    107
    +
    
    108
    +    actuallyDoTheWork(...)
    
    109
    +  }
    
    110
    +
    
    111
    +  executeMessage(...) {
    
    112
    +
    
    113
    +    if (i == &stg_MY_MSG_info) {
    
    114
    +
    
    115
    +      MessageMyMsg* msg = (MessageMyMsg*) m
    
    116
    +      runMyMsg(cap, m->tso, ...)
    
    117
    +
    
    118
    +    }
    
    119
    +  }
    
    120
    +
    
    121
    +See example `updThreadFlag` and `executeMessage`'s `stg_MSG_UPD_TSO_FLAG_info`,
    
    122
    +or `tryWakeUpThread` and `stg_MSG_TRY_WAKEUP_info` for two live examples.
    
    123
    +*/
    
    124
    +
    
    70 125
     #if defined(THREADED_RTS)
    
    71 126
     
    
    72 127
     void
    
    ... ... @@ -141,15 +196,11 @@ loop:
    141 196
             MessageCloneStack *cloneStackMessage = (MessageCloneStack*) m;
    
    142 197
             handleCloneStackMessage(cap, cloneStackMessage);
    
    143 198
         }
    
    144
    -    else if(i == &stg_MSG_SET_TSO_FLAG_info){
    
    199
    +    else if(i == &stg_MSG_UPD_TSO_FLAG_info){
    
    145 200
             MessageUpdTSOFlag *u = (MessageUpdTSOFlag*) m;
    
    146
    -        u->tso->flags |= u->flag;
    
    147
    -        return;
    
    148
    -    }
    
    149
    -    else if(i == &stg_MSG_UNSET_TSO_FLAG_info){
    
    150
    -        MessageUpdTSOFlag *u = (MessageUpdTSOFlag*) m;
    
    151
    -        u->tso->flags &= ~u->flag;
    
    152
    -        return;
    
    201
    +
    
    202
    +        StgTSO *tso = RELAXED_LOAD(&u->tso);
    
    203
    +        updThreadFlag(cap, tso, u->flag, u->set);
    
    153 204
         }
    
    154 205
         else
    
    155 206
         {
    

  • rts/StgMiscClosures.cmm
    ... ... @@ -855,11 +855,8 @@ INFO_TABLE_CONSTR(stg_MSG_NULL,1,0,0,PRIM,"MSG_NULL","MSG_NULL")
    855 855
     INFO_TABLE_CONSTR(stg_MSG_CLONE_STACK,3,0,0,PRIM,"MSG_CLONE_STACK","MSG_CLONE_STACK")
    
    856 856
     { ccall pbarf("stg_MSG_CLONE_STACK object (%p) entered!", R1 "ptr") never returns; }
    
    857 857
     
    
    858
    -INFO_TABLE_CONSTR(stg_MSG_SET_TSO_FLAG,2,1,0,PRIM,"MSG_SET_TSO_FLAG","MSG_SET_TSO_FLAG")
    
    859
    -{ foreign "C" barf("stg_MSG_SET_TSO_FLAG object (%p) entered!", R1) never returns; }
    
    860
    -
    
    861
    -INFO_TABLE_CONSTR(stg_MSG_UNSET_TSO_FLAG,2,1,0,PRIM,"MSG_UNSET_TSO_FLAG","MSG_UNSET_TSO_FLAG")
    
    862
    -{ foreign "C" barf("stg_MSG_UNSET_TSO_FLAG object (%p) entered!", R1) never returns; }
    
    858
    +INFO_TABLE_CONSTR(stg_MSG_UPD_TSO_FLAG,2,2,0,PRIM,"MSG_UPD_TSO_FLAG","MSG_UPD_TSO_FLAG")
    
    859
    +{ foreign "C" barf("stg_MSG_UPD_TSO_FLAG object (%p) entered!", R1) never returns; }
    
    863 860
     
    
    864 861
     /* ----------------------------------------------------------------------------
    
    865 862
        END_TSO_QUEUE
    

  • rts/Threads.c
    ... ... @@ -379,32 +379,46 @@ migrateThread (Capability *from, StgTSO *tso, Capability *to)
    379 379
        sets or unsets a flag in a given TSO
    
    380 380
        ------------------------------------------------------------------------- */
    
    381 381
     
    
    382
    -#if defined(THREADED_RTS)
    
    383
    -static void
    
    384
    -updThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag, const StgInfoTable* info);
    
    385
    -
    
    386 382
     void setThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag)
    
    387 383
     {
    
    388
    -    updThreadFlag(from, tso, flag, &stg_MSG_SET_TSO_FLAG_info);
    
    384
    +    updThreadFlag(from, tso, flag, true);
    
    389 385
     }
    
    390 386
     
    
    391 387
     void unsetThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag)
    
    392 388
     {
    
    393
    -    updThreadFlag(from, tso, flag, &stg_MSG_UNSET_TSO_FLAG_info);
    
    389
    +    updThreadFlag(from, tso, flag, false);
    
    394 390
     }
    
    395 391
     
    
    396
    -static void
    
    397
    -updThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag, const StgInfoTable* info)
    
    392
    +void
    
    393
    +updThreadFlag(Capability *from USED_IF_THREADS, StgTSO *tso, StgWord32 flag, StgBool set /* true=set, false=unset */)
    
    398 394
     {
    
    399
    -    MessageUpdTSOFlag *msg;
    
    400
    -    msg = (MessageUpdTSOFlag *)allocate(from,sizeofW(MessageUpdTSOFlag));
    
    401
    -    msg->tso  = tso;
    
    402
    -    msg->flag = flag;
    
    403
    -    SET_HDR_RELEASE(msg, info, CCS_SYSTEM);
    
    404
    -    sendMessage(from, tso->cap, (Message*)msg);
    
    405
    -}
    
    395
    +#if defined(THREADED_RTS)
    
    396
    +    // If we're the current owner of the thread we want to modify, do it.
    
    397
    +    // Otherwise, we must forward the message to the actual owner.
    
    398
    +    // When executing the upd message, we check again that we're still the TSO
    
    399
    +    // owner (which may have changed since the message was queued on this cap.)
    
    400
    +    // See Note [TSO owner may change in between Msg being sent and received]
    
    401
    +    Capability *tso_owner = RELAXED_LOAD(&tso->cap);
    
    402
    +    if (from != tso_owner) {
    
    403
    +      MessageUpdTSOFlag *msg;
    
    404
    +      msg = (MessageUpdTSOFlag *)allocate(from,sizeofW(MessageUpdTSOFlag));
    
    405
    +      msg->tso  = tso;
    
    406
    +      msg->flag = flag;
    
    407
    +      msg->set  = set;
    
    408
    +      SET_HDR_RELEASE(msg, &stg_MSG_UPD_TSO_FLAG_info, CCS_SYSTEM);
    
    409
    +      sendMessage(from, tso_owner, (Message*)msg);
    
    410
    +      return;
    
    411
    +    }
    
    406 412
     #endif
    
    407 413
     
    
    414
    +    if (set) {
    
    415
    +      tso->flags |= flag;
    
    416
    +    }
    
    417
    +    else {
    
    418
    +      tso->flags &= ~flag;
    
    419
    +    }
    
    420
    +}
    
    421
    +
    
    408 422
     /* ----------------------------------------------------------------------------
    
    409 423
        awakenBlockedQueue
    
    410 424
     
    

  • rts/Threads.h
    ... ... @@ -19,10 +19,9 @@ void checkBlockingQueues (Capability *cap, StgTSO *tso);
    19 19
     void tryWakeupThread     (Capability *cap, StgTSO *tso);
    
    20 20
     void migrateThread       (Capability *from, StgTSO *tso, Capability *to);
    
    21 21
     
    
    22
    -#if defined(THREADED_RTS)
    
    23 22
     void setThreadFlag       (Capability *from, StgTSO *tso, StgWord32 flag);
    
    24 23
     void unsetThreadFlag     (Capability *from, StgTSO *tso, StgWord32 flag);
    
    25
    -#endif
    
    24
    +void updThreadFlag       (Capability *from, StgTSO *tso, StgWord32 flag, StgBool set);
    
    26 25
     
    
    27 26
     // Wakes up a thread on a Capability (probably a different Capability
    
    28 27
     // from the one held by the current Task).
    

  • rts/include/rts/storage/Closures.h
    ... ... @@ -625,6 +625,7 @@ typedef struct MessageUpdTSOFlag_ {
    625 625
         Message   *link;
    
    626 626
         StgTSO    *tso;
    
    627 627
         StgWord   flag;
    
    628
    +    StgWord   set; // bool: true=SET; false=UNSET
    
    628 629
     } MessageUpdTSOFlag;
    
    629 630
     
    
    630 631
     /* ----------------------------------------------------------------------------
    

  • rts/include/stg/MiscClosures.h
    ... ... @@ -151,8 +151,7 @@ RTS_ENTRY(stg_MSG_TRY_WAKEUP);
    151 151
     RTS_ENTRY(stg_MSG_THROWTO);
    
    152 152
     RTS_ENTRY(stg_MSG_BLACKHOLE);
    
    153 153
     RTS_ENTRY(stg_MSG_CLONE_STACK);
    
    154
    -RTS_ENTRY(stg_MSG_SET_TSO_FLAG);
    
    155
    -RTS_ENTRY(stg_MSG_UNSET_TSO_FLAG);
    
    154
    +RTS_ENTRY(stg_MSG_UPD_TSO_FLAG);
    
    156 155
     RTS_ENTRY(stg_MSG_NULL);
    
    157 156
     RTS_ENTRY(stg_MVAR_TSO_QUEUE);
    
    158 157
     RTS_ENTRY(stg_catch);