CDEmergencyHandling.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
by Christian Jacobi, July 13, 1984 9:11:20 am PDT
last edited Christian Jacobi, June 11, 1985 10:56:36 pm PDT
DIRECTORY
CedarProcess,
CD USING [Design],
CDIO USING [WriteDesign],
CDDraw,
CDVPrivate,
CDViewer USING [DesignOf],
CDSequencer,
IO USING [PutFR, int],
MBQueue USING [Flush],
Process USING [Detach, MsecToTicks, Pause, SecondsToTicks],
Rope USING [ROPE, Cat, IsEmpty],
RuntimeError USING [UNCAUGHT],
Terminal USING [GetKeys, Virtual, Current],
TerminalIO USING [WriteRope],
ViewerClasses USING [ViewerClass, SaveProc],
ViewerOps USING [FetchViewerClass, EnumerateViewers, EnumProc];
CDEmergencyHandling:
CEDAR
MONITOR
IMPORTS CedarProcess, CDIO, CDDraw, CDVPrivate, CDViewer, CDSequencer, IO, MBQueue, Process, Rope, RuntimeError, Terminal, TerminalIO, ViewerOps
SHARES CDVPrivate =
BEGIN
SaveAll:
PROC [] =
BEGIN
CallTheSaver: ViewerOps.EnumProc
-- PROC [v: Viewer] RETURNS [BOOL ← TRUE] -- =
BEGIN
design: CD.Design = CDViewer.DesignOf[v].design; -- is not monitored
IF design#NIL THEN Save[v, TRUE]
END;
--I checked the implementation;
--ViewerOps.EnumerateViewers then was really not monitored
ViewerOps.EnumerateViewers[CallTheSaver]
END;
StopDrawing:
PROC[] =
BEGIN
ENABLE RuntimeError.UNCAUGHT => GOTO exit;
FOR l: CDVPrivate.MyGraphicRef ← CDVPrivate.linkBase, l.link
WHILE l#
NIL
DO
IF l.ct#NIL THEN CDDraw.FlushCommands[l.ct]
ENDLOOP;
EXITS exit => NULL;
END;
StopDrawingCommand:
PROC [comm: CDSequencer.Command] =
BEGIN
TerminalIO.WriteRope["Stop drawing (better use <ESC-LF>)\n"];
StopDrawing[];
END;
EmergencySaveProcess:
PROC =
BEGIN
virtual: Terminal.Virtual ← Terminal.Current[];
CedarProcess.SetPriority[CedarProcess.Priority[foreground]];
DO
-- for nearly ever
Process.Pause[Process.SecondsToTicks[1]];
IF Terminal.GetKeys[virtual][
ESC]=down
AND Terminal.GetKeys[virtual][LF]=down
THEN StopDrawing[];
IF Terminal.GetKeys[virtual][Spare3]=down
AND Terminal.GetKeys[virtual][RightShift]=down
AND Terminal.GetKeys[virtual][LeftShift]=down
THEN {
SaveAll[];
TerminalIO.WriteRope["\nyou got it; this command will not work a second time\n"];
RETURN
}
ENDLOOP;
END;
-- -- -- -- -- -- -- -- -- -- --
-- now real stuff
Save: ViewerClasses.SaveProc
--PROC [self: Viewer, force: BOOL ← FALSE]-- =
BEGIN
IF force
AND ~self.saveInProgress
THEN {
--otherwise don't consider saving
design: CD.Design = CDViewer.DesignOf[self].design; -- is not monitored
IF design#
NIL
THEN {
--vanilla try to avoid concurrency with the write, which is unmonitored;
--forked, so save may not hang in MBQueue monitor locking on the design
TRUSTED {Process.Detach[FORK MBQueue.Flush[design.queue]]};
--forked, so save of other designs may not hang
TRUSTED {Process.Detach[FORK SaveDesign[design]]};
}
}
END;
SaveDesign:
PROC[design:
CD.Design] =
BEGIN
done: BOOL ← FALSE;
saveOn: Rope.ROPE;
--using our own monitor prevents it at least from wedging together with other's;
--we must use some monitor because emergencywrite tries to kill any interferences,
--which could be other emergencywrite's
ReallySaveDesign:
ENTRY
PROC[design:
CD.Design] =
BEGIN
ENABLE
BEGIN
UNWIND => NULL;
RuntimeError.UNCAUGHT => GOTO next;
END;
--we use the list business to prevent multiple save instead of CDValue,
--to never call any monitored procedure which could cause additional wedges
FOR list:
LIST
OF
CD.Design ← savedDesigns, list.rest
WHILE list#
NIL
DO
IF list.first=design THEN RETURN;
ENDLOOP;
saveOn ← IO.PutFR["///temp/ChipNDale/emergencysave%01g.dale", IO.int[saveKey^]];
saveKey^ ← saveKey^+1;
done ← CDIO.WriteDesign[design: design, to: saveOn, emergency: TRUE];
IF done THEN savedDesigns ← CONS[design, savedDesigns];
EXITS next => NULL
END;
Process.Pause[Process.MsecToTicks[100]]; -- give the detached Flush process a chance
ReallySaveDesign[design];
IF done
THEN TerminalIO.WriteRope[Rope.Cat["design ",
(IF Rope.IsEmpty[design.name] THEN "no name" ELSE design.name),
" emergency saved on file """, saveOn,
"""\nWARNING: This write was made out of synchronisation; (what means: if any other process was fooling with the design, both could be broken, the design, and the file). Roll back, Copy the file and CHECK it.\n"]];
END;
savedDesigns: LIST OF CD.Design ← NIL;
saveKey: REF INT = NEW[INT𡤀]; -- ref used as key; referent used as counter
class: ViewerClasses.ViewerClass = ViewerOps.FetchViewerClass[$ChipNDale];
IF class#NIL AND class.save=NIL THEN class.save ← Save;
TRUSTED {Process.Detach[FORK EmergencySaveProcess[]]};
CDSequencer.ImplementCommand[$StopDrawing, StopDrawingCommand,, dontQueue];
END.