HistorySpyCommandsImpl.mesa
Copyright Ó 1990, 1991 by Xerox Corporation. All rights reserved.
Michael Plass, December 13, 1991 4:12 pm PST
Chauser, December 8, 1992 2:27 pm PST
DIRECTORY IO, PFS, HistorySpy, Commander, Convert, RefText, Rope, CommanderOps, CardTab;
HistorySpyCommandsImpl: CEDAR MONITOR
IMPORTS IO, PFS, HistorySpy, Commander, Convert, RefText, CommanderOps, CardTab
~ BEGIN
ROPE: TYPE ~ Rope.ROPE;
StartCommand: Commander.CommandProc ~ {
nodeCount: NAT ¬ 10000;
IF NOT HistorySpy.Start[nodeCount, 10000] THEN CommanderOps.Failed["Spy already running!"];
};
StopCommand: Commander.CommandProc ~ {
spy: HistorySpy.Ref ¬ HistorySpy.Stop[];
stream: IO.STREAM ¬ cmd.out;
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF spy = NIL THEN CommanderOps.Failed["Spy not running!"];
IF arg # NIL THEN {
ENABLE PFS.Error => {
IO.PutF1[cmd.err, "PFS.Error[%g] - writing to standard out instead\n", [rope[error.explanation]]];
GOTO Recovery;
};
stream ¬ PFS.StreamOpen[PFS.PathFromRope[arg], $create];
EXITS Recovery => {};
};
HistorySpy.WriteTree[stream, spy ! UNWIND => {IF stream # cmd.out THEN IO.Close[stream]}];
IO.PutChar[stream, '\n];
IF stream # cmd.out THEN IO.Close[stream];
};
HaltCommand: Commander.CommandProc ~ {
spy: HistorySpy.Ref ¬ HistorySpy.Stop[];
stream: IO.STREAM ¬ cmd.out;
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF spy = NIL THEN CommanderOps.Failed["Spy not running!"];
lastSpy ¬ spy;
IF arg # NIL THEN {
CommanderOps.Failed["Halt takes no arguments--argument ignored"];
};
};
lastSpy: HistorySpy.Ref;
WriteCommand: Commander.CommandProc ~ {
spy: HistorySpy.Ref ¬ lastSpy;
stream: IO.STREAM ¬ cmd.out;
arg: ROPE ~ CommanderOps.NextArgument[cmd];
IF spy = NIL THEN CommanderOps.Failed["No saved spy!"];
IF arg # NIL THEN {
ENABLE PFS.Error => {
IO.PutF1[cmd.err, "PFS.Error[%g] - writing to standard out instead\n", [rope[error.explanation]]];
GOTO Recovery;
};
stream ¬ PFS.StreamOpen[PFS.PathFromRope[arg], $create];
EXITS Recovery => {};
};
HistorySpy.WriteTree[stream, spy ! UNWIND => {IF stream # cmd.out THEN IO.Close[stream]}];
IO.PutChar[stream, '\n];
IF stream # cmd.out THEN IO.Close[stream];
lastSpy ¬ NIL;
};
ReadSpyCounts: PROC [table: CardTab.Ref, stream: IO.STREAM] ~ {
buffer: REF TEXT ¬ NEW[TEXT[80]];
tokenKind: IO.TokenKind;
charsSkipped: INT;
error: IO.TokenError;
state: {init, count, name, pc, offset, post} ¬ init;
nest: INT ¬ 0;
count, pc, offset: CARD ¬ 0;
DO
[tokenKind, buffer, charsSkipped, error] ¬ IO.GetCedarToken[stream: stream, buffer: buffer, flushComments: FALSE];
SELECT tokenKind FROM
tokenSINGLE => {
SELECT buffer[0] FROM
'; => { [] ¬ IO.GetLine[stream, buffer]; LOOP };
'( => {
IF NOT (state=init OR state=post) THEN GOTO ParseFailed;
state ¬ count;
nest ¬ nest + 1;
};
') => {
IF NOT (state=post) THEN GOTO ParseFailed;
nest ¬ nest - 1;
IF nest < 0 THEN GOTO ParseFailed;
};
ENDCASE => GOTO ParseFailed;
};
tokenDECIMAL => {
value: CARD ¬ Convert.CardFromRope[RefText.TrustTextAsRope[buffer]];
SELECT state FROM
count => count ¬ value;
pc => pc ¬ value;
offset => offset ¬ value;
ENDCASE => GOTO ParseFailed;
state ¬ state.SUCC;
IF state = post THEN {
Tally: CardTab.UpdateAction ~ {
PROC [found: BOOL, val: Val] RETURNS [op: UpdateOperation ← none, new: Val ← NIL]
c: REF CARD ¬ IF found THEN NARROW[val] ELSE NEW[CARD ¬ 0];
c­ ¬ c­ + count;
IF NOT found THEN RETURN [store, c]
};
CardTab.Update[table, pc+offset, Tally];
};
};
tokenID => {
IF state # name THEN GOTO ParseFailed;
state ¬ state.SUCC;
};
tokenROPE => {
IF state # name THEN GOTO ParseFailed;
state ¬ state.SUCC;
};
tokenEOF => {
EXIT;
};
ENDCASE => GOTO ParseFailed;
ENDLOOP;
IF nest # 0 THEN GOTO ParseFailed;
EXITS ParseFailed => {
CommanderOps.Failed[IO.PutFR1["Parse error near %g", [integer[IO.GetIndex[stream]]]]];
};
};
Commander.Register["HistorySpyStart", StartCommand, "Start the spy. Arguments:\n-a  => watch allocations\n-w => watch words allocated\n-t  => watch thread switches (default)\n-s => watch SIGNALs and ERRORs\n-n <n> => preallocate n spy tree nodes (default 10000)"];
Commander.Register["HistorySpyStop", StopCommand, "Stop the spy, write results to specified file (or to standard out, if no argument is provided)."];
Commander.Register["HistorySpyHalt", HaltCommand, "Stop the spy, without writing the results)."];
Commander.Register["HistorySpyWrite", WriteCommand, "Write the results from the last halt)."];
END.