RosemaryRun.mesa
last changed by Barth, June 9, 1983 11:14 am
Last Edited by: Spreitzer, July 14, 1983 11:24 am
DIRECTORY IO, List, OrderedSymbolTableRef, Rope, Rosemary, RosemaryInsides;
RosemaryRun: CEDAR MONITOR
IMPORTS IO, List, OSTR: OrderedSymbolTableRef, Rope, Rosemary
EXPORTS Rosemary, RosemaryInsides =
BEGIN OPEN Rosemary, RosemaryInsides;
EvalStructure: PUBLIC EvalProc =
BEGIN
str: Structure ← NARROW[cell.realCellStuff.state];
FOR c: CARDINAL IN [0 .. cell.class.ioWordCount) DO
TRUSTED
BEGIN
(str.mirror.realCellStuff.newIOAsWP+c)^ ← (cell.realCellStuff.oldIOAsWP+c)^ ← (cell.realCellStuff.newIOAsWP+c)^;
END;
ENDLOOP;
FOR portIndex: CARDINAL IN [0 .. cell.class.ports.length) DO
port: Port ← cell.class.ports[portIndex];
IF NOT port.input THEN LOOP;
TRUSTED BEGIN
Distribute[
cell.realCellStuff.newIOAsWP + port.firstWord,
port.wordCount,
str.insideNodes[portIndex],
NIL,
str];
END;
ENDLOOP;
Run[str];
FOR c: CARDINAL IN [0 .. cell.class.ioWordCount) DO
TRUSTED
BEGIN
(cell.realCellStuff.newIOAsWP+c)^ ← (str.mirror.realCellStuff.newIOAsWP+c)^;
END;
ENDLOOP;
END;
Distribute: PROC [base: WordPtr, count: CARDINAL, fromNode: Node, fromCell: Cell, str: Structure] =
BEGIN
abort: BOOLEANFALSE;
FOR dests: SocketList ← fromNode.readers, dests.rest WHILE dests # NIL DO
target: Cell ← dests.first.cell;
targPort: Port ← target.class.ports[dests.first.index];
sourceWP: WordPtr ← base;
destWP: WordPtr;
TRUSTED BEGIN
destWP ← target.realCellStuff.newIOAsWP + targPort.firstWord;
END;
FOR j: CARDINAL IN [0 .. targPort.wordCount) DO
TRUSTED
BEGIN
destWP^ ← sourceWP^;
sourceWP ← sourceWP + 1;
destWP ← destWP + 1;
END;
ENDLOOP;
IF target # fromCell THEN Schedule[target, str];
ENDLOOP;
FOR watchers: NodeWatcherList ← fromNode.watchers[1], watchers.rest WHILE watchers # NIL DO
watchers.first.notify[node: fromNode, clientData: watchers.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
FOR watchers: NodeWatcherList ← fromNode.watchers[0], watchers.rest WHILE watchers # NIL DO
watchers.first.notify[node: fromNode, clientData: watchers.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
END;
Operations:
GetStrLock: ENTRY PROC [str: Structure] =
BEGIN ENABLE UNWIND => NULL;
IF str.locked THEN ERROR Error["Structure in use"];
str.locked ← TRUE;
END;
ReleaseStrLock: PROC [str: Structure] = {str.locked ← FALSE};
notInSchedule: PUBLIC Cell ← NEW [CellRep];
ScheduleCell: PUBLIC PROC [cell: Cell] =
BEGIN
WHILE cell.parent # NIL DO
str: Structure ← CellToStr[cell.parent];
Schedule[cell, str];
cell ← str.container;
ENDLOOP;
END;
CellToStr: PUBLIC PROC [cell: Cell] RETURNS [str: Structure] =
BEGIN
WHILE (IF cell.realCellStuff = NIL THEN TRUE ELSE IF cell.realCellStuff.state = NIL THEN TRUE ELSE NOT ISTYPE[cell.realCellStuff.state, Structure]) DO cell ← cell.parent ENDLOOP;
RETURN [NARROW[cell.realCellStuff.state]];
END;
NotifyCellEval: PROC [cell: Cell] =
BEGIN
abort: BOOLEANFALSE;
FOR wl: CellWatcherList ← cell.realCellStuff.evalWatchers, wl.rest WHILE wl # NIL DO
wl.first.notify[cell: cell, clientData: wl.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
END;
SingleStep: PUBLIC PROC [str: Structure] =
BEGIN
GetStrLock[str];
BEGIN ENABLE UNWIND => ReleaseStrLock[str];
IF stop THEN SIGNAL Stop[msg: "Stopped", data: str];
IF str.schedFirst # NIL THEN
BEGIN
cell: Cell ← PickFromSchedule[str];
IF cell.realCellStuff.eval # NIL THEN
BEGIN
errorAbort: BOOLEANFALSE;
cell.realCellStuff.eval[cell !UNWIND => [] ← ReallyCleanUpAfterModify[cell, str, TRUE, FALSE]];
[] ← ReallyCleanUpAfterModify[cell, str, TRUE, FALSE];
NotifyCellEval[cell];
END;
END;
END;
ReleaseStrLock[str];
END;
stop: PUBLIC BOOLEANFALSE;
Run: PUBLIC PROC [str: Structure] =
BEGIN
GetStrLock[str];
BEGIN ENABLE UNWIND => ReleaseStrLock[str];
WHILE str.schedFirst # NIL DO
cell: Cell;
IF stop THEN SIGNAL Stop[msg: "Stopped", data: str];
cell ← PickFromSchedule[str];
IF cell.realCellStuff.eval # NIL THEN
BEGIN
errorAbort: BOOLEANFALSE;
cell.realCellStuff.eval[cell !UNWIND => [] ← ReallyCleanUpAfterModify[cell, str, TRUE, FALSE]];
[] ← ReallyCleanUpAfterModify[cell, str, TRUE, FALSE];
NotifyCellEval[cell];
END;
ENDLOOP;
END;
ReleaseStrLock[str];
END;
PickFromSchedule: PROC [str: Structure] RETURNS [cell: Cell] =
BEGIN
abort: BOOLEANFALSE;
cell ← str.schedFirst;
IF (str.schedFirst ← cell.realCellStuff.schedNext) = NIL THEN str.schedLast ← NIL;
cell.realCellStuff.schedNext ← notInSchedule;
FOR cw: CellWatcherList ← cell.realCellStuff.schedWatchers, cw.rest WHILE cw # NIL DO
cw.first.notify[cell: cell, clientData: cw.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
IF str.schedFirst = NIL THEN RETURN;
FOR cw: CellWatcherList ← str.schedFirst.realCellStuff.schedWatchers, cw.rest WHILE cw # NIL DO
cw.first.notify[cell: str.schedFirst, clientData: cw.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
END;
AllowToModify: PUBLIC PROC [cell: Cell, modifier: ModifyProc, blindly: BOOLEANFALSE] =
BEGIN
ReallyAllowToModify: ModifyProc =
BEGIN
GetStrLock[str];
IF NOT blindly THEN FOR c: CARDINAL IN [0 .. theCell.class.ioWordCount) DO
TRUSTED
BEGIN
(theCell.realCellStuff.oldIOAsWP+c)^ ← (theCell.realCellStuff.newIOAsWP+c)^;
END;
ENDLOOP;
subtle ← modifier[theCell !UNWIND =>
BEGIN
subtle ← ReallyCleanUpAfterModify[theCell, str, FALSE, blindly];
ReleaseStrLock[str];
END];
IF subtle THEN Schedule[theCell, str];
subtle ← subtle OR ReallyCleanUpAfterModify[theCell, str, FALSE, blindly];
ReleaseStrLock[str];
END;
theCell: Cell ← cell;
str: Structure ← NIL;
IF cell.parent = NIL THEN [] ← modifier[theCell]
ELSE IF (str ← CellToStr[cell.parent]).container.parent = NIL THEN [] ← ReallyAllowToModify[NIL]
ELSE AllowToModify[str.container, ReallyAllowToModify, FALSE];
END;
CleanUpAfterModify: PUBLIC PROC [cell: Cell] =
BEGIN
[] ← ReallyCleanUpAfterModify[cell, CellToStr[cell.parent], FALSE, FALSE];
END;
ReallyCleanUpAfterModify: PROC [cell: Cell, str: Structure, strict, blindly: BOOLEAN] RETURNS [anyDiff: BOOLEAN] =
BEGIN
anyDiff ← FALSE;
FOR outPortIndex: CARDINAL IN [0 .. cell.class.ports.length) DO
port: Port ← cell.class.ports[outPortIndex];
diff: BOOLEANFALSE;
newWP: WordPtr;
oldWP: WordPtr;
IF strict AND NOT port.output THEN LOOP;
TRUSTED BEGIN
newWP ← cell.realCellStuff.newIOAsWP + port.firstWord;
oldWP ← cell.realCellStuff.oldIOAsWP + port.firstWord;
END;
IF blindly THEN diff ← TRUE
ELSE FOR i: CARDINAL IN [0 .. port.wordCount) DO
TRUSTED
BEGIN
IF newWP^ # oldWP^ THEN {diff ← TRUE; EXIT};
newWP ← newWP + 1;
oldWP ← oldWP + 1;
END;
ENDLOOP;
IF diff THEN
TRUSTED BEGIN
anyDiff ← TRUE;
cell.interfaceNodes[outPortIndex].visible ← [cell, outPortIndex];
Distribute[
cell.realCellStuff.newIOAsWP + port.firstWord,
port.wordCount,
cell.interfaceNodes[outPortIndex],
cell,
str];
END;
ENDLOOP;
END;
Test: PUBLIC PROC [subject: Cell, parms: TestParms] =
BEGIN
ReallyTest: ModifyProc =
BEGIN
subject.class.test[subject];
subtle ← TRUE;
END;
IF subject.type # Real THEN ERROR Error["Attempt to test a Shadow Cell", subject];
subject.other ← List.PutAssoc[key: $TestParms, val: parms, aList: subject.other];
AllowToModify[subject, ReallyTest];
END;
Eval: PUBLIC PROC [cell: Cell] =
BEGIN
parms: TestParms ← NARROW[List.Assoc[key: $TestParms, aList: cell.other]];
str: Structure ← NIL;
IF cell.parent # NIL THEN
BEGIN
str ← CellToStr[cell.parent];
IF ReallyCleanUpAfterModify[cell, str, FALSE, FALSE] THEN Schedule[cell, str];
END;
NotifyCellEval[cell];
IF parms.stopBefore THEN SIGNAL Stop["About to eval", cell];
cell.realCellStuff.eval[cell];
IF cell.parent # NIL THEN
BEGIN
IF ReallyCleanUpAfterModify[cell, str, FALSE, FALSE] THEN Schedule[cell, str];
END;
NotifyCellEval[cell];
IF parms.stopAfter THEN SIGNAL Stop["Just eval'ed", cell];
IF cell.parent # NIL THEN
BEGIN
FOR c: CARDINAL IN [0 .. cell.class.ioWordCount) DO
TRUSTED
BEGIN
(cell.realCellStuff.oldIOAsWP+c)^ ← (cell.realCellStuff.newIOAsWP+c)^;
END;
ENDLOOP;
END;
END;
UpToReal: PUBLIC PROC [cell: Cell] RETURNS [realCell: Cell] =
BEGIN
FOR realCell ← cell, realCell.parent WHILE realCell.type # Real DO NULL ENDLOOP;
END;
Schedule: PROC [cell: Cell, str: Structure] =
BEGIN
abort: BOOLEANFALSE;
IF cell.realCellStuff.schedNext # notInSchedule THEN RETURN;
cell.realCellStuff.schedNext ← NIL;
IF str.schedLast = NIL THEN str.schedFirst ← cell ELSE str.schedLast.realCellStuff.schedNext ← cell;
str.schedLast ← cell;
FOR cw: CellWatcherList ← cell.realCellStuff.schedWatchers, cw.rest WHILE cw # NIL DO
cw.first.notify[cell: cell, clientData: cw.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
END;
SocketToWP: PUBLIC PROC [s: Socket] RETURNS [wp: WordPtr] =
TRUSTED BEGIN
wp ← s.cell.realCellStuff.newIOAsWP + s.cell.class.ports[s.index].firstWord;
END;
UnScheduleCell: PUBLIC PROC [cell: Cell] =
BEGIN
str: Structure ← CellToStr[cell.parent];
prev, cur: Cell ← NIL;
abort: BOOLEANFALSE;
FOR cur ← str.schedFirst, cur.realCellStuff.schedNext WHILE cur # NIL DO
IF cur = cell THEN EXIT;
ENDLOOP;
IF cur = NIL THEN RETURN;
IF prev = NIL THEN str.schedFirst ← cur.realCellStuff.schedNext ELSE prev.realCellStuff.schedNext ← cur.realCellStuff.schedNext;
IF str.schedLast = cur THEN str.schedLast ← prev;
cur.realCellStuff.schedNext ← notInSchedule;
FOR cw: CellWatcherList ← cell.realCellStuff.schedWatchers, cw.rest WHILE cw # NIL DO
cw.first.notify[cell: cell, clientData: cw.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
IF str.schedFirst = NIL THEN RETURN;
FOR cw: CellWatcherList ← str.schedFirst.realCellStuff.schedWatchers, cw.rest WHILE cw # NIL DO
cw.first.notify[cell: str.schedFirst, clientData: cw.first.clientData !ABORTED => {abort ← TRUE; CONTINUE}];
ENDLOOP;
IF abort THEN ERROR ABORTED;
END;
LongCellName: PUBLIC PROC [cell: Cell] RETURNS [ln: ROPE] =
BEGIN
ln ← cell.name;
FOR cell ← cell.parent, cell.parent WHILE cell # NIL DO
ln ← cell.name.Cat[".", ln];
ENDLOOP;
END;
LookupCell: PUBLIC PROC [path: LIST OF ROPE, from: Cell ← NIL] RETURNS [cell: Cell] =
BEGIN
sofar: LIST OF ROPENIL;
cell ← from;
WHILE path # NIL DO
next: Cell ← NARROW[(IF cell = NIL THEN roots ELSE cell.components). Lookup[path.first]];
IF next = NIL THEN
{SIGNAL Warning[IO.PutFR["Not found: %g %g %g", IO.refAny[sofar], IO.refAny[path.first], IO.refAny[path.rest]]]; RETURN [NIL]};
sofar ← CONS[path.first, sofar];
path ← path.rest;
cell ← next;
ENDLOOP;
END;
RootStructure: PUBLIC PROC [cell: Cell] RETURNS [str: Structure] =
BEGIN
FOR str ← CellToStr[cell], CellToStr[str.container.parent] WHILE str.container.parent # NIL DO NULL ENDLOOP;
END;
END.