-- XDPsbPack.mesa
-- Edited by:
-- Sandman on July 22, 1980 3:02 PM
-- Bruce on October 8, 1980 6:52 PM
DIRECTORY
Actions USING [CallInterpreter],
Ascii USING [CR, DEL, SP],
ComData USING [typeLOCK, typeCONDITION],
Commands USING [GetComment, Prompt, Umbrella],
DebugOps USING [
fileSW, Foo, Interpret, InvalidNumber, LongREAD, ShortCopyREAD, ShortREAD,
StringExpToOctal],
DI USING [Foo, GetNumber, GetValue, Number, TypeForSe],
DOutput USING [Char, EOL, Line, Octal, Text],
DPsb USING [Handle],
Frames USING [Invalid],
Init USING [CheckSymTabLength, TopLevel],
Inline USING [COPY],
Lf USING [Display, GF, Handle, NoPrevious, PC, Previous],
MachineDefs USING [FHandle, Priority],
PrincOps USING [StateVector],
ProcessDefs USING [DefaultPriority, Priority],
ProcessOps USING [
CurrentPSB, FirstProcess, FirstStateVector, LastProcess, Queue, ReadyList],
PSBDefs USING [Empty, MonitorLock, PSB],
Source USING [Display],
State USING [GetGS, GSHandle, SetParse],
Storage USING [Free, Node],
String USING [UpperCase],
SymbolTable USING [Missing],
Table USING [Overflow],
TextSW USING [BlinkingCaret];
XDPsbPack: PROGRAM
IMPORTS
Actions, com: ComData, Commands, DebugOps, DI, DOutput,
Init, Inline, Frames, Lf, Source, st: State, Storage, String,
SymbolTable, Table, TextSW
EXPORTS Commands, DPsb =
BEGIN OPEN MachineDefs;
PSB: TYPE = PSBDefs.PSB;
Handle: TYPE = DPsb.Handle;
NotAnXfer: ERROR = CODE;
Invalid: PUBLIC SIGNAL [psb: Handle] = CODE;
data: st.GSHandle ← st.GetGS[];
Head: POINTER TO PItem ← NIL;
lastRead: PSB;
first: Handle ← NIL;
last: Handle ← NIL;
current: Handle ← NIL;
PItem: TYPE = RECORD [
link: POINTER TO PItem,
p: Handle,
psb: PSB];
Read: PUBLIC PROCEDURE [p: Handle] RETURNS [local: Handle] =
BEGIN
l: POINTER TO PItem;
Check[p];
IF (l ← CheckCache[p]) # NIL THEN RETURN[@l.psb];
DebugOps.ShortCopyREAD[from: p, to: @lastRead, nwords: SIZE[PSB]];
RETURN[IF lastRead.state # dead THEN @Cache[p].l.psb ELSE @lastRead];
END;
CheckCache: PROCEDURE [p: Handle] RETURNS [l: POINTER TO PItem] =
BEGIN
FOR l ← Head, l.link UNTIL l = NIL DO
IF l.p = p THEN RETURN;
ENDLOOP;
END;
Cache: PROCEDURE [p: Handle] RETURNS [l: POINTER TO PItem] =
BEGIN
IF (l ← CheckCache[p]) # NIL THEN RETURN;
l ← Storage.Node[SIZE[PItem]];
l↑ ← [link: Head, p: p, psb:];
Head ← l;
Inline.COPY[from: @lastRead, to: @l.psb, nwords: SIZE[PSB]];
END;
ResetCache: PUBLIC PROCEDURE =
BEGIN OPEN ProcessOps;
p, next: POINTER TO PItem;
FOR p ← Head, next UNTIL p = NIL DO
next ← p.link;
Storage.Free[p];
ENDLOOP;
first ← DebugOps.ShortREAD[FirstProcess];
last ← DebugOps.ShortREAD[LastProcess];
current ← DebugOps.ShortREAD[CurrentPSB];
Head ← NIL;
END;
First: PUBLIC PROC RETURNS [Handle] = {RETURN[first]};
Last: PUBLIC PROC RETURNS [Handle] = {RETURN[last]};
Current: PUBLIC PROC RETURNS [Handle] = {RETURN[current]};
Next: PUBLIC PROC [psb: Handle] RETURNS [Handle] =
BEGIN
head: Handle ← psb;
Check[psb];
DO
psb ← IF psb # last THEN psb+SIZE[PSB] ELSE first;
IF psb = head THEN RETURN[NIL];
IF Validate[psb] AND StateOK[psb] THEN RETURN[psb];
ENDLOOP;
END;
Check: PUBLIC PROC [p: Handle] =
BEGIN IF ~Validate[p] THEN SIGNAL Invalid[p] END;
Validate: PUBLIC PROCEDURE [p: Handle] RETURNS [BOOLEAN] =
BEGIN
IF LOOPHOLE[p,CARDINAL] < LOOPHOLE[first,CARDINAL]
OR LOOPHOLE[p,CARDINAL] > LOOPHOLE[last,CARDINAL] THEN RETURN[FALSE];
RETURN[
LOOPHOLE[(p-LOOPHOLE[first, CARDINAL]), CARDINAL] MOD SIZE[PSB] = 0]
END;
Priority: PUBLIC PROCEDURE [p: Handle] RETURNS [MachineDefs.Priority] =
BEGIN RETURN[Read[p].local.priority] END;
WaitingCV: PUBLIC PROCEDURE [p: Handle] RETURNS [BOOLEAN] =
BEGIN
p1: Handle ← Read[p];
RETURN[~p1.enterFailed AND p1.waitingOnCV]
END;
WaitingML: PUBLIC PROCEDURE [p: Handle] RETURNS [BOOLEAN] =
BEGIN RETURN[Read[p].local.enterFailed] END;
Running: PUBLIC PROCEDURE [p: Handle] RETURNS [BOOLEAN] =
BEGIN
p1: Handle ← Read[p];
RETURN[~p1.enterFailed AND ~p1.waitingOnCV AND p1.state = alive]
END;
Frame: PUBLIC PROC [psb: Handle] RETURNS [MachineDefs.FHandle] =
--get the frame for the currently running process from the StateVector
BEGIN
RETURN[IF psb # current THEN Read[psb].local.frame
ELSE DebugOps.LongREAD[@State[].sv.dest]]
END;
State: PUBLIC PROC RETURNS [sv: LONG POINTER TO PrincOps.StateVector] =
BEGIN OPEN DebugOps, ProcessOps;
priority: CARDINAL;
fsv: POINTER;
IF Head = NIL THEN current ← ShortREAD[CurrentPSB];
priority ←
IF Validate[current] THEN Priority[current] ELSE ProcessDefs.DefaultPriority;
fsv ← ShortREAD[FirstStateVector];
RETURN[LONG[fsv + priority*SIZE[PrincOps.StateVector]]]
END;
StateOK: PROCEDURE [psb: Handle] RETURNS [BOOLEAN] =
BEGIN RETURN[Read[psb].local.state # dead] END;
ListProcesses: PUBLIC PROCEDURE =
BEGIN
i: Handle ← last;
DO
i ← Next[i];
DumpPSB[i]; DOutput.EOL[];
IF i = last THEN EXIT;
ENDLOOP;
RETURN
END;
StackType: TYPE = {process, queue};
dumping: StackType;
headPSB, currentPSB, qHead: Handle;
Caret: PROC = {DOutput.EOL[]; DOutput.Text[" >"L]};
DumpStack: PROCEDURE [psb: Handle, s: StackType] =
BEGIN
headPSB ← currentPSB ← psb;
dumping ← s;
Caret[];
st.SetParse[StackCommands];
RETURN
END;
prompt: BOOLEAN;
StackCommands: PROCEDURE [char: CHARACTER] = {
prompt ← TRUE;
Init.TopLevel[];
Commands.Umbrella[process, char];
IF prompt THEN {Caret[]; TextSW.BlinkingCaret[DebugOps.fileSW, on]}};
UProcess: PUBLIC PROCEDURE [char: CHARACTER] =
BEGIN ENABLE Table.Overflow => {Init.CheckSymTabLength[]; RETRY};
IF char # Ascii.SP AND char # Ascii.DEL THEN {
DOutput.Char[char]; TextSW.BlinkingCaret[DebugOps.fileSW, off]};
SELECT String.UpperCase[char] FROM
'N => {
currentPSB ←
IF dumping = process THEN Next[currentPSB]
ELSE DebugOps.ShortREAD[@currentPSB.link];
IF currentPSB = headPSB OR currentPSB = NIL THEN {
Commands.Prompt[]; prompt ← FALSE}
ELSE DumpPSB[currentPSB]};
'P => DumpPriority[currentPSB];
'Q, Ascii.DEL => {Commands.Prompt[]; prompt ← FALSE};
'R => DumpRoot[currentPSB];
'L => IF dumping = process THEN DumpSource[currentPSB, FALSE] ELSE BadChar[];
'S => IF dumping = process THEN DumpSource[currentPSB, TRUE] ELSE BadChar[];
Ascii.SP => {Actions.CallInterpreter[]; prompt ← FALSE};
'- => {Commands.GetComment[FALSE]; prompt ← FALSE};
'? => DOutput.Text[IF dumping = process THEN
" --Options are: List source, Next, Priority, Quit, Root, Source"L
ELSE " --Options are: Next, Priority, Quit, Root"L];
ENDCASE => BadChar[];
END;
BadChar: PROC = {DOutput.Char['?]};
DisplayReadyList: PUBLIC PROCEDURE =
{qHead ← DebugOps.ShortREAD[ProcessOps.ReadyList]; DumpQueue[FALSE]};
DumpQueue: PROCEDURE [condition: BOOLEAN] =
BEGIN
IF (qHead ← StartQueue[condition]) = NIL THEN
BEGIN
DOutput.Text[" Queue empty!"L];
Commands.Prompt[];
RETURN
END;
DumpPSB[qHead];
DumpStack[qHead, queue];
RETURN
END;
StartQueue: PROCEDURE [condition: BOOLEAN] RETURNS [Handle] =
BEGIN
cleanupLink, local: Handle;
IF qHead = NIL THEN RETURN[NIL];
local ← Read[qHead];
cleanupLink ← local.cleanup;
IF ~condition OR cleanupLink = NIL THEN RETURN[local.link];
UNTIL cleanupLink = NIL OR cleanupLink = qHead DO
qHead ← cleanupLink;
cleanupLink ← DebugOps.ShortREAD[@cleanupLink.cleanup];
ENDLOOP;
RETURN[IF cleanupLink = NIL THEN qHead ELSE NIL];
END;
DisplayProcess: PUBLIC PROCEDURE [p: STRING] =
BEGIN
psb: Handle;
DumpPSB[psb ← StringToPSB[p]];
DumpStack[psb, process];
RETURN
END;
DumpPSB: PROCEDURE [psb: Handle] =
BEGIN
f: MachineDefs.FHandle;
Check[psb]; DOutput.EOL[];
DOutput.Text["PSB: "L];
DOutput.Octal[psb]; IF psb = current THEN DOutput.Char['*];
DOutput.Text[", "L];
SELECT TRUE FROM
WaitingML[psb] => DOutput.Text["waiting ML, "L];
WaitingCV[psb] => DOutput.Text["waiting CV, "L];
ENDCASE;
IF (f ← Frame[psb]) = NIL THEN DOutput.Line["No frame!"L]
ELSE Lf.Display[f ! Frames.Invalid =>
{DOutput.Octal[f]; DOutput.Text[" is not a valid frame!"L]; CONTINUE}];
RETURN
END;
DumpSource: PROCEDURE [psb: Handle, loadSource: BOOLEAN]=
BEGIN
frame: MachineDefs.FHandle ← Frame[psb];
DOutput.EOL[];
Source.Display[Lf.GF[frame], Lf.PC[frame], loadSource !
SymbolTable.Missing--[seg]-- => {DOutput.Text[" No symbol table."L]; CONTINUE}];
RETURN
END;
DumpRoot: PROCEDURE [psb: Handle] =
BEGIN
f: MachineDefs.FHandle ← Frame[psb];
DO
f ← Lf.Previous[f ! Lf.NoPrevious => EXIT];
ENDLOOP;
IF f = NIL THEN RETURN;
DOutput.EOL[];
Lf.Display[f];
RETURN
END;
DumpPriority: PROCEDURE [psb: Handle] =
BEGIN DOutput.Text["riority "L]; DOutput.Octal[Priority[psb]] END;
StringToPSB: PROCEDURE [p: STRING] RETURNS [psb: Handle] =
BEGIN
psb ← NIL;
psb ← LOOPHOLE[
DebugOps.StringExpToOctal[p ! DebugOps.InvalidNumber => CONTINUE]];
IF psb # NIL THEN Check[psb];
END;
CheckCondition: PROCEDURE [char: CHARACTER] = {
SELECT char FROM
'y, 'Y, Ascii.CR => {DOutput.Line["yes"L]; DumpQueue[TRUE]};
ENDCASE => {DOutput.Line["no"L]; DumpQueue[FALSE]} };
DisplayQueue: PUBLIC PROC [q: STRING] = {
condition: BOOLEAN;
call: BOOLEAN ← TRUE;
FindQueue: PROCEDURE [f: DebugOps.Foo] = {
PSBBase: CARDINAL = 0;
mLock: PSBDefs.MonitorLock;
n: DI.Number;
DI.GetValue[f];
SELECT DI.TypeForSe[f.tsei] FROM
com.typeLOCK => {condition ← FALSE; mLock ← f.addr.base↑};
com.typeCONDITION => {condition ← TRUE; mLock ← f.addr.base↑};
ENDCASE => {
call ← FALSE;
n ← DI.GetNumber[f];
IF n.type = one THEN
mLock ← DebugOps.ShortREAD[n.p]
ELSE mLock ← DebugOps.LongREAD[n.lp]};
qHead ← IF mLock.queue = PSBDefs.Empty THEN NIL ELSE mLock.queue + PSBBase};
qHead ← NIL;
DebugOps.Interpret[q, FindQueue];
IF call THEN DumpQueue[condition]
ELSE {
DOutput.Text[" Condition ([Y or N])? "L];
st.SetParse[CheckCondition]} };
END.