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

Commits:

12 changed files:

Changes:

  • changelog.d/T27131
    1
    +section: rts
    
    2
    +synopsis: Add rts Message to set/unset TSO flags
    
    3
    +issues: #27131
    
    4
    +mrs: !15831
    
    5
    +description: This enables e.g. toggling breakpoints from different threads,
    
    6
    +    which is necessary to safely implement features like pausing, per-thread
    
    7
    +    step-in, and more in the haskell debugger.
    
    8
    +

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

  • rts/Messages.c
    ... ... @@ -35,7 +35,9 @@ void sendMessage(Capability *from_cap, Capability *to_cap, Message *msg)
    35 35
                 i != &stg_MSG_TRY_WAKEUP_info &&
    
    36 36
                 i != &stg_IND_info && // can happen if a MSG_BLACKHOLE is revoked
    
    37 37
                 i != &stg_WHITEHOLE_info &&
    
    38
    -            i != &stg_MSG_CLONE_STACK_info) {
    
    38
    +            i != &stg_MSG_CLONE_STACK_info &&
    
    39
    +            i != &stg_MSG_SET_TSO_FLAG_info &&
    
    40
    +            i != &stg_MSG_UNSET_TSO_FLAG_info) {
    
    39 41
                 barf("sendMessage: %p", i);
    
    40 42
             }
    
    41 43
         }
    
    ... ... @@ -137,6 +139,16 @@ loop:
    137 139
             MessageCloneStack *cloneStackMessage = (MessageCloneStack*) m;
    
    138 140
             handleCloneStackMessage(cap, cloneStackMessage);
    
    139 141
         }
    
    142
    +    else if(i == &stg_MSG_SET_TSO_FLAG_info){
    
    143
    +        MessageUpdTSOFlag *u = (MessageUpdTSOFlag*) m;
    
    144
    +        u->tso->flags |= u->flag;
    
    145
    +        return;
    
    146
    +    }
    
    147
    +    else if(i == &stg_MSG_UNSET_TSO_FLAG_info){
    
    148
    +        MessageUpdTSOFlag *u = (MessageUpdTSOFlag*) m;
    
    149
    +        u->tso->flags &= ~u->flag;
    
    150
    +        return;
    
    151
    +    }
    
    140 152
         else
    
    141 153
         {
    
    142 154
             barf("executeMessage: %p", i);
    

  • rts/StgMiscClosures.cmm
    ... ... @@ -855,6 +855,12 @@ 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; }
    
    863
    +
    
    858 864
     /* ----------------------------------------------------------------------------
    
    859 865
        END_TSO_QUEUE
    
    860 866
     
    

  • rts/Threads.c
    ... ... @@ -376,6 +376,38 @@ migrateThread (Capability *from, StgTSO *tso, Capability *to)
    376 376
         tryWakeupThread(from, tso);
    
    377 377
     }
    
    378 378
     
    
    379
    +/* ----------------------------------------------------------------------------
    
    380
    +   {set,unset}ThreadFlag
    
    381
    +
    
    382
    +   sets or unsets a flag in a given TSO
    
    383
    +   ------------------------------------------------------------------------- */
    
    384
    +
    
    385
    +#if defined(THREADED_RTS)
    
    386
    +static void
    
    387
    +updThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag, const StgInfoTable* info);
    
    388
    +
    
    389
    +void setThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag)
    
    390
    +{
    
    391
    +    updThreadFlag(from, tso, flag, &stg_MSG_SET_TSO_FLAG_info);
    
    392
    +}
    
    393
    +
    
    394
    +void unsetThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag)
    
    395
    +{
    
    396
    +    updThreadFlag(from, tso, flag, &stg_MSG_UNSET_TSO_FLAG_info);
    
    397
    +}
    
    398
    +
    
    399
    +static void
    
    400
    +updThreadFlag(Capability *from, StgTSO *tso, StgWord32 flag, const StgInfoTable* info)
    
    401
    +{
    
    402
    +    MessageUpdTSOFlag *msg;
    
    403
    +    msg = (MessageUpdTSOFlag *)allocate(from,sizeofW(MessageUpdTSOFlag));
    
    404
    +    msg->tso  = tso;
    
    405
    +    msg->flag = flag;
    
    406
    +    SET_HDR_RELEASE(msg, info, CCS_SYSTEM);
    
    407
    +    sendMessage(from, tso->cap, (Message*)msg);
    
    408
    +}
    
    409
    +#endif
    
    410
    +
    
    379 411
     /* ----------------------------------------------------------------------------
    
    380 412
        awakenBlockedQueue
    
    381 413
     
    

  • rts/Threads.h
    ... ... @@ -19,6 +19,11 @@ 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
    +void setThreadFlag       (Capability *from, StgTSO *tso, StgWord32 flag);
    
    24
    +void unsetThreadFlag     (Capability *from, StgTSO *tso, StgWord32 flag);
    
    25
    +#endif
    
    26
    +
    
    22 27
     // Wakes up a thread on a Capability (probably a different Capability
    
    23 28
     // from the one held by the current Task).
    
    24 29
     //
    

  • rts/include/rts/storage/Closures.h
    ... ... @@ -620,6 +620,12 @@ typedef struct MessageCloneStack_ {
    620 620
         StgTSO    *tso;
    
    621 621
     } MessageCloneStack;
    
    622 622
     
    
    623
    +typedef struct MessageUpdTSOFlag_ {
    
    624
    +    StgHeader header;
    
    625
    +    Message   *link;
    
    626
    +    StgTSO    *tso;
    
    627
    +    StgWord   flag;
    
    628
    +} MessageUpdTSOFlag;
    
    623 629
     
    
    624 630
     /* ----------------------------------------------------------------------------
    
    625 631
        Compact Regions
    

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

  • testsuite/tests/rts/T27131.hs
    1
    +{-# LANGUAGE MagicHash #-}
    
    2
    +{-# LANGUAGE UnliftedFFITypes #-}
    
    3
    +
    
    4
    +module Main where
    
    5
    +
    
    6
    +import Control.Concurrent
    
    7
    +import Control.Monad
    
    8
    +import Foreign.C.Types
    
    9
    +import GHC.Conc.Sync (ThreadId(..), forkOn, myThreadId, setNumCapabilities)
    
    10
    +import GHC.Exts (ThreadId#)
    
    11
    +
    
    12
    +foreign import ccall unsafe "rts_enableStopNextBreakpoint"
    
    13
    +  rts_enableStopNextBreakpoint :: ThreadId# -> IO ()
    
    14
    +
    
    15
    +foreign import ccall unsafe "rts_disableStopNextBreakpoint"
    
    16
    +  rts_disableStopNextBreakpoint :: ThreadId# -> IO ()
    
    17
    +
    
    18
    +foreign import ccall unsafe "rts_enableStopAfterReturn"
    
    19
    +  rts_enableStopAfterReturn :: ThreadId# -> IO ()
    
    20
    +
    
    21
    +foreign import ccall unsafe "rts_disableStopAfterReturn"
    
    22
    +  rts_disableStopAfterReturn :: ThreadId# -> IO ()
    
    23
    +
    
    24
    +foreign import ccall unsafe "has_local_stop_next_breakpoint"
    
    25
    +  c_hasLocalStopNextBreakpoint :: IO CInt
    
    26
    +
    
    27
    +foreign import ccall unsafe "has_local_stop_after_return"
    
    28
    +  c_hasLocalStopAfterReturn :: IO CInt
    
    29
    +
    
    30
    +main :: IO ()
    
    31
    +main = do
    
    32
    +  setNumCapabilities 2
    
    33
    +  checkFlag
    
    34
    +    "TSO_STOP_NEXT_BREAKPOINT"
    
    35
    +    rts_enableStopNextBreakpoint
    
    36
    +    rts_disableStopNextBreakpoint
    
    37
    +    c_hasLocalStopNextBreakpoint
    
    38
    +  checkFlag
    
    39
    +    "TSO_STOP_AFTER_RETURN"
    
    40
    +    rts_enableStopAfterReturn
    
    41
    +    rts_disableStopAfterReturn
    
    42
    +    c_hasLocalStopAfterReturn
    
    43
    +
    
    44
    +checkFlag
    
    45
    +  :: String
    
    46
    +  -> (ThreadId# -> IO ())
    
    47
    +  -> (ThreadId# -> IO ())
    
    48
    +  -> IO CInt
    
    49
    +  -> IO ()
    
    50
    +checkFlag label enable disable isMyThreadFlagSet = do
    
    51
    +  -- Print the main thread's capability (should be 0)
    
    52
    +  print =<< threadCapability =<< myThreadId
    
    53
    +
    
    54
    +  -- Target thread will write its own flag value here
    
    55
    +  targetCheckVar <- newEmptyMVar
    
    56
    +
    
    57
    +  -- Run the new TSO runs on capability 1
    
    58
    +  ThreadId tid# <- forkOn 1 $ do
    
    59
    +    replicateM_ 2 $ do
    
    60
    +      replyVar <- takeMVar targetCheckVar
    
    61
    +      isSet <- (/= 0) <$> isMyThreadFlagSet
    
    62
    +      putMVar replyVar isSet
    
    63
    +
    
    64
    +  -- Enable the other TSO's flag
    
    65
    +  enable tid#
    
    66
    +  -- It will check whether it is set and reply here
    
    67
    +  renderCheck label "set" =<< checkTarget targetCheckVar
    
    68
    +
    
    69
    +  -- Ditto.
    
    70
    +  disable tid#
    
    71
    +  renderCheck label "unset" . not =<< checkTarget targetCheckVar
    
    72
    +
    
    73
    +checkTarget :: MVar (MVar Bool) -> IO Bool
    
    74
    +checkTarget targetCheckVar = do
    
    75
    +  replyVar <- newEmptyMVar
    
    76
    +  putMVar targetCheckVar replyVar
    
    77
    +  takeMVar replyVar
    
    78
    +
    
    79
    +renderCheck :: String -> String -> Bool -> IO ()
    
    80
    +renderCheck label state ok = putStrLn $
    
    81
    +  label ++ " " ++ state ++ ": " ++ if ok then "ok" else "failed"

  • testsuite/tests/rts/T27131.stdout
    1
    +(0,False)
    
    2
    +TSO_STOP_NEXT_BREAKPOINT set: ok
    
    3
    +TSO_STOP_NEXT_BREAKPOINT unset: ok
    
    4
    +(0,False)
    
    5
    +TSO_STOP_AFTER_RETURN set: ok
    
    6
    +TSO_STOP_AFTER_RETURN unset: ok

  • testsuite/tests/rts/T27131_c.c
    1
    +#include "Rts.h"
    
    2
    +
    
    3
    +int has_local_stop_next_breakpoint(void)
    
    4
    +{
    
    5
    +    CapabilityPublic *cap = (CapabilityPublic *) rts_unsafeGetMyCapability();
    
    6
    +    StgTSO *tso = cap->r.rCurrentTSO;
    
    7
    +    return (tso->flags & TSO_STOP_NEXT_BREAKPOINT) != 0;
    
    8
    +}
    
    9
    +
    
    10
    +int has_local_stop_after_return(void)
    
    11
    +{
    
    12
    +    CapabilityPublic *cap = (CapabilityPublic *) rts_unsafeGetMyCapability();
    
    13
    +    StgTSO *tso = cap->r.rCurrentTSO;
    
    14
    +    return (tso->flags & TSO_STOP_AFTER_RETURN) != 0;
    
    15
    +}

  • testsuite/tests/rts/all.T
    ... ... @@ -623,6 +623,13 @@ test('T20201b', [js_skip, exit_code(1)], compile_and_run, ['-with-rtsopts -A64z'
    623 623
     
    
    624 624
     test('T22012', [js_skip, extra_ways(['ghci'])], compile_and_run, ['T22012_c.c'])
    
    625 625
     
    
    626
    +test('T27131',
    
    627
    +     [ only_ways(['threaded1', 'threaded2'])
    
    628
    +     , req_ghc_with_threaded_rts
    
    629
    +     , req_target_smp
    
    630
    +     ],
    
    631
    +     compile_and_run, ['T27131_c.c'])
    
    632
    +
    
    626 633
     # Skip for JS platform as the JS RTS is always single threaded
    
    627 634
     test('T22795a', [only_ways(['normal']), js_skip, req_ghc_with_threaded_rts], compile_and_run, ['-threaded'])
    
    628 635
     test('T22795b', [only_ways(['normal']), js_skip], compile_and_run, ['-single-threaded'])