DIRECTORY FS USING [Close, OpenOrCreate, nullOpenFile, OpenFile, Read, SetPageCount, Write], Loader USING [MakeGlobalFrameResident, MakeGlobalFrameSwappable, MakeProcedureResident, MakeProcedureSwappable], PrincOps USING [BytePC, FrameHandle, GFTIndex, PsbHandle, wordsPerPage], PrincOpsUtils USING [GetClockPulses, GetReturnFrame, LongCOPY, ReadPSB], Process USING [GetPriority, Priority, priorityForeground, SetPriority], Rope USING [ROPE], SpyLog, VM USING [AddressForPageNumber, Allocate, Free, Interval, nullInterval, PageNumber, PageNumberForAddress, Pin, Unpin]; SpyLogImpl: MONITOR IMPORTS FS, Loader, PrincOpsUtils, Process, VM EXPORTS SpyLog = BEGIN OPEN SpyLog; active: PUBLIC BOOLEAN _ FALSE; -- true iff we are writing to the log. Error: PUBLIC ERROR = CODE; Log: TYPE = REF LogDesc; -- want it pinned in the global frame LogDesc: TYPE = RECORD [ base: EntryBasePointer _ NIL, index: EntryPointer _ FIRST[EntryPointer], file: FS.OpenFile _ FS.nullOpenFile, fileName: Rope.ROPE _ NIL, filePage: INT _ 0, buffer: VM.Interval _ VM.nullInterval, next: VM.Interval _ VM.nullInterval, bufferProcess: PROCESS _ NIL]; EntryBasePointer: TYPE = LONG ORDERED BASE POINTER; EntryPointer: TYPE = EntryBasePointer RELATIVE POINTER [0..177777B] TO Entry; bufferPages: CARDINAL = 40; limit: EntryPointer = LOOPHOLE[bufferPages*PrincOps.wordsPerPage]; log1: Log = NEW[LogDesc _ [fileName: "spy.log"]]; log2: Log = NEW[LogDesc _ [fileName: "spyingonspy.log"]]; Init: PROC = BEGIN Pin: PROC[ref: REF, length: CARDINAL] = BEGIN page1: VM.PageNumber = VM.PageNumberForAddress[LOOPHOLE[LOOPHOLE[ref, LONG CARDINAL]-2]]; page2: VM.PageNumber = VM.PageNumberForAddress[LOOPHOLE[LOOPHOLE[ref, LONG CARDINAL]+length]]; VM.Pin[[page1, page2-page1+1]]; END; Pin[log1, LogDesc.SIZE]; Pin[log2, LogDesc.SIZE]; OpenLog[log1]; END; OpenForRead: PUBLIC ENTRY PROC = BEGIN IF readLog # NIL THEN RETURN; -- already have a log IF writeLog # NIL THEN { -- read from the write log FinalizeWriteLog[writeLog]; readLog _ writeLog; writeLog _ NIL}; IF readLog = NIL AND log1.file # FS.nullOpenFile THEN readLog _ log1; -- use the last log IF readLog = NIL THEN { -- create a dummy log (the one on the disk isn't valid) InitializeWriteLog[readLog _ log1]; FinalizeWriteLog[readLog]}; MakeSwappable[]; readLog.filePage _ 0; readLog.index _ limit; END; OpenForWrite: PUBLIC ENTRY PROC[spyOnSpyLog: BOOLEAN] = BEGIN IF ~spyOnSpyLog THEN writeLog _ log1 ELSE { readLog _ log1; readLog.filePage _ 0; readLog.index _ limit; writeLog _ log2}; InitializeWriteLog[writeLog]; MakeResident[]; END; Close: PUBLIC ENTRY PROC = BEGIN IF readLog # NIL THEN readLog _ NIL; IF writeLog = log1 THEN {FinalizeWriteLog[writeLog]; writeLog _ NIL}; IF writeLog = NIL THEN MakeSwappable[]; END; InitializeWriteLog: PROC[log: Log] = BEGIN -- initialize the log for writing IF log.file = FS.nullOpenFile THEN OpenLog[log]; VM.Pin[log.buffer]; VM.Pin[log.next]; log.base _ LOOPHOLE[VM.AddressForPageNumber[log.buffer.page]]; log.index _ FIRST[EntryPointer]; log.filePage _ 0; END; FinalizeWriteLog: PROC[log: Log] = BEGIN IF log.bufferProcess # NIL THEN { -- wait until it is done JOIN log.bufferProcess; log.bufferProcess _ NIL}; log.base[log.index] _ [endOfLog[]]; FS.SetPageCount[log.file, log.filePage + bufferPages]; FS.Write[log.file, log.filePage, bufferPages, log.base]; VM.Unpin[log.buffer]; VM.Unpin[log.next]; END; OpenLog: PROC[log: Log] = BEGIN IF log.file # FS.nullOpenFile THEN RETURN; log.file _ FS.OpenOrCreate[name: log.fileName, pages: 2*bufferPages]; log.buffer _ VM.Allocate[bufferPages]; log.next _ VM.Allocate[bufferPages]; END; CloseLog: PROC [log: Log] = BEGIN IF log.file = FS.nullOpenFile THEN RETURN; FS.Close[log.file]; log.file _ FS.nullOpenFile; VM.Free[log.buffer]; log.buffer _ VM.nullInterval; VM.Free[log.next]; log.next _ VM.nullInterval; END; MakeResident: PROC = BEGIN IF ~active THEN { Loader.MakeGlobalFrameResident[WriteData]; Loader.MakeProcedureResident[WriteData]; Loader.MakeProcedureResident[WriteTrace]; Loader.MakeProcedureResident[NextWriteBuffer]; active _ TRUE}; END; MakeSwappable: PROC = BEGIN IF active THEN { active _ FALSE; Loader.MakeGlobalFrameSwappable[WriteData]; Loader.MakeProcedureSwappable[WriteData]; Loader.MakeProcedureSwappable[WriteTrace]; Loader.MakeProcedureSwappable[NextWriteBuffer]}; END; readLog, writeLog: Log _ NIL; NextEntry: PUBLIC ENTRY PROC RETURNS[entry: LONG POINTER TO Entry] = BEGIN IF readLog = NIL THEN Error; IF GreaterEqual[readLog.index, limit] THEN { FS.Read[readLog.file, readLog.filePage, bufferPages, readLog.base]; readLog.filePage _ readLog.filePage + bufferPages; readLog.index _ FIRST[EntryPointer]; IF readLog.base[readLog.index].type = nullEntry THEN ERROR}; entry _ @readLog.base[readLog.index]; WITH entry: entry SELECT FROM endOfLog => NULL; trace => readLog.index _ readLog.index + SIZE[trace Entry]; data => readLog.index _ readLog.index + SIZE[data Entry] + entry.size; nullEntry => readLog.index _ limit; ENDCASE => ERROR; RETURN[entry]; END; WriteData: PUBLIC ENTRY PROC [data: LONG POINTER, size: [0..8000], type: CARDINAL] = BEGIN entrySize: CARDINAL = SIZE[data Entry] + size; IF writeLog = NIL THEN RETURN; IF GreaterEqual[writeLog.index + entrySize, limit] THEN { NextWriteBuffer[writeLog]; writeLog.index _ FIRST[EntryPointer]}; writeLog.base[writeLog.index] _ [data[size, type, PrincOpsUtils.GetClockPulses[],]]; WITH e: writeLog.base[writeLog.index] SELECT FROM data => PrincOpsUtils.LongCOPY[data, size, @e.data]; ENDCASE => ERROR; writeLog.index _ writeLog.index + entrySize; END; WriteTrace: PUBLIC ENTRY PROC [gfi: PrincOps.GFTIndex, pc: PrincOps.BytePC] = BEGIN process: PrincOps.PsbHandle; entrySize: CARDINAL = SIZE[trace Entry]; IF writeLog = NIL THEN RETURN; IF GreaterEqual[writeLog.index+SIZE[trace Entry], limit] THEN { NextWriteBuffer[writeLog]; writeLog.index _ FIRST[EntryPointer]}; IF gfi = 0 AND pc = 0 THEN { frame: PrincOps.FrameHandle = PrincOpsUtils.GetReturnFrame[]; gfi _ frame.accesslink.gfi; pc _ frame.pc}; process _ PrincOpsUtils.ReadPSB[]; writeLog.base[writeLog.index] _ [trace[, gfi, pc, process, PrincOpsUtils.GetClockPulses[]]]; writeLog.index _ writeLog.index + entrySize; END; NextWriteBuffer: PROCEDURE[log: Log] = BEGIN temp: VM.Interval; log.base[log.index] _ [nullEntry[limit-log.index]]; IF log.bufferProcess # NIL THEN {JOIN log.bufferProcess; log.bufferProcess _ NIL}; log.bufferProcess _ FORK WriteBuffer[log, log.filePage, log.base]; temp _ log.buffer; log.buffer _ log.next; log.next _ temp; log.base _ LOOPHOLE[VM.AddressForPageNumber[log.buffer.page]]; log.filePage _ log.filePage + bufferPages; END; WriteBuffer: PROC[log: Log, filePage: INT, base: EntryBasePointer] = BEGIN priority: Process.Priority _ Process.GetPriority[]; IF priority > Process.priorityForeground THEN Process.SetPriority[Process.priorityForeground]; FS.SetPageCount[log.file, filePage + bufferPages]; FS.Write[log.file, filePage, bufferPages, base]; END; GreaterEqual: PROCEDURE[a,b: UNSPECIFIED] RETURNS[BOOLEAN] = INLINE BEGIN RETURN[LOOPHOLE[a,CARDINAL]>=LOOPHOLE[b,CARDINAL]]; END; Init[]; END. . . &SpyLogImpl.mesa Last Modified by: John Maxwell November 28, 1983 2:49 pm ************************************************************ -- control ************************************************************ don't close the alternate log IF log1.file # FS.nullOpenFile THEN CloseLog[log1]; IF log2.file # FS.nullOpenFile AND log2 # writeLog THEN CloseLog[log2]; ************************************************************ -- reading and writing ************************************************************ move the index to the next entry are we at the end of the buffer? write out the entry. are we at the end of the buffer? write out the entry. wait until next buffer is written, then fork a write update the indices IF priority > Process.priorityForeground THEN Process.SetPriority[priority]; Ê Ú˜Jšœ™Jšœ9™9J™šÏk ˜ JšœœJ˜RJšœœd˜pJšœ œ:˜HJšœœ5˜HJšœœ:˜GJšœœœ˜Jšœ˜Jšœœn˜v—J˜šœ ˜Jšœœ"˜.Jšœ ˜Jšœ˜ —J˜JšœœœœÏc&˜FJšœœœœ˜J˜Jšœœœ ž%˜?šœ œœ˜Jšœœ˜Jšœœ˜*Jšœœ œ˜%Jšœœœ˜Jšœ œ˜Jšœœ œ˜&Jšœœ œ˜$Jšœœœ˜—Jš œœœœœœ˜3Jš œœœœœ˜MJ˜Jšœ<™Jšœ œ˜ J˜Jšœ˜J˜—šŸœœ ˜#Jš˜šœœœž˜:Jšœ(œ˜1—J˜#Jšœ4˜6Jšœ6˜8Jšœ˜Jšœ˜Jšœ˜J˜—šŸœœ ˜Jšœ œœœ˜*Jšœ œ8˜EJšœ œ˜&Jšœ œ˜$Jšœ˜J˜—šŸœœ˜!Jšœ œœœ˜*Jšœœ˜/Jšœ œ˜2Jšœœ˜.Jšœ˜J˜—šŸ œœ˜Jš˜šœ œ˜Jšœ*˜*J˜(J˜)Jšœ.˜.Jšœ œ˜—Jšœ˜J˜—šŸ œœ˜Jš˜šœœ˜Jšœ œ˜Jšœ+˜+Jšœ)˜)Jšœ*˜*Jšœ0˜0—Jšœ˜—J™Jšœ<™Jšœ*˜*Jšœ˜—J˜šŸ œœœ˜JJšœ3˜3Jšœ'œ1˜^Jšœ0˜2Jšœ.˜0Jšœ'œ™LJšœ˜J˜—š Ÿ œ œ œœœ˜CJšœœœœœœœ˜>—J˜J˜J˜Jšœ˜J˜J˜—…—Ø(Ø