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],
IO USING [PutFR, int],
MBQueue USING [Flush],
Process USING [Detach, MsecToTicks, Pause],
Rope USING [ROPE, Cat, IsEmpty],
RuntimeError USING [UNCAUGHT],
TerminalIO USING [WriteRope],
ViewerClasses USING [ViewerClass, SaveProc],
ViewerOps USING [FetchViewerClass];
CDEmergencyHandling: CEDAR MONITOR
IMPORTS CDIO, CDViewer, IO, MBQueue, Process, Rope, RuntimeError, TerminalIO, ViewerOps =
BEGIN
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/saved%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;
END.