[896] | 1 | TMGIDE3 ;TMG/kst/A debugger/tracer for GT.M (Controller code) ;04/14/08
|
---|
| 2 | ;;1.0;TMG-LIB;**1**;03/23/09
|
---|
| 3 |
|
---|
| 4 | ;" TMG IDE Debugger Controller
|
---|
| 5 | ;"
|
---|
| 6 | ;" K. Toppenberg
|
---|
| 7 | ;" 4-14-2008
|
---|
| 8 | ;" License: GPL Applies
|
---|
| 9 | ;"
|
---|
| 10 | ;"------------------------------------------------------------
|
---|
| 11 | ;"------------------------------------------------------------
|
---|
| 12 | ;"Notes: HOW DOES IT ALL WORK?
|
---|
| 13 | ;"
|
---|
| 14 | ;"Here is how the system fits together:
|
---|
| 15 | ;"
|
---|
| 16 | ;"Below is what happens in the CONTROLLING job
|
---|
| 17 | ;"=================================================
|
---|
| 18 | ;" -- LaunchIntr^TMGIDE5(JobNum) sets up a signaling global and then
|
---|
| 19 | ;" creates a 'mupip intrpt JobNum', then starts listening
|
---|
| 20 | ;" in Controller^TMGIDE3 for communication from the interrupted job.
|
---|
| 21 | ;" (See below about how this communication gets started)
|
---|
| 22 | ;" -- Controller^TMGIDE3 polls a communicating global location and can talk back
|
---|
| 23 | ;" and forth with the other job. When it gets a message to
|
---|
| 24 | ;" DO TRAP %ZPOS, it then calls STEPTRAP^TMGIDE2, and returns
|
---|
| 25 | ;" the result of that function back to the other job.
|
---|
| 26 | ;" -- STEPTRAP^TMGIDE2 is the same interface as the prior debugger. It shows
|
---|
| 27 | ;" the code, allows the user to move around, and interact
|
---|
| 28 | ;" with the code. If the user wants to query variables
|
---|
| 29 | ;" in the other process, then a message is sent out, and
|
---|
| 30 | ;" a copy of that variable is passed back here for display.
|
---|
| 31 | ;" If the user wants to modify the other environment, then
|
---|
| 32 | ;" arbitrary M code can be entered by the user, and it is passed
|
---|
| 33 | ;" to the other job for execution in that job process space.
|
---|
| 34 | ;" When ready to execute the next line of code, then STEPTRAP
|
---|
| 35 | ;" quits with a result signalling a zstep INTO or OVER.
|
---|
| 36 | ;"
|
---|
| 37 | ;"Below is what happens in the OTHER job
|
---|
| 38 | ;"=================================================
|
---|
| 39 | ;" -- mupip intrpt JobNum --> causes the specified job to execute the code
|
---|
| 40 | ;" stored in $ZINTERRUPT. For VistA (or if setup in
|
---|
| 41 | ;" in an environmental script during GT.M launch), this
|
---|
| 42 | ;" code is to run JOBEXAM^ZU (slightly customized)
|
---|
| 43 | ;" -- JOBEXAM^ZU --> looks for signaling global, and if found runs INTERUPT^TMGIDE5
|
---|
| 44 | ;" -- INTERUPT^TMGIDE5 --> sets up $ZSTEP and then calls ZSTEP INTO and
|
---|
| 45 | ;" quits out of the $ZINTERRUPT code.
|
---|
| 46 | ;" -- ZSTEP --> causes GT.M to execute the code in $ZSTEP before performing
|
---|
| 47 | ;" the next line of mumps code for the program that was
|
---|
| 48 | ;" running at the time the interrupt request was received.
|
---|
| 49 | ;" -- $ZSTEP holds instruction to run $$STEPTRAP^TMGIDE4($ZPOS)
|
---|
| 50 | ;" -- STEPTRAP^TMGIDE4 --> sends message to CONTROLLING JOB and waits for reply.
|
---|
| 51 | ;" Reply will either be a request from the user for more
|
---|
| 52 | ;" information from this job, or a final reply that allows
|
---|
| 53 | ;" execution to continue, either by a step INTO, OVER, or
|
---|
| 54 | ;" a plain ZCONTINUE (which will stop further code-stepping)
|
---|
| 55 |
|
---|
| 56 |
|
---|
| 57 | Controller
|
---|
| 58 | ;"Purpose: This code will wait for messages from the executing process, and
|
---|
| 59 | ;" will display the code as it changes, and send messages back to
|
---|
| 60 | ;" all the user to control the process remotely.
|
---|
| 61 |
|
---|
| 62 | ;"Notice: There are
|
---|
| 63 |
|
---|
| 64 | ;"A globally-scoped var that will be checked in STEPTRAP^TMGIDE2
|
---|
| 65 | if +$get(tmgDbgRemoteJob)'>0 set tmgDbgRemoteJob=1
|
---|
| 66 |
|
---|
| 67 | ;"write #
|
---|
| 68 | new i for i=1:1:12 write !
|
---|
| 69 | write "=== TMG IDE Controller (Job# "_$JOB_") ===",!,!
|
---|
| 70 | write "Waiting for action from SENDING (Remote) process (ESC to abort)",!
|
---|
| 71 | new msgRef set msgRef=$name(^TMG("TMGIDE","CONTROLLER"))
|
---|
| 72 | kill @msgRef
|
---|
| 73 | set @msgRef@("JOB")=$JOB
|
---|
| 74 |
|
---|
| 75 | new Msg,UsrInput,Cmd
|
---|
| 76 | new hangDelay set hangDelay=0.2
|
---|
| 77 |
|
---|
| 78 | new ideBlankLine set $piece(ideBlankLine," ",78)=" "
|
---|
| 79 | ;"new HxSize set HxSize=8 ;"hard codes in history length of 8
|
---|
| 80 | new TMGdbgLine
|
---|
| 81 | new TMGlastline set TMGlastLine=""
|
---|
| 82 | new HxShowNum set HxShowNum=0
|
---|
| 83 | new HxLine,HxLineMax,HxLineCur
|
---|
| 84 | do INITKB^XGF() ;"set up keyboard input escape code processing
|
---|
| 85 | ;
|
---|
| 86 | Init set @msgRef@("STATUS")="AVAIL"
|
---|
| 87 | set @msgRef@("MSG-OUT")=""
|
---|
| 88 | new TMGstartH set TMGstartH=$piece($H,",",2)
|
---|
| 89 | new tempCh,%
|
---|
| 90 | ;
|
---|
| 91 | Loop set Msg=$get(@msgRef@("MSG-IN"))
|
---|
| 92 | set Cmd=$piece(Msg," ",1)
|
---|
| 93 | ;
|
---|
| 94 | if Cmd="INQ" do HndlINQ(Msg) goto Loop
|
---|
| 95 | if Cmd="LISTEN" do HndlListen(Msg) goto Loop
|
---|
| 96 | if Cmd="DONE" do HndlDone(Msg) goto LstnDone ;"This is when SENDER signals a quit.
|
---|
| 97 | if Cmd="WRITE" do HndlWrite(Msg) goto Loop
|
---|
| 98 | if Cmd="DO" goto:($$HndlDo(Msg)'=0) Loop goto LstnDone ;"Leave if CONTROLLER signals a quit
|
---|
| 99 | if Cmd="READ" do HndlRead(Msg) goto Loop
|
---|
| 100 | if Cmd="NEED" do HndlNeed(Msg) goto Loop
|
---|
| 101 | ;
|
---|
| 102 | ;"Checking UserAborted grabs keystrokes, and prevents user from getting out of RUN mode
|
---|
| 103 | ;"in ^TMGIDE2, so only check here after an X second delay.
|
---|
| 104 | if $piece($H,",",2)-TMGstartH<2 goto Loop
|
---|
| 105 | read *tempCh:0
|
---|
| 106 | if tempCh'=27 goto Loop
|
---|
| 107 | write !,"Abort From Remote Debugging Controller"
|
---|
| 108 | set TMGstartH=$piece($H,",",2)
|
---|
| 109 | set %=2 do YN^DICN write !
|
---|
| 110 | if %'=1 goto Loop
|
---|
| 111 | ;
|
---|
| 112 | LstnDone ;
|
---|
| 113 | write !,"Quitting.",!
|
---|
| 114 | kill @msgRef
|
---|
| 115 | kill tmgDbgRemoteJob
|
---|
| 116 | quit
|
---|
| 117 | ;
|
---|
| 118 | ;"-------------------------------
|
---|
| 119 | ;"-------------------------------
|
---|
| 120 | ;
|
---|
| 121 | ACK SET @msgRef@("MSG-OUT")="ACK "_$J
|
---|
| 122 | SET @msgRef@("MSG-IN")=""
|
---|
| 123 | QUIT
|
---|
| 124 |
|
---|
| 125 | HndlINQ(Msg) ;"Expects 'INQ <Job#>'
|
---|
| 126 | ;"write "Msg=",Msg,! ;"temp!!
|
---|
| 127 | set tmgDbgRemoteJob=+$piece(Msg," ",2)
|
---|
| 128 | do ACK
|
---|
| 129 | quit
|
---|
| 130 |
|
---|
| 131 | HndlListen(Msg)
|
---|
| 132 | new JobToControl
|
---|
| 133 | set JobToControl=+$piece(Msg," ",3)
|
---|
| 134 | set @msgRef@("STATUS")="LISTENING TO "_JobToControl
|
---|
| 135 | set @msgRef@("MSG-OUT")=@msgRef@("STATUS")
|
---|
| 136 | DO ACK
|
---|
| 137 | quit
|
---|
| 138 |
|
---|
| 139 | HndlWrite(Msg)
|
---|
| 140 | write $piece(Msg," ",2,99),!
|
---|
| 141 | DO ACK
|
---|
| 142 | quit
|
---|
| 143 |
|
---|
| 144 | HndlDo(Msg)
|
---|
| 145 | ;"Purpose: Handle message from interrupted application to DO something.
|
---|
| 146 | ;"Result: 1 = OK to continue
|
---|
| 147 | ;" 0 = should quit controller.
|
---|
| 148 | new result set result=1 ;"default to continue
|
---|
| 149 | new msgResult set msgResult=""
|
---|
| 150 | if $piece(Msg," ",2)="PROMPT" do
|
---|
| 151 | . set msgResult=$$Prompt()
|
---|
| 152 | else if $piece(Msg," ",2)="TRAP" do
|
---|
| 153 | . new idePos set idePos=$piece(Msg," ",3)
|
---|
| 154 | . new TMGMsg set TMGMsg=$piece(Msg," ",4)
|
---|
| 155 | . set msgResult=$$STEPTRAP^TMGIDE2(idePos,TMGMsg)
|
---|
| 156 | . if msgResult=0 set result=0 ;"STEPTRAP result of 0 means to stop controller.
|
---|
| 157 | set @msgRef@("MSG-OUT")=msgResult
|
---|
| 158 | set @msgRef@("MSG-IN")=""
|
---|
| 159 | set TMGstartH=$piece($H,",",2) ;"restart timer countdown before allowing user input.
|
---|
| 160 | quit result
|
---|
| 161 |
|
---|
| 162 | HndlDone(Msg)
|
---|
| 163 | DO ACK
|
---|
| 164 | quit
|
---|
| 165 |
|
---|
| 166 | HndlRead(Msg)
|
---|
| 167 | new result
|
---|
| 168 | write $piece(Msg," ",2,99)
|
---|
| 169 | read result:$get(DTIME,3600),!
|
---|
| 170 | if result="" set result="<null>"
|
---|
| 171 | set @msgRef@("MSG-OUT")=result
|
---|
| 172 | set @msgRef@("MSG-IN")=""
|
---|
| 173 | quit
|
---|
| 174 |
|
---|
| 175 | HndlNeed(Msg)
|
---|
| 176 | set SndJob=+$piece(Msg," ",3)
|
---|
| 177 | set @MsgRef@("STATUS")="CONTROLLING "_SndJob
|
---|
| 178 | set @MsgRef@("MSG-OUT")=@MsgCtrlRef@("STATUS")
|
---|
| 179 | quit
|
---|
| 180 |
|
---|
| 181 | ;"-------------------------------------------------------------------
|
---|
| 182 |
|
---|
| 183 | Prompt()
|
---|
| 184 | ;"Purpose: to interact with user and run through code.
|
---|
| 185 |
|
---|
| 186 | ;"new i write # for i=1:1:12 write !
|
---|
| 187 | write "=== TMG IDE Controller ===",!,!
|
---|
| 188 |
|
---|
| 189 | Ppt2
|
---|
| 190 | set HxShowNum=+$get(HxShowNum)
|
---|
| 191 | set TMGStepMode="into" ;"kt added 5/3/06
|
---|
| 192 | set HxLine=$get(^TMG("TMGIDE","CMD HISTORY",$J,HxShowNum))
|
---|
| 193 | set HxLineMax=$get(^TMG("TMGIDE","CMD HISTORY",$J,"MAX"),0)
|
---|
| 194 |
|
---|
| 195 | write "Remote command (^ to quit): "
|
---|
| 196 | if HxShowNum=0 write "^// "
|
---|
| 197 | else write "// ",HxLine
|
---|
| 198 |
|
---|
| 199 | set TMGdbgLine=$$READ^TMGIDE() ;"$$READ^XGF ;"returns line terminator in tmgXGRT
|
---|
| 200 | set tmgXGRT=$get(tmgXGRT) ;"ensure existence
|
---|
| 201 | if TMGdbgLine="?" do goto Ppt2
|
---|
| 202 | . write !,"Here you should enter any valid M command, as would normally",!
|
---|
| 203 | . write "entered at a GTM> prompt.",!
|
---|
| 204 | . write " examples: WRITE ""HELLO"",! or DO ^TMGTEST",!
|
---|
| 205 |
|
---|
| 206 | if (TMGdbgLine="")&(HxShowNum>0) set TMGdbgLine=HxLine
|
---|
| 207 |
|
---|
| 208 | if (tmgXGRT="DOWN")!(tmgXGRT="RIGHT")!(TMGdbgLine="]") do goto Ppt2
|
---|
| 209 | . set HxShowNum=HxShowNum-1
|
---|
| 210 | . if HxShowNum<0 set HxShowNum=HxLineMax
|
---|
| 211 | . ;"write "setting HxShowNum=",HxShowNum,!
|
---|
| 212 | . do CHA^TMGTERM(1) write ideBlankLine do CHA^TMGTERM(1)
|
---|
| 213 |
|
---|
| 214 | if (tmgXGRT="UP")!(tmgXGRT="LEFT")!(TMGdbgLine="[") do goto Ppt2
|
---|
| 215 | . set HxShowNum=HxShowNum+1
|
---|
| 216 | . if HxShowNum>HxLineMax set HxShowNum=0
|
---|
| 217 | . ;"write "setting HxShowNum=",HxShowNum,!
|
---|
| 218 | . do CHA^TMGTERM(1) write ideBlankLine do CHA^TMGTERM(1)
|
---|
| 219 |
|
---|
| 220 | if TMGdbgLine="" set TMGdbgLine="^"
|
---|
| 221 | write !
|
---|
| 222 |
|
---|
| 223 | ;"Save Cmd history
|
---|
| 224 | set HxLineCur=$get(^TMG("TMGIDE","CMD HISTORY",$J,"CUR"),0) ;"<-- points to last used, not next avail
|
---|
| 225 | set HxLineMax=$get(^TMG("TMGIDE","CMD HISTORY",$J,"MAX"),0) ;"equals buffer size AFTER it fills
|
---|
| 226 | set HxLineCur=HxLineCur+1
|
---|
| 227 | ;"if HxLineCur>HxSize set HxLineCur=1
|
---|
| 228 | set ^TMG("TMGIDE","CMD HISTORY",$J,HxLineCur)=TMGdbgLine
|
---|
| 229 | set ^TMG("TMGIDE","CMD HISTORY",$J,"CUR")=HxLineCur
|
---|
| 230 | if HxLineCur>HxLineMax do
|
---|
| 231 | . set HxLineMax=HxLineCur
|
---|
| 232 | . set ^TMG("TMGIDE","CMD HISTORY",$J,"MAX")=HxLineMax
|
---|
| 233 | ;"write "Saving line in #",HxLineCur," Max=",HxLineMax,!
|
---|
| 234 |
|
---|
| 235 | quit TMGdbgLine
|
---|