Changes between Version 88 and Version 89 of NewGhciDebugger

Apr 12, 2007 3:32:40 PM (8 years ago)



  • NewGhciDebugger

    v88 v89  
    471471This is defined in `runStmt` in `main/GHC.hs`. We "pass" the I/O action to the runtime system by way of a global stable pointer, which is called `breakPointIOAction`. Note that the thread ID is possibly redundant now, but I left it there since it may be useful for other purposes. The I/O action takes two arguments: `ids` and `apStack`. The first argument is the list of local variables names, paired with their stack offsets. We need this information for printing out the local vars. The second argumet is an AP_STACK closure, which contains the top stack frame of the expression thread. This is saved when the thread hits a breakpoint in Interpreter.c. The AP_STACK is used for finding the ''values'' of the local variables of the breakpoint. So, `ids` and `apStack` are used in conjunction for inspecting local variables. Note that the I/O action proceeds to write to the `statusMVar`, which wakes up the GHCi thread, and then it waits on the `breakMVar`.
    473 The last tricky part is how we resume execution of a thread after a breakpoint. This
     473The last tricky part is how we resume execution of a thread after a breakpoint. This is the purpose of the fourth argument of `Runbreak`:
     475   resume :: IO RunResult
     477As you can see it is an I/O action that will eventually yield a `RunResult`. This accords with our intuition that, at least for terminating computations, we will get another `RunResult` if we execute this thing. It could be another breakpoint, or it may be a final value. `resume` is defined like so:
     479   do stablePtr <- newStablePtr onBreakAction
     480      poke breakPointIOAction stablePtr
     481      putMVar breakMVar ()
     482      status <- takeMVar statusMVar
     483      switchOnStatus ref new_hsc_env names status
     485The first thing it does is set up the `onBreakAction` global variable. Then it writes to the `breakMVar` which wakes up the blocked expression thread. Then it waits for `statusMVar` to be filled in again. Eventually when we get a status value, we call the `switchInStatus` function to decide what to do (either we hit another breakpoint, or we completed).
     487I've been a bit crafty in my implementation, and you will notice that `resume` and `onBreakAction` are mutually recursive. So in `main/GHC.runStmt` you will see them defined like this:
     489   let (resume, onBreakAction)
     490          = ( ..., ...)
     492The reason I did it this way is because they need to share their own versions of `breakMVar` and `statusMVar`. This must be understood in the context that we can have nested breakpoints. By writing them in this mutually recursive fashion, we can have multiple (`resume`, `onBreaAction`) pairs, and that they don't get their MVars mixed up.
    475495=== Inspecting values ===