<> <> <> 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: BOOLEAN _ FALSE; 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; <> 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: BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE; 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 BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE] = 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: BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE; 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 ROPE _ NIL; 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.