-- Copyright (C) Xerox Corporation 1984, 1985. All rights reserved. -- MergeControlImpl.mesa -- Last edited by Jacks 6-Nov-85 14:01:41 <> DIRECTORY ControlMessages USING [Key], DecomposerControl USING [FreeDecomposeObject], Environment USING [bytesPerPage], FEPSMerge USING [ Cancel, Code, Create, ExceptionCode, ExceptionProc, FinishedCode, FreeMergeJob, Handle, Initialize, MergeDoc, PlatesMerged], Heap USING [systemZone], MergeControl USING [CancelProc, NotifyProc, TraceLevel, WaitChoice], NSFile USING[ Close, Error, Handle, ID, nullAttributeList, nullHandle, nullID, nullTime, Session, Time], NSString USING [ AppendString, FreeString, MakeString, nullString, String, StringFromMesaString], PrintingTypes USING [Option], PrintQueue USING [ Empty, maxStringBytes, nilQueueObjectHandle, ObjectStatus, QueueObjectHandle, QueueStage, QueueWatcher, Requeue], Process USING [ Detach, Priority, priorityBackground, SecondsToTicks, SetPriority, SetTimeout], PSAsyncMsg USING [ExpandArrayAndPutString, Proc, PutMesaString], PSKMessages USING [GetHandle], PSVolume USING [GetDefaultSession], QueueFile USING [CreateError, CreateTempFile, Delete, MakePermanent], String USING [ AppendDecimal, AppendLongDecimal, Overflow, StringBoundsFault], System USING [ gmtEpoch, GetGreenwichMeanTime, GreenwichMeanTime, Overflow, SecondsSinceEpoch], XMessage USING [Get, Handle], XString USING [ReaderBody]; MergeControlImpl: MONITOR IMPORTS DecomposerControl, FEPSMerge, Heap, NSFile, NSString, PrintQueue, Process, PSAsyncMsg, PSKMessages, PSVolume, QueueFile, String, System, XMessage EXPORTS MergeControl SHARES XString = BEGIN Control: TYPE = RECORD [ stop: BOOLEAN ¬ TRUE, start: BOOLEAN ¬ FALSE, jobQueueEntry: BOOLEAN ¬ FALSE, tpQueueEntry: BOOLEAN ¬ FALSE ]; State: TYPE = RECORD [ stopped: BOOLEAN ¬ TRUE, merging: BOOLEAN ¬ FALSE, mergeHandle: FEPSMerge.Handle ¬ NIL, --currently only one merge handle allowed tpJob: BOOLEAN ¬ FALSE, mergeFile: NSFile.Handle ¬ NSFile.nullHandle, mergeFileID: NSFile.ID ¬ NSFile.nullID, trace: MergeControl.TraceLevel ¬ none, qOH: PrintQueue.QueueObjectHandle ¬ PrintQueue.nilQueueObjectHandle, exceptions: CARDINAL ¬ 0, -- FEPSMerge.Exception calls stopStatus: PrintQueue.ObjectStatus ¬ canceledInMerger, -- specified in Stop call notifyProc: MergeControl.NotifyProc ¬ NIL, canceledWhileMerging: MergeControl.CancelProc ¬ NIL, putAsyncMsgFromKey: PSAsyncMsg.Proc ¬ NIL, startMergeTime: NSFile.Time ¬ NSFile.nullTime ]; event: CONDITION; stopped: CONDITION; control: Control ¬ []; state: State ¬ []; -- Message domain handle controlMsgs: XMessage.Handle ¬ PSKMessages.GetHandle[control]; session: NSFile.Session = PSVolume.GetDefaultSession[]; Init: PUBLIC ENTRY PROCEDURE [ currentOption: PrintingTypes.Option, priority: Process.Priority ¬ Process.priorityBackground, notifyProc: MergeControl.NotifyProc, putAsyncMsgFromKey: PSAsyncMsg.Proc] = BEGIN IF currentOption # feps9700 THEN ERROR; --only engine currently supporting merge operation. FEPSMerge.Initialize[ engineType: currentOption, session: session, finishedProc: Finished, exceptionProc: Exception]; state ¬ [ mergeHandle: FEPSMerge.Create[], notifyProc: notifyProc, putAsyncMsgFromKey: putAsyncMsgFromKey]; PrintQueue.QueueWatcher[proc: JobQueueEntry, queueStage: decomposed]; PrintQueue.QueueWatcher[proc: TPQueueEntry, queueStage: tpDecomposed]; Process.SetTimeout[@event, Process.SecondsToTicks[seconds: 30]]; --check queue every 30 secs Process.Detach[FORK MergeControlLoop[priority]]; END; --Init Start: PUBLIC ENTRY PROCEDURE = BEGIN control.start ¬ TRUE; control.stop ¬ FALSE; NOTIFY event; END; --Start Stop: PUBLIC ENTRY PROCEDURE [status: PrintQueue.ObjectStatus, canceledWhileMerging: MergeControl.CancelProc ¬ NIL] = BEGIN state.stopStatus ¬ status; state.canceledWhileMerging ¬ canceledWhileMerging; control.stop ¬ TRUE; control.start ¬ FALSE; NOTIFY event; END; --Stop Stopped: PUBLIC ENTRY PROCEDURE [wither: MergeControl.WaitChoice ¬ dontWait] RETURNS [BOOLEAN] = BEGIN IF wither = wait THEN UNTIL state.stopped DO WAIT stopped; ENDLOOP; RETURN[state.stopped]; END; --Stopped Status: PUBLIC PROCEDURE RETURNS [merging: BOOLEAN] = BEGIN RETURN[state.merging]; END; --Status ModifyTraceLevel: PUBLIC ENTRY PROCEDURE [trace: MergeControl.TraceLevel] = BEGIN state.trace ¬ trace; END; --ModifyTraceLevel JobQueueEntry: ENTRY PROCEDURE = -- called by PrintQueue BEGIN control.jobQueueEntry ¬ TRUE; NOTIFY event; IF state.trace = verbose THEN PSAsyncMsg.PutMesaString["$$Merger JobQEntry"L]; END; --JobQueueEntry TPQueueEntry: ENTRY PROCEDURE = --called by PrintQueue when TestPattern is queued BEGIN control.tpQueueEntry ¬ TRUE; NOTIFY event; IF state.trace = verbose THEN PSAsyncMsg.PutMesaString["$$Merger TPQEntry"L]; END; --TPQueueEntry MergeControlLoop: ENTRY PROCEDURE [priority: Process.Priority] = BEGIN Process.SetPriority[priority]; DO --forever SELECT TRUE FROM control.tpQueueEntry AND NOT state.merging => BEGIN --over-rides state.stopped state.qOH ¬ PrintQueue.Requeue[fromQueue: tpDecomposed, toQueue: merging]; IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN control.tpQueueEntry ¬ FALSE; LOOP; END; state.tpJob ¬ TRUE; MergeDocument[]; END; control.stop => BEGIN SELECT TRUE FROM --disables merging; merge in progress is aborted state.stopped => NULL; state.merging => BEGIN FEPSMerge.Cancel[state.mergeHandle]; Queue[status: state.stopStatus]; END; ENDCASE; state.stopped ¬ TRUE; NOTIFY stopped; END; control.start => BEGIN state.stopped ¬ control.start ¬ FALSE; -- so we don't keep looking here LOOP; -- make another pass END; state.stopped => NULL; state.merging => NULL; --so we don't start multiple merge operations control.jobQueueEntry => BEGIN state.qOH ¬ PrintQueue.Requeue[fromQueue: decomposed, toQueue: merging]; IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN control.jobQueueEntry ¬ FALSE; LOOP; END; MergeDocument[]; END; ENDCASE; WAIT event; ENDLOOP; END; --MergeControlLoop MergeDocument: INTERNAL PROCEDURE = BEGIN code: FEPSMerge.Code; retried: BOOLEAN ¬ FALSE; sMerging: LONG STRING = "$$Merging ""<1>"""L; nsMerging: NSString.String = Str[sMerging]; mergeFileSuffix: NSString.String = Str[".IV"]; mergeFileName: NSString.String ¬ NSString.MakeString[ z: Heap.systemZone, bytes: PrintQueue.maxStringBytes + 10]; BEGIN ENABLE UNWIND => NSString.FreeString[z: Heap.systemZone, s: mergeFileName]; IF state.trace # none THEN BEGIN stringArray: ARRAY [0..1) OF NSString.String; stringArray[0] ¬ state.qOH.fileName; PSAsyncMsg.ExpandArrayAndPutString[nsMerging, DESCRIPTOR[stringArray]]; END; mergeFileName ¬ NSString.AppendString[to: mergeFileName, from: state.qOH.fileName]; mergeFileName ¬ NSString.AppendString[to: mergeFileName, from: mergeFileSuffix]; --Create merge file (merge file initially set to be --1 page long, merger redefines it to correct length for data): [state.mergeFileID, state.mergeFile] ¬ QueueFile.CreateTempFile[ fName: mergeFileName, fBytes: Environment.bytesPerPage ! QueueFile.CreateError => IF retried THEN GOTO OutOfSpace ELSE IF state.notifyProc # NIL THEN BEGIN keepGoing: BOOLEAN ¬ state.notifyProc[ queueObject: state.qOH, code: noResources, continuable: TRUE]; IF keepGoing THEN {retried ¬ TRUE; RETRY} ELSE GOTO OutOfSpace; END ELSE GOTO OutOfSpace; ]; state.exceptions ¬ 0; state.merging ¬ TRUE; state.qOH.currentStatus ¬ merging; state.startMergeTime ¬ System.GetGreenwichMeanTime[]; code ¬ FEPSMerge.MergeDoc[ handle: state.mergeHandle, output: state.mergeFile, inputObjectH: state.qOH.printObjectHandle, bannerOnly: state.qOH.bannerOnly, paperSize: state.qOH.paper]; IF code # ok THEN ERROR; NSString.FreeString[z: Heap.systemZone, s: mergeFileName]; EXITS OutOfSpace => BEGIN NSString.FreeString[z: Heap.systemZone, s: mergeFileName]; Queue[status: mergeFailure]; END; END; --enable clause and code END; --MergeDocument Finished: ENTRY PROCEDURE [ handle: FEPSMerge.Handle, code: FEPSMerge.FinishedCode] = --parameter to FEPSMerge.Initialize BEGIN IF code = bannerOnly AND NOT state.qOH.bannerOnly THEN BEGIN state.qOH.bannerOnly ¬ TRUE; state.qOH.priorStatus ¬ mergeFailure; --After the banner is forwarded this "priorStatus" will become the "currentStatus". END; Queue[status: IF code = noOutput THEN mergeFailure ELSE merged]; END; --Finished Exception: ENTRY FEPSMerge.ExceptionProc = <> BEGIN --NOTE: Do we need a way to get error msgs and put them in queue object? --"Msg" parameter was removed in 10.0. IF state.trace # none THEN BEGIN sPage: LONG STRING ¬ [10]; stringArray: ARRAY [0..5) OF NSString.String; atPage: CARDINAL ¬ FEPSMerge.PlatesMerged[state.mergeHandle]; sPlates: LONG STRING ¬ [10]; sMergeException: LONG STRING ¬ "$$Merge Exception: <1>File: ""<2>""; Plate: <3>; <4>Continuable"L; sNot: LONG STRING ¬ "NOT "L; nsMergeException: NSString.String ¬ Str[sMergeException]; nsNot: NSString.String ¬ Str[sNot]; stringArray[0] ¬ MergeCodeToString[code]; stringArray[1] ¬ state.qOH.fileName; String.AppendDecimal[sPlates, atPage]; stringArray[2] ¬ Str[sPlates]; stringArray[3] ¬ IF NOT continuable THEN nsNot ELSE NSString.nullString; PSAsyncMsg.ExpandArrayAndPutString[nsMergeException, DESCRIPTOR[stringArray]]; END; state.exceptions ¬ state.exceptions + 1; keepGoing ¬ IF code = noResources THEN state.notifyProc[state.qOH, noResources, continuable] ELSE state.notifyProc[state.qOH, other, continuable]; END; --Exception Queue: INTERNAL PROCEDURE [status: PrintQueue.ObjectStatus] = BEGIN startSinceEpoch: LONG CARDINAL; endSinceEpoch: LONG CARDINAL; IF state.qOH = PrintQueue.nilQueueObjectHandle THEN BEGIN --This could be true if Queue gets called twice (once by --MergeControlLoop and once from Finished) in case that doc --finishes decomposing while decomposition is being suspended. IF state.trace # none THEN PSAsyncMsg.PutMesaString["##Can't Queue nilQOH! "L]; RETURN; END; startSinceEpoch ¬ System.SecondsSinceEpoch[state.startMergeTime]; endSinceEpoch ¬ System.SecondsSinceEpoch[System.GetGreenwichMeanTime[]]; IF endSinceEpoch >= startSinceEpoch THEN state.qOH.markTime ¬ endSinceEpoch - startSinceEpoch; IF state.trace # none THEN BEGIN sDoneMerging: LONG STRING ¬ "$$Done Merging ""<1>""; status= <2>; Plates= <3>; seconds= <4>"L; sPlates: LONG STRING ¬ [10]; sSeconds: LONG STRING ¬ [10]; nsDoneMerging: NSString.String ¬ Str[sDoneMerging]; stringArray: ARRAY [0..4) OF NSString.String; stringArray[0] ¬ state.qOH.fileName; stringArray[1] ¬ Str[SELECT status FROM restart => "restart"L, canceledInMerger => "canceledInMerger"L, mergeFailure => "mergeFailure"L, ENDCASE => "merged"L]; String.AppendDecimal[sPlates, FEPSMerge.PlatesMerged[state.mergeHandle]]; stringArray[2] ¬ Str[sPlates]; String.AppendLongDecimal[sSeconds, state.qOH.markTime ! System.Overflow, String.Overflow, String.StringBoundsFault => CONTINUE]; stringArray[3] ¬ Str[sSeconds]; PSAsyncMsg.ExpandArrayAndPutString[nsDoneMerging, DESCRIPTOR[stringArray]] END; state.qOH.currentStatus ¬ status; FEPSMerge.FreeMergeJob[state.mergeHandle]; SELECT TRUE FROM status = restart => BEGIN --Closing the temporary merge file will delete it... IF state.mergeFile # NSFile.nullHandle THEN NSFile.Close[state.mergeFile, session ! NSFile.Error => CONTINUE]; --Free decompose handle (doc will be decomposed again)... IF state.qOH.printObjectHandle # NIL THEN BEGIN DecomposerControl.FreeDecomposeObject[state.qOH.uid]; state.qOH.printObjectHandle ¬ NIL END; [] ¬ PrintQueue.Requeue[qOH: state.qOH, fromQueue: merging, toQueue: IF state.tpJob THEN aborted ELSE spooledNormal, position: front]; END; status = canceledInMerger => BEGIN --Closing the temporary merge file will delete it... IF state.mergeFile # NSFile.nullHandle THEN NSFile.Close[state.mergeFile, session ! NSFile.Error => CONTINUE]; [] ¬ PrintQueue.Requeue[ qOH: state.qOH, fromQueue: merging, toQueue: aborted]; IF state.canceledWhileMerging # NIL THEN state.canceledWhileMerging[state.qOH.fileName, status]; END; status # merged => BEGIN --Closing the temporary merge file will delete it... IF state.mergeFile # NSFile.nullHandle THEN NSFile.Close[state.mergeFile, session ! NSFile.Error => CONTINUE]; [] ¬ PrintQueue.Requeue[qOH: state.qOH, fromQueue: merging, toQueue: aborted]; END; ENDCASE => BEGIN IF state.qOH.printObjectHandle # NIL THEN BEGIN DecomposerControl.FreeDecomposeObject[state.qOH.uid]; state.qOH.printObjectHandle ¬ NIL END; WITH q: state.qOH SELECT FROM feps9700 => q.ivFileID ¬ state.mergeFileID; ENDCASE => ERROR; --Delete the spooled file: IF NOT state.tpJob THEN state.qOH.fileID ¬ QueueFile.Delete[fileID: state.qOH.fileID]; [] ¬ QueueFile.MakePermanent[state.mergeFile, NSFile.nullAttributeList]; NSFile.Close[state.mergeFile, session]; [] ¬ PrintQueue.Requeue[qOH: state.qOH, fromQueue: merging, toQueue: IF state.tpJob THEN tpMerged ELSE merged]; END; state.mergeFile ¬ NSFile.nullHandle; state.mergeFileID ¬ NSFile.nullID; state.merging ¬ state.tpJob ¬ FALSE; state.qOH ¬ PrintQueue.nilQueueObjectHandle; control.jobQueueEntry ¬ NOT PrintQueue.Empty[decomposed]; control.tpQueueEntry ¬ NOT PrintQueue.Empty[tpDecomposed]; NOTIFY event; -- in case there's something to do END; --Queue MergeCodeToString: INTERNAL PROCEDURE [code: FEPSMerge.ExceptionCode] RETURNS [NSString.String] = BEGIN RETURN [ IF code = noResources THEN M[mDecompErrorNoResources] ELSE M[mDecompErrorUnknown]]; END; --MergeCodeToString -- Proc for getting NSString from XMessage key M: PROCEDURE [key: ControlMessages.Key] RETURNS [string: NSString.String] = { r: XString.ReaderBody _ XMessage.Get[controlMsgs, ORD[key]]; string _ [bytes: LOOPHOLE[r.bytes], length: r.limit, maxlength: r.limit]}; Str: PROCEDURE [s: LONG STRING] RETURNS [ns: NSString.String] = INLINE { RETURN[NSString.StringFromMesaString[s]]}; END. --MergeControlImpl LOG when/who/what 16-Oct-84 10:34:41 - Jacks - Created. 25-Oct-84 17:04:15 - Jacks - Added reference to bannerOnly in Finished. 16-Nov-84 12:32:26 - Jacks - Moved call to FreeMergeJob to beginning of Queue; updated to new FEPSMerge interface. 29-Nov-84 15:55:51 - Jacks - Added bannerOnly parm to MergeDoc call. 17-Dec-84 10:57:39 - Jacks - Removed ControlMessages from directory. 14-Jan-85 16:09:16 - Jacks - Make merged file permanent for TP jobs as well as normal jobs (in Queue). 17-Jun-85 16:14:37 - Jacks - Added copyright notice; updated to PS Euclid interfaces. 19-Jul-85 17:59:52 - Jacks - Updated to XMessage and QueueFile. 6-Aug-85 9:08:56 - Jacks - Updated to 10.0 FEPSMerge interface and DecomposerControl.FreeDecomposeObject. 19-Sep-85 11:45:16 - Jacks - Rewrote Finished and some of Exception to handle bannerOnlys correctly; removed mergeFailure from state record. 6-Nov-85 14:01:38 - Jacks - Get msg handle from PSKMessages.