Rodrigo Mesquita pushed to branch wip/romes/per-thread-break-on-exception at Glasgow Haskell Compiler / GHC

Commits:

12 changed files:

Changes:

  • libraries/ghc-heap/GHC/Exts/Heap/FFIClosures_ProfilingDisabled.hsc
    ... ... @@ -93,6 +93,7 @@ parseTsoFlags w | isSet (#const TSO_LOCKED) w = TsoLocked : parseTsoFlags (unset
    93 93
     #if __GLASGOW_HASKELL__ >= 913
    
    94 94
                     | isSet (#const TSO_STOP_NEXT_BREAKPOINT) w = TsoStopNextBreakpoint : parseTsoFlags (unset (#const TSO_STOP_NEXT_BREAKPOINT) w)
    
    95 95
                     | isSet (#const TSO_STOP_AFTER_RETURN) w = TsoStopAfterReturn : parseTsoFlags (unset (#const TSO_STOP_AFTER_RETURN) w)
    
    96
    +                | isSet (#const TSO_STOP_ON_EXCEPTION) w = TsoStopOnException : parseTsoFlags (unset (#const TSO_STOP_ON_EXCEPTION) w)
    
    96 97
     #endif
    
    97 98
     parseTsoFlags 0 = []
    
    98 99
     parseTsoFlags w = [TsoFlagsUnknownValue w]
    

  • libraries/ghc-heap/GHC/Exts/Heap/FFIClosures_ProfilingEnabled.hsc
    ... ... @@ -93,6 +93,7 @@ parseTsoFlags w | isSet (#const TSO_LOCKED) w = TsoLocked : parseTsoFlags (unset
    93 93
     #if __GLASGOW_HASKELL__ >= 913
    
    94 94
                     | isSet (#const TSO_STOP_NEXT_BREAKPOINT) w = TsoStopNextBreakpoint : parseTsoFlags (unset (#const TSO_STOP_NEXT_BREAKPOINT) w)
    
    95 95
                     | isSet (#const TSO_STOP_AFTER_RETURN) w = TsoStopAfterReturn : parseTsoFlags (unset (#const TSO_STOP_AFTER_RETURN) w)
    
    96
    +                | isSet (#const TSO_STOP_ON_EXCEPTION) w = TsoStopOnException : parseTsoFlags (unset (#const TSO_STOP_ON_EXCEPTION) w)
    
    96 97
     #endif
    
    97 98
     parseTsoFlags 0 = []
    
    98 99
     parseTsoFlags w = [TsoFlagsUnknownValue w]
    

  • libraries/ghc-heap/tests/parse_tso_flags.hs
    ... ... @@ -15,5 +15,6 @@ main = do
    15 15
         assertEqual (parseTsoFlags 256) [TsoAllocLimit]
    
    16 16
         assertEqual (parseTsoFlags 512) [TsoStopNextBreakpoint]
    
    17 17
         assertEqual (parseTsoFlags 1024) [TsoStopAfterReturn]
    
    18
    +    assertEqual (parseTsoFlags 2048) [TsoStopOnException]
    
    18 19
     
    
    19 20
         assertEqual (parseTsoFlags 6) [TsoLocked, TsoBlockx]

  • libraries/ghc-internal/src/GHC/Internal/Heap/Closures.hs
    ... ... @@ -632,6 +632,7 @@ data TsoFlags
    632 632
       | TsoAllocLimit
    
    633 633
       | TsoStopNextBreakpoint
    
    634 634
       | TsoStopAfterReturn
    
    635
    +  | TsoStopOnException
    
    635 636
       | TsoFlagsUnknownValue Word32 -- ^ Please report this as a bug
    
    636 637
       deriving (Eq, Show, Generic, Ord)
    
    637 638
     
    

  • libraries/ghci/GHCi/Debugger.hs
    ... ... @@ -13,7 +13,10 @@ module GHCi.Debugger
    13 13
       , rts_disableStopAfterReturn
    
    14 14
     
    
    15 15
       -- * Stop on exception
    
    16
    -  , exceptionFlag
    
    16
    +  , rts_enableStopOnException
    
    17
    +  , rts_disableStopOnException
    
    18
    +  , rts_enableStopOnExceptionAll
    
    19
    +  , rts_disableStopOnExceptionAll
    
    17 20
     
    
    18 21
       -- * Breakpoint Callback
    
    19 22
       , BreakpointCallback
    
    ... ... @@ -23,7 +26,6 @@ module GHCi.Debugger
    23 26
     import Prelude -- See note [Why do we import Prelude here?]
    
    24 27
     
    
    25 28
     import GHC.Base (ThreadId#, Addr#, Int#)
    
    26
    -import Foreign.C (CInt)
    
    27 29
     import Foreign (StablePtr, Ptr)
    
    28 30
     import GHCi.RemoteTypes (HValue)
    
    29 31
     
    
    ... ... @@ -60,7 +62,19 @@ foreign import ccall unsafe "rts_disableStopAfterReturn"
    60 62
     
    
    61 63
     --------------------------------------------------------------------------------
    
    62 64
     
    
    63
    -foreign import ccall "&rts_stop_on_exception" exceptionFlag :: Ptr CInt
    
    65
    +-- | Make this thread break when an exception is hit
    
    66
    +foreign import ccall unsafe "rts_enableStopOnException"  rts_enableStopOnException  :: ThreadId# -> IO ()
    
    67
    +
    
    68
    +-- | No longer have this thread break when an exception is hit
    
    69
    +foreign import ccall unsafe "rts_disableStopOnException" rts_disableStopOnException :: ThreadId# -> IO ()
    
    70
    +
    
    71
    +-- | Enables global break-on-exception for all threads
    
    72
    +foreign import ccall unsafe "rts_enableStopOnExceptionAll"  rts_enableStopOnExceptionAll :: IO ()
    
    73
    +
    
    74
    +-- | Disables the global break-on-exception for all threads. Individual threads
    
    75
    +-- with break-on-exception will still break on exception if the global flag is
    
    76
    +-- disabled.
    
    77
    +foreign import ccall unsafe "rts_disableStopOnExceptionAll" rts_disableStopOnExceptionAll :: IO ()
    
    64 78
     
    
    65 79
     --------------------------------------------------------------------------------
    
    66 80
     
    

  • libraries/ghci/GHCi/Run.hs
    ... ... @@ -269,14 +269,17 @@ rethrow EvalOpts{..} io =
    269 269
       catchNoPropagate io $ \(ExceptionWithContext cx se) -> do
    
    270 270
         -- If -fbreak-on-error, we break unconditionally,
    
    271 271
         --  but with care of not breaking twice
    
    272
    +    ThreadId mytid <- myThreadId
    
    272 273
         if breakOnError && not breakOnException
    
    273
    -       then poke exceptionFlag 1
    
    274
    +       then rts_enableStopOnException mytid
    
    274 275
            else case fromException se of
    
    275 276
                    -- If it is a "UserInterrupt" exception, we allow
    
    276 277
                    --  a possible break by way of -fbreak-on-exception
    
    277 278
                    Just UserInterrupt -> return ()
    
    278 279
                    -- In any other case, we don't want to break
    
    279
    -               _ -> poke exceptionFlag 0
    
    280
    +               _ -> do
    
    281
    +                  rts_disableStopOnException mytid
    
    282
    +                  rts_disableStopOnExceptionAll
    
    280 283
         rethrowIO (ExceptionWithContext cx se)
    
    281 284
     
    
    282 285
     --
    
    ... ... @@ -338,7 +341,11 @@ withBreakAction opts breakMVar statusMVar mtid act
    338 341
        setBreakAction = do
    
    339 342
          stablePtr <- newStablePtr onBreak
    
    340 343
          poke breakPointIOAction stablePtr
    
    341
    -     when (breakOnException opts) $ poke exceptionFlag 1
    
    344
    +     when (breakOnException opts) $ do
    
    345
    +      case mtid of
    
    346
    +        Nothing -> rts_enableStopOnExceptionAll
    
    347
    +        Just (ThreadId tid) -> do
    
    348
    +          rts_enableStopOnException tid
    
    342 349
          when (singleStep opts) rts_enableStopNextBreakpointAll
    
    343 350
          when (stepOut opts) $ do
    
    344 351
           case mtid of
    
    ... ... @@ -380,7 +387,9 @@ withBreakAction opts breakMVar statusMVar mtid act
    380 387
     
    
    381 388
        resetBreakAction stablePtr = do
    
    382 389
          poke breakPointIOAction noBreakStablePtr
    
    383
    -     poke exceptionFlag 0
    
    390
    +     case mtid of
    
    391
    +      Just (ThreadId tid) -> rts_disableStopOnException tid
    
    392
    +      _                   -> rts_disableStopOnExceptionAll
    
    384 393
          rts_disableStopNextBreakpointAll
    
    385 394
          case mtid of
    
    386 395
           Just (ThreadId tid) -> rts_disableStopAfterReturn tid
    

  • rts/Exception.cmm
    ... ... @@ -523,14 +523,16 @@ retry_pop_stack:
    523 523
         if (W_[no_break_on_exception] != 0) {
    
    524 524
             W_[no_break_on_exception] = 0;
    
    525 525
         } else {
    
    526
    -        if (TO_W_(CInt[rts_stop_on_exception]) != 0) {
    
    526
    +        if (TO_W_(CInt[rts_stop_on_exception]) != 0 ||
    
    527
    +            (TO_W_(StgTSO_flags(CurrentTSO)) & TSO_STOP_ON_EXCEPTION) != 0) {
    
    527 528
                 W_ ioAction;
    
    528 529
                 // we don't want any further exceptions to be caught,
    
    529 530
                 // until GHCi is ready to handle them.  This prevents
    
    530 531
                 // deadlock if an exception is raised in InteractiveUI,
    
    531
    -            // for example.  Perhaps the stop_on_exception flag should
    
    532
    -            // be per-thread.
    
    532
    +            // for example.
    
    533 533
                 CInt[rts_stop_on_exception] = 0;
    
    534
    +            StgTSO_flags(CurrentTSO) = %lobits32(
    
    535
    +              TO_W_(StgTSO_flags(CurrentTSO)) & ~TSO_STOP_ON_EXCEPTION);
    
    534 536
                 ("ptr" ioAction) = ccall deRefStablePtr (W_[rts_breakpoint_io_action] "ptr");
    
    535 537
                 Sp = Sp - WDS(11);
    
    536 538
                 Sp(10) = exception;
    

  • rts/Interpreter.c
    ... ... @@ -388,8 +388,6 @@ is_ret_bco_frame(const StgPtr frame_head) {
    388 388
           );
    
    389 389
     }
    
    390 390
     
    
    391
    -int rts_stop_on_exception = 0;
    
    392
    -
    
    393 391
     /* ---------------------------------------------------------------------------
    
    394 392
      * Enabling and disabling global single step mode
    
    395 393
      * ------------------------------------------------------------------------ */
    
    ... ... @@ -398,7 +396,7 @@ int rts_stop_on_exception = 0;
    398 396
      * Unlike `TSO_STOP_NEXT_BREAKPOINT`, which sets single-step mode per-thread,
    
    399 397
      * `rts_stop_next_breakpoint` globally enables single-step mode. If enabled, we
    
    400 398
      * will stop at the immediate next breakpoint regardless of what thread it is in. */
    
    401
    -int rts_stop_next_breakpoint = 0;
    
    399
    +static int rts_stop_next_breakpoint = 0;
    
    402 400
     
    
    403 401
     void rts_enableStopNextBreakpointAll(void)
    
    404 402
     {
    
    ... ... @@ -473,7 +471,50 @@ A limitation of this approach is that stepping-out of a function that was
    473 471
     tail-called will skip its caller since no stack frame is pushed for a tail
    
    474 472
     call (i.e. a tail call returns directly to its caller's first non-tail caller).
    
    475 473
     */
    
    476
    -/* -------------------------------------------------------------------------- */
    
    474
    +
    
    475
    +/* ---------------------------------------------------------------------------
    
    476
    + * Enabling and disabling global break-on-exception
    
    477
    + * ------------------------------------------------------------------------ */
    
    478
    +
    
    479
    +/* A global toggle for break-on-exception
    
    480
    +
    
    481
    +   Unlike `TSO_STOP_ON_EXCEPTION`, which breaks when an exception is raised in
    
    482
    +   this thread, the global toggle makes an exception raised in any thread yield
    
    483
    +   a breakpoint in that thread.
    
    484
    +
    
    485
    +   Currently, this is necessary if we ever want to break on an exception raised
    
    486
    +   in thread forked by the main debuggee thead: we can only toggle TSO_STOP_ON_EXCEPTION
    
    487
    +   on threads we control, and those forked by the debuggee we don't.
    
    488
    + */
    
    489
    +int rts_stop_on_exception = 0;
    
    490
    +
    
    491
    +void rts_enableStopOnExceptionAll(void)
    
    492
    +{
    
    493
    +  rts_stop_on_exception = 1;
    
    494
    +}
    
    495
    +
    
    496
    +void rts_disableStopOnExceptionAll(void)
    
    497
    +{
    
    498
    +  rts_stop_on_exception = 0;
    
    499
    +}
    
    500
    +
    
    501
    +/* ---------------------------------------------------------------------------
    
    502
    + * Enabling and disabling per-thread break-on-exception
    
    503
    + * ------------------------------------------------------------------------ */
    
    504
    +
    
    505
    +void rts_enableStopOnException(StgTSO* tso)
    
    506
    +{
    
    507
    +  Capability* cap = rts_unsafeGetMyCapability();
    
    508
    +  setThreadFlag(cap, tso, TSO_STOP_ON_EXCEPTION);
    
    509
    +}
    
    510
    +
    
    511
    +void rts_disableStopOnException(StgTSO* tso)
    
    512
    +{
    
    513
    +  Capability* cap = rts_unsafeGetMyCapability();
    
    514
    +  unsetThreadFlag(cap, tso, TSO_STOP_ON_EXCEPTION);
    
    515
    +}
    
    516
    +
    
    517
    +/* ------------------------------------------------------------------------ */
    
    477 518
     
    
    478 519
     #if defined(INTERP_STATS)
    
    479 520
     
    

  • rts/Interpreter.h
    ... ... @@ -12,6 +12,11 @@ RTS_PRIVATE Capability *interpretBCO (Capability* cap);
    12 12
     void interp_startup ( void );
    
    13 13
     void interp_shutdown ( void );
    
    14 14
     
    
    15
    +// The following debugger functions are exported from here, but not from the
    
    16
    +// RTS public api (RtsApi.h). They are used by the `ghci` library to implement
    
    17
    +// debugger commands on the interpreter like step-next, step-out, and
    
    18
    +// break-on-exception.
    
    19
    +
    
    15 20
     // Debugger single step
    
    16 21
     void rts_enableStopNextBreakpointAll  ( void );
    
    17 22
     void rts_disableStopNextBreakpointAll ( void );
    
    ... ... @@ -21,3 +26,9 @@ void rts_disableStopNextBreakpoint ( StgTSO* );
    21 26
     // Debugger step out
    
    22 27
     void rts_enableStopAfterReturn        ( StgTSO* );
    
    23 28
     void rts_disableStopAfterReturn       ( StgTSO* );
    
    29
    +
    
    30
    +// Debugger stop on exception
    
    31
    +void rts_enableStopOnException        ( StgTSO* );
    
    32
    +void rts_disableStopOnException       ( StgTSO* );
    
    33
    +void rts_enableStopOnExceptionAll     ( void );
    
    34
    +void rts_disableStopOnExceptionAll    ( void );

  • rts/RtsSymbols.c
    ... ... @@ -942,14 +942,16 @@ extern char **environ;
    942 942
           SymI_HasProto(revertCAFs)                                         \
    
    943 943
           SymI_HasDataProto(RtsFlags)                                           \
    
    944 944
           SymI_NeedsDataProto(rts_breakpoint_io_action)                     \
    
    945
    -      SymI_NeedsDataProto(rts_stop_next_breakpoint)                     \
    
    946
    -      SymI_NeedsDataProto(rts_stop_on_exception)                        \
    
    947 945
           SymI_NeedsProto(rts_enableStopNextBreakpointAll)                  \
    
    948 946
           SymI_NeedsProto(rts_disableStopNextBreakpointAll)                 \
    
    949 947
           SymI_NeedsProto(rts_enableStopNextBreakpoint)                     \
    
    950 948
           SymI_NeedsProto(rts_disableStopNextBreakpoint)                    \
    
    951 949
           SymI_NeedsProto(rts_enableStopAfterReturn)                        \
    
    952 950
           SymI_NeedsProto(rts_disableStopAfterReturn)                       \
    
    951
    +      SymI_NeedsProto(rts_enableStopOnException)                        \
    
    952
    +      SymI_NeedsProto(rts_disableStopOnException)                       \
    
    953
    +      SymI_NeedsProto(rts_enableStopOnExceptionAll)                     \
    
    954
    +      SymI_NeedsProto(rts_disableStopOnExceptionAll)                    \
    
    953 955
           SymI_HasProto(stopTimer)                                          \
    
    954 956
           SymI_HasDataProto(n_capabilities)                                     \
    
    955 957
           SymI_HasDataProto(max_n_capabilities)                                 \
    

  • rts/include/rts/Constants.h
    ... ... @@ -394,6 +394,11 @@
    394 394
      */
    
    395 395
     #define TSO_STOP_AFTER_RETURN 1024
    
    396 396
     
    
    397
    +/*
    
    398
    + * Enables break-on-exception mode for this thread
    
    399
    + */
    
    400
    +#define TSO_STOP_ON_EXCEPTION 2048
    
    401
    +
    
    397 402
     /*
    
    398 403
      * The number of times we spin in a spin lock before yielding (see
    
    399 404
      * #3758).  To tune this value, use the benchmark in #3758: run the
    

  • rts/include/stg/MiscClosures.h
    ... ... @@ -583,7 +583,6 @@ RTS_FUN_DECL(stg_annotateStackzh);
    583 583
     #if IN_STG_CODE && !IN_STGCRUN
    
    584 584
     
    
    585 585
     // Interpreter.c
    
    586
    -extern StgWord rts_stop_next_breakpoint[];
    
    587 586
     extern StgWord rts_stop_on_exception[];
    
    588 587
     extern StgWord rts_breakpoint_io_action[];
    
    589 588