CDEmergencyHandling.mesa
by Christian Jacobi July 13, 1984 9:11:20 am PDT
last edited Christian Jacobi July 13, 1984 9:11:25 am PDT
DIRECTORY
CD USING [Design],
CDIO USING [WriteDesign],
CDViewer USING [DesignOf],
Interminal USING [terminal],
IO USING [PutFR, int],
MBQueue USING [Flush],
Process USING [Detach, MsecToTicks, Pause, SecondsToTicks, SetPriority, priorityForeground],
Rope USING [ROPE, Cat, IsEmpty],
RuntimeError USING [UNCAUGHT],
Terminal USING [GetKeys],
TerminalIO USING [WriteRope],
ViewerClasses USING [ViewerClass, SaveProc],
ViewerOps USING [FetchViewerClass, EnumerateViewers, EnumProc];
CDEmergencyHandling: CEDAR MONITOR
IMPORTS CDIO, CDViewer, Interminal, IO, MBQueue, Process, Rope, RuntimeError, Terminal, TerminalIO, ViewerOps =
BEGIN
SaveAll: PROC [] =
--typically called from a debugger
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;
EmergencySaveProcess: PROC =
BEGIN
Process.SetPriority[Process.priorityForeground];
DO -- forever
Process.Pause[Process.SecondsToTicks[1]];
IF Interminal.terminal.GetKeys[][Spare3]=down
AND Interminal.terminal.GetKeys[][RightShift]=down
AND Interminal.terminal.GetKeys[][LeftShift]=down
THEN SaveAll[]
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: BOOLFALSE;
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[]]};
END.