Changes between Version 88 and Version 89 of NewGhciDebugger


Ignore:
Timestamp:
Apr 12, 2007 3:32:40 PM (7 years ago)
Author:
guest
Comment:

--

Legend:

Unmodified
Added
Removed
Modified
  • 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`.  
    472472 
    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`: 
     474{{{ 
     475   resume :: IO RunResult 
     476}}} 
     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: 
     478{{{ 
     479   do stablePtr <- newStablePtr onBreakAction 
     480      poke breakPointIOAction stablePtr 
     481      putMVar breakMVar () 
     482      status <- takeMVar statusMVar 
     483      switchOnStatus ref new_hsc_env names status 
     484}}} 
     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).  
     486 
     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: 
     488{{{ 
     489   let (resume, onBreakAction) 
     490          = ( ..., ...) 
     491}}} 
     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.  
     493              
    474494 
    475495=== Inspecting values ===