SpyLog.mesa
Copyright © 1985 by Xerox Corporation. All rights reserved.
Maxwell, September 16, 1983 11:07 am
Russ Atkinson (RRA) March 31, 1986 2:23:17 pm PST
DIRECTORY
AMTypes USING [nullType],
IO USING [STREAM],
PrincOps USING [BytePC, GlobalFrameHandle, PsbHandle];
SpyLog: DEFINITIONS = BEGIN
The Spy log is a fast means of logging information. It is guaranteed not to cause any page faults or allocations for the client process. It is implemented with two pinned buffers, one of which is being written out to the disk by a separate process while the other is being filled with data. Normally there is only one log, which can be written or read, but not both. Calling OpenForRead with spyOnSpyLog = TRUE will create a second log that can be written to while the first log is being read. After the first log is read, calling OpenForRead again will open the second log for reading.
************************************************************
-- control
************************************************************
active: READONLY BOOL; -- true iff the spy is open for writing.
OpenForRead: PROC;
Opens the spy log for reading.
OpenForWrite: PROC[spyOnSpyLog: BOOLFALSE];
Opens the spy log for writing. If spyOnSpyLog is TRUE, then use the secondary log.
Close: PROC;
Unpins the buffers and the module. Does not destroy any information. There is no need to close the log if you are just going to re-open it in a different mode.
Print: PROC[stream: IO.STREAMNIL];
************************************************************
-- reading and writing
************************************************************
Entry: TYPE = MACHINE DEPENDENT RECORD[
SELECT type:{endOfLog, nullEntry, trace, data} FROM
endOfLog => [fill: [0..16000)𡤀], -- marks the end of valid data
nullEntry => [size: [0..16000)𡤀], -- indicates data to be skipped (used internally).
trace => [ -- 6 words
fill: [0..16000)𡤀,
gfh: PrincOps.GlobalFrameHandle,
pc: PrincOps.BytePC,
process: PrincOps.PsbHandle,
timestamp: LONG CARDINAL],
data => [ -- 4 words + size
size: [0..16000),
rttype: CARDINAL,
timestamp: LONG CARDINAL,
data: SEQUENCE COMPUTED CARDINAL OF WORD],
ENDCASE];
NextEntry: PROC RETURNS[LONG POINTER TO Entry];
Moves the index to the next entry. The last entry will contain [endOfLog[]]. Raises Error if the spy log is not open for reading.
WriteData: PROC [data: LONG POINTER, size: [0..8000], type: CARDINAL ← AMTypes.nullType];
Examples: WriteData[@foo, SIZE[Foo], CODE[Foo]]; WriteData[@data, size].
The system will store the type and use it to print the data. This doesn't slow down the spying; the costs are incurred when the log is printed. The type cannot be ref-containing. Raises Error if the spy log is not open for writing.
WriteTrace: PROC [gfh: PrincOps.GlobalFrameHandle ← NIL, pc: PrincOps.BytePC ← [0]];
Records the gfh and pc. This will be printed as a procedure and pc.
Defaults to the gfh and pc of the calling procedure. Raises Error if the spy log is not open for writing.
Here: PROC = INLINE {IF active THEN WriteTrace[]};
Very cheap if the log isn't activated.
Error: ERROR;
END.