CDEmergencyHandling.mesa
Copyright © 1984 by Xerox Corporation. All rights reserved.
Created by Christian Jacobi, July 13, 1984 9:11:20 am PDT
Last edited by: Christian Jacobi, September 18, 1986 2:02:01 pm PDT
DIRECTORY
CedarProcess,
CD USING [Design],
CDIO USING [WriteDesign],
CDDrawQueue,
CDVPrivate,
CDViewer USING [DesignOf],
CDSequencer,
IO USING [PutFR, int],
Process USING [Detach, MsecToTicks, Pause, SecondsToTicks],
Rope USING [ROPE, IsEmpty],
RuntimeError USING [UNCAUGHT],
Terminal USING [GetKeys, Virtual, Current],
TerminalIO USING [PutRope, PutRopes],
ViewerClasses USING [ViewerClass, SaveProc],
ViewerOps USING [FetchViewerClass, EnumerateViewers, EnumProc];
CDEmergencyHandling: CEDAR MONITOR
IMPORTS CedarProcess, CDIO, CDDrawQueue, CDVPrivate, CDViewer, CDSequencer, IO, Process, Rope, RuntimeError, Terminal, TerminalIO, ViewerOps
SHARES CDVPrivate =
BEGIN
SaveAll: PROC [] = {
OneViewer: ViewerOps.EnumProc = {
design: CD.Design = CDViewer.DesignOf[v].design; -- is not monitored
IF design#NIL THEN Save[v, TRUE]
};
--I checked the implementation;
--ViewerOps.EnumerateViewers then was really not monitored
ViewerOps.EnumerateViewers[OneViewer]
};
StopDrawing: PROC[] = {
ENABLE RuntimeError.UNCAUGHT => GOTO exit;
FOR l: LIST OF CDVPrivate.VRef ← CDVPrivate.allVRefs, l.rest WHILE l#NIL DO
IF l.first.ct#NIL THEN CDDrawQueue.Flush[l.first.ct]
ENDLOOP;
EXITS exit => NULL;
};
StopDrawingCommand: PROC [comm: CDSequencer.Command] = {
TerminalIO.PutRope["Stop drawing (better use <ESC-LF>)\n"];
StopDrawing[];
};
EmergencySaveProcess: PROC = {
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.PutRope["\nsaved ChipNDale viewers; works only once\n"];
RETURN
}
ENDLOOP;
};
-- -- -- -- -- -- -- -- -- -- --
-- now real stuff
Save: ViewerClasses.SaveProc --PROC [self: Viewer, force: BOOL ← FALSE]-- = {
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]]};
}
}
};
SaveDesign: PROC[design: CD.Design] = {
done: BOOLFALSE;
fileName: 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] = {
ENABLE {
UNWIND => NULL;
RuntimeError.UNCAUGHT => GOTO next;
};
--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;
fileName ← IO.PutFR["///temp/ChipNDale/emergencysave%01g.dale", IO.int[saveKey^]];
saveKey^ ← saveKey^+1;
done ← CDIO.WriteDesign[design: design, to: fileName, emergency: TRUE];
IF done THEN savedDesigns ← CONS[design, savedDesigns];
EXITS next => NULL
};
Process.Pause[Process.MsecToTicks[100]]; -- give the detached Flush process a chance
ReallySaveDesign[design];
IF done THEN {
TerminalIO.PutRopes["design ", (IF Rope.IsEmpty[design.name] THEN "no name" ELSE design.name)];
TerminalIO.PutRopes[" saved on file """, fileName, """\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"];
}
};
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.