BansheeMarkerControlImpl.mesa
Copyright (C) 1986 by Xerox Corporation. All rights reserved.
Ruseli Binsol: November 21, 1986 1:25:25 pm PST
Tim Diebert: December 2, 1986 4:11:11 pm PST
<<This module is part of a multi-module monitor, the root of which is MarkerControlImpl.>>
DIRECTORY
BasicTime USING [GMT, Now, Period, Update],
IO,
MarkerControl USING [ClientProcs, ClientProcsHandle, MarkerStatus],
MarkerControlImpl,
MarkerControlInternal,
PaperHandling USING [BannerMode, PrintOrder],
PaperTypes USING [nullDimensions, Paper],
PrintingState USING [Type],
PrintingTypes USING [Option],
PrintQueue USING [Empty, nilQueueObjectHandle, ObjectStatus, QueueObjectHandle, QueueStage, Requeue],
Process USING [Detach, MsecToTicks, Pause, Priority, priorityBackground, SecondsToTicks, SetPriority, SetTimeout],
PSAsyncMsg USING [PutString],
BansheeCounter USING [ForceOut],
BansheeEngine USING [GetPaperSize, GetStatus, GetPrintingState, Job, SetJob, SetPrintingState,
WaitStatus, WaitPrintingState, JobHandle],
BansheeMarkerControl,
BansheeStatus USING [Type],
Rope USING [ROPE, ToRefText];
BansheeMarkerControlImpl: CEDAR MONITOR LOCKS root
IMPORTS
root: MarkerControlImpl, --DecomposerControl, -- BansheeCounter, BansheeEngine, BasicTime, IO, MarkerControlInternal, PrintQueue, Process, PSAsyncMsg, Rope
EXPORTS BansheeMarkerControl
SHARES MarkerControlImpl = BEGIN
ROPE: TYPE ~ Rope.ROPE;
JobStatus: TYPE = {normal, paused, canceled, imagingError};
BansheeState: TYPE = RECORD [
jobStatus: JobStatus ← normal,
job: BansheeEngine.JobHandle ← NIL,
lastEngineStatus: BansheeStatus.Type ← okay,
banner: PaperHandling.BannerMode ← oncePerJob,
media: PaperTypes.Paper ← [knownSize: letter, otherSize: PaperTypes.nullDimensions]];
BansheeClientProcsHandle: TYPE = REF bansheeDl MarkerControl.ClientProcs;
updateBansheeLog: CONDITION;
engineStatusChange: CONDITION;
jobStateChange: CONDITION;
bansheeState: REF BansheeState ← NIL;
bansheeClientProcs: BansheeClientProcsHandle ← NIL;
lastActivityTimeStamp: BasicTime.GMT ← BasicTime.Now[]; --The time the last job completed marking.
********************************
PUBLIC PROCS:
*******************************
Startup: PUBLIC INTERNAL PROCEDURE [priority: Process.Priority]
RETURNS [MarkerControl.ClientProcsHandle] = TRUSTED BEGIN
bansheeState ← NEW[BansheeState];
bansheeState.job ← NEW[BansheeEngine.Job ← [document: NIL]];
bansheeClientProcs ← NEW[
bansheeDl MarkerControl.ClientProcs ← [
start: MarkerControlInternal.Start, stop: MarkerControlInternal.Stop,
stopped: MarkerControlInternal.Stopped, pause: MarkerControlInternal.Pause,
resume: MarkerControlInternal.Resume, status: Status,
waitStatusChange: WaitStatusChange,
setPrintOrder: MarkerControlInternal.SetPrintOrder,
modifyTraceLevel: MarkerControlInternal.ModifyTraceLevel,
engineSpecific: bansheeDl[
setBanner: SetBansheeBanner]
]];
bansheeState.lastEngineStatus ← BansheeEngine.GetStatus[];
Process.Detach[FORK StatusChangeWatcher[]];
Process.Detach[FORK StatusWatcher[]];
Process.Detach[FORK BansheeLogUpdater[]];
Process.Detach[FORK MarkingControl[priority]];
BansheeCounter.ForceOut[]; -- to start the logging; fixes AR 12573
RETURN[bansheeClientProcs]
END; -- Startup
Status: PUBLIC PROCEDURE RETURNS [MarkerControl.MarkerStatus] = BEGIN
bansheeState.media ← BansheeEngine.GetPaperSize[];
RETURN[
[
activity: root.state.activity,
engineFault: root.state.engineProblem,
engine: [bansheeDl[
banshee: bansheeState.lastEngineStatus,
paper: bansheeState.media]]]];
END; --Status
********************************
PRIVATE PROCS:
********************************
SetBansheeBanner: PROCEDURE [banner: PaperHandling.BannerMode] =
BEGIN bansheeState.banner ← banner;
END; --SetBanner
WaitStatusChange: ENTRY PROCEDURE RETURNS [MarkerControl.MarkerStatus] = BEGIN
ENABLE UNWIND => NULL;
WAIT engineStatusChange;
bansheeState.lastEngineStatus ← BansheeEngine.GetStatus[];
RETURN[Status[]];
END; --WaitStatusChange
UpdateBansheeLog: ENTRY PROCEDURE = INLINE
BEGIN ENABLE UNWIND => NULL; NOTIFY updateBansheeLog; END; --UpdateBansheeLog
BansheeLogUpdater: ENTRY PROCEDURE = TRUSTED BEGIN
ENABLE UNWIND => NULL;
Process.SetTimeout[@updateBansheeLog, Process.SecondsToTicks[60 * 30 --secs/min-- ]];
Process.SetPriority[Process.priorityBackground];
DO -- forever
WAIT updateBansheeLog;
IF NOT root.state.idle THEN LOOP;
IF root.state.trace = verbose THEN PSAsyncMsg.PutString["MarkerBansheeCounter.ForceOut"];
BansheeCounter.ForceOut[];
ENDLOOP;
END; --BansheeLogUpdater
GetLatestPaperSize: PROCEDURE = BEGIN
Process.Pause [Process.MsecToTicks[500]]; --Must pause before getting paper size, or correct size will not have been posted yet.
bansheeState.media ← BansheeEngine.GetPaperSize[];
END; --GetLatestPaperSize
StatusChangeWatcher: ENTRY PROCEDURE = BEGIN -- updates the Banshee display if necessary
ENABLE UNWIND => NULL;
engineStatus: BansheeStatus.Type;
DO -- forever
engineStatus ← BansheeEngine.GetStatus[];
SELECT engineStatus FROM
imageFault1, imageFault2, sequenceFault => BEGIN
root.state.engineProblem ← TRUE; -- Stop everything when an imaging error is detected...
root.state.stopStatus ← restart;
root.control.stop ← TRUE;
root.control.start ← root.control.pause ← root.control.resume ←
root.control.pausing ← root.control.resuming ←
root.control.resumeWhenAppropriate ← FALSE;
bansheeState.jobStatus ← imagingError;
BansheeEngine.SetPrintingState[completed];
END;
okay => TRUSTED BEGIN
Process.Detach [FORK GetLatestPaperSize[]]; --This proc is forked because it pauses before getting the current paper size and we don't want to hang up the StatusChangeWatcher with a pause or it might miss the next status change.
IF root.state.activity = markingButInterruptable THEN
root.state.activity ← marking;
root.state.engineProblem ← FALSE;
IF root.state.activity = paused OR root.control.pause THEN
BEGIN
root.control.resume ← TRUE;
IF root.state.trace = verbose THEN
PSAsyncMsg.PutString["Marker.Resume Internal"];
BROADCAST root.event;
END;
END;
ENDCASE => BEGIN
root.state.engineProblem ← TRUE;
IF root.state.activity = marking THEN
BEGIN
root.state.activity ← markingButInterruptable;
root.control.pause ← TRUE;
IF root.state.trace = verbose THEN
PSAsyncMsg.PutString["Marker.Pause Internal"];
BROADCAST root.event;
END;
END;
bansheeState.lastEngineStatus ← engineStatus;
WAIT engineStatusChange;
ENDLOOP;
END; --StatusChangeWatcher
StatusWatcher: PROCEDURE = BEGIN -- Forked process
status: BansheeStatus.Type;
DO -- forever
status ← BansheeEngine.WaitStatus[];
IF status # bansheeState.lastEngineStatus OR status IN [imageFault1..sequenceFault]
must process every image fault so printing gets stopped
THEN TRUSTED BEGIN
Process.Detach[FORK NotifyStatusChange[status]]; -- avoid Monitor locks
IF root.state.trace # none THEN PSAsyncMsg.PutString["Banshee Status Change"];
END;
ENDLOOP;
END; --StatusWatcher
NotifyStatusChange: ENTRY PROCEDURE [status: BansheeStatus.Type] = BEGIN
ENABLE UNWIND => NULL;
bansheeState.lastEngineStatus ← status;
BROADCAST engineStatusChange;
END; --NotifyStatusChange
MarkingControl: ENTRY PROCEDURE [priority: Process.Priority] = BEGIN
ENABLE UNWIND => NULL;
WaitJobState: PROCEDURE [
targetState: PrintingState.Type, targetEqual: BOOLEAN]
RETURNS [pState: PrintingState.Type] = BEGIN -- FORKed to avoid MLs
NotifyJobStateChange: ENTRY PROC = BEGIN NOTIFY jobStateChange; END;
pState ← BansheeEngine.WaitPrintingState[targetState, targetEqual];
NotifyJobStateChange[];
END; --WaitJobState
Process.SetPriority[priority];
DO --forever
SELECT TRUE FROM
root.control.tpQueueEntry AND root.state.idle => BEGIN -- over-rides root.state.stopped
root.state.tpJob ← TRUE;
IF NOT MarkDocument[tpDecomposed] THEN
BEGIN root.control.tpQueueEntry ← FALSE; LOOP; END;
END;
root.control.stop =>
SELECT TRUE FROM
root.state.stopped => NULL;
NOT root.state.idle AND NOT bansheeState.jobStatus = canceled AND NOT
bansheeState.jobStatus = imagingError => BEGIN
root.control.start ← root.control.pause ← root.control.resume ←
root.control.pausing ← root.control.resuming ←
root.control.resumeWhenAppropriate ← FALSE;
bansheeState.jobStatus ← canceled;
BansheeEngine.SetPrintingState[completed];
END;
root.state.idle => BEGIN root.state.stopped ← TRUE; NOTIFY root.stopped; END;
ENDCASE;
root.control.start => BEGIN
root.control.start ← root.state.stopped ← root.control.pause ←
root.control.resume ← root.control.pausing ← root.control.resuming ←
root.control.resumeWhenAppropriate ← FALSE; -- so we don't keep looking here
LOOP; -- make another pass
END;
root.control.pause => BEGIN
IF root.state.activity IN [marking..markingButInterruptable] THEN TRUSTED BEGIN
waitJobState: PROCESS RETURNS [PrintingState.Type];
engineState: PrintingState.Type;
BansheeEngine.SetPrintingState[stopped];
waitJobState ← FORK WaitJobState[started, FALSE]; -- avoid MLs
WAIT jobStateChange;
engineState ← JOIN waitJobState;
IF engineState = stopped THEN root.state.activity ← paused;
root.control.resumeWhenAppropriate ← FALSE;
IF root.state.trace = verbose THEN PSAsyncMsg.PutString["Marking Paused"];
END;
NOTIFY root.paused;
root.control.pause ← FALSE;
END;
root.control.resume OR root.control.resumeWhenAppropriate => BEGIN
root.control.resumeWhenAppropriate ← FALSE;
IF root.state.activity = paused AND BansheeEngine.GetPrintingState[] = stopped AND root.state.clientPause = 0 THEN BEGIN
IF BansheeEngine.GetStatus[] = okay THEN TRUSTED BEGIN
waitJobState: PROCESS RETURNS [PrintingState.Type];
engineState: PrintingState.Type;
BansheeEngine.SetPrintingState[started];
waitJobState ← FORK WaitJobState[stopped, FALSE]; -- avoid MLs
WAIT jobStateChange;
engineState ← JOIN waitJobState;
IF engineState = started THEN root.state.activity ← marking;
IF root.state.trace = verbose THEN
PSAsyncMsg.PutString["Marking Resumed"];
END
ELSE BEGIN
root.control.resumeWhenAppropriate ← TRUE;
IF root.state.trace = verbose THEN
PSAsyncMsg.PutString["Marker.ResumeWhenAppropriate"];
END;
END;
root.control.resume ← FALSE;
END;
NOT root.state.idle => NULL; -- so we don't start multiple markers
root.control.jobQueueEntry => BEGIN
IF NOT MarkDocument[decomposed] THEN
BEGIN root.control.jobQueueEntry ← FALSE; LOOP; END;
END;
ENDCASE;
WAIT root.event;
ENDLOOP;
END; --MarkingControl
MarkDocument: INTERNAL PROCEDURE [fromQ: PrintQueue.QueueStage,
qOH: PrintQueue.QueueObjectHandle ← PrintQueue.nilQueueObjectHandle]
RETURNS [okay: BOOLEAN] = TRUSTED BEGIN
root.state.qOH ← PrintQueue.Requeue[qOH: qOH, fromQueue: fromQ, toQueue: marking];
IF root.state.qOH = PrintQueue.nilQueueObjectHandle THEN RETURN[FALSE];
root.state.idle ← FALSE;
root.state.activity ← marking;
Process.Detach[FORK DoMarking];
IF root.state.trace # none THEN BEGIN
PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR["Marking File \"%g\"; Copy Count: %g", IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.numberCopies]]]];
END;
RETURN[TRUE];
END; -- MarkDocument
DoMarking: PROCEDURE = BEGIN
secondsToWait: LONG INTEGER ← 0;
decomposedDocument: Decompose.Handle ← LOOPHOLE[root.state.qOH.printObjectHandle];
root.state.qOH.currentStatus ← marking;
bansheeState.jobStatus ← normal;
Initialize and set job record:
bansheeState.job.document ← decomposedDocument.docTransferH;
bansheeState.job.copyCount ← root.state.qOH.numberCopies;
bansheeState.job.banner ←
SELECT TRUE FROM
root.state.tpJob => suppressed,
root.state.qOH.bannerOnly => oncePerJob,
ENDCASE => bansheeState.banner;
BansheeEngine.SetJob[bansheeState.job];
IF root.state.waitBetweenJobs THEN BEGIN
<<The client may specify a number of seconds to wait between jobs. Usually this is done to allow spooling when spooling while marking is disabled and decomposing while marking is enabled. With such a set up, spool time is limited.>>
secondsToWait ← --last activity time plus wait time minus current time
BasicTime.Period[
from: BasicTime.Update[lastActivityTimeStamp, root.state.betweenJobWaitTime],
to: BasicTime.Now[]];
IF secondsToWait > 0 THEN BEGIN
IF root.state.trace = verbose THEN BEGIN
PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR["Wait %g seconds to allow spooling", IO.card[secondsToWait]]]];
END;
Process.Pause[Process.SecondsToTicks[CARDINAL[secondsToWait]]]; --Wait a few seconds to allow spooling
END;
END;
root.state.starting[];
root.state.startMarkDate ← BasicTime.Now[];
Check here for copyCount = 0 and don't pass those jobs to engine level...
IF bansheeState.job.copyCount > 0 THEN BEGIN
BansheeEngine.SetPrintingState[started];
[] ← BansheeEngine.WaitPrintingState[started, TRUE];
[] ← BansheeEngine.WaitPrintingState[completed, TRUE]; --returns when done
END;
root.state.finished[];
lastActivityTimeStamp ← BasicTime.Now[];
Queue[
SELECT bansheeState.jobStatus FROM
normal => printed,
imagingError => restart,
ENDCASE => root.state.stopStatus];
MarkerControlInternal.SetActivity[available];
UpdateBansheeLog[];
END; -- DoMarking
Queue: ENTRY PROCEDURE [status: PrintQueue.ObjectStatus] = BEGIN
ENABLE UNWIND => NULL;
nsDone: ROPE ← "Done Marking \"%g\"; seconds = %g";
nsFail: ROPE ← "Mark Failure on \"%g\"; seconds = %g";
p: CARD ← BasicTime.Period[from: lastActivityTimeStamp, to: root.state.startMarkDate];
IF p >= 0 THEN root.state.qOH.markTime ← p;
root.state.qOH.currentStatus ← status;
SELECT TRUE FROM
status = printed OR root.state.tpJob --any tp failure-- => BEGIN
IF root.state.trace # none THEN
PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsDone, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]];
[] ← PrintQueue.Requeue[
qOH: root.state.qOH, fromQueue: marking, toQueue: marked];
END;
status = restart => BEGIN -- requeue document
<<NOTE: Currently restart documents are requeued to the spooled queue. In the future we may with to save the decompose object and requeue them to the decomposed queue. (Currently, the Stop Printing command requeues all decomposed documents to the spooled queue.)>>
IF root.state.trace # none THEN
PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsDone, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]];
IF root.state.qOH.printObjectHandle # NIL THEN BEGIN
Must free decompose handle before requeuing doc.
DecomposerControl.FreeDecomposeObject[root.state.qOH.uid];
root.state.qOH.printObjectHandle ← NIL;
END;
[] ← PrintQueue.Requeue[qOH: root.state.qOH, fromQueue: marking,
toQueue: spooledNormal, position: front];
IF bansheeState.jobStatus = imagingError THEN TRUSTED BEGIN
Process.Detach[FORK root.state.engineFailure[]];
END;
END;
status = canceledInMarker => BEGIN
IF root.state.trace # none THEN
PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsDone, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]];
[] ← PrintQueue.Requeue[qOH: root.state.qOH, fromQueue: marking, toQueue: aborted];
IF root.state.canceledWhileMarking # NIL THEN
root.state.canceledWhileMarking[root.state.qOH.fileName, status];
END;
ENDCASE => BEGIN
IF root.state.trace # none THEN
PSAsyncMsg.PutString[Rope.ToRefText[IO.PutFR[nsFail, IO.text[root.state.qOH.fileName], IO.card[root.state.qOH.markTime]]]];
[] ← PrintQueue.Requeue[qOH: root.state.qOH, fromQueue: marking, toQueue: errors];
END;
bansheeState.job.lastPage ← LAST[CARDINAL]; -- was modified by BansheeEngine??
root.state.tpJob ← FALSE;
root.control.jobQueueEntry ← NOT PrintQueue.Empty[decomposed];
root.control.tpQueueEntry ← NOT PrintQueue.Empty[tpDecomposed];
BROADCAST root.event; -- in case there's something to do
END; --Queue
END. --BansheeMarkerControlImpl
LOG when - who - what
19-Sep-84 13:52:32 - Strickberger - Created based on RavenMarkerControlImpl of 30-Aug-84 13:02:13.
8-Nov-84 16:52:08 - Jacks - Updated to second round of 9.0 interface changes; changed Stop parm from queue to status.
16-Jan-85 16:15:17 - Jacks - Put pause in "okay" arm of select stmt in StatusChangeWatcher to give time for paper size to be updated.
4-Feb-85 13:36:55 - Jacks - Moved SetActivity[available] after Queue[] at end of DoMarking.
17-Jun-85 16:08:32 - Jacks - Added copyright notice; updated to PS Euclid interfaces.
6-Aug-85 9:06:14 - Jacks - Updated to 10.0 DecomposerControl.FreeDecomposeObject.
23-Sep-85 15:22:18 - Jacks - String.AppendLongDecimal sCopies in MarkDocument to avoid Bounds Fault; only pause between jobs if client requests it.
4-Oct-85 9:33:49 - Jacks - Set printObjectHandle to NIL after calling DecomposerControl.FreeDecomposeObject.
21-Oct-85 17:12:44 - Jacks - Converted to new banshee paper def.
1-Nov-85 11:09:42 - Jacks - Check for copyCount=0 in DoMarking.
23-Apr-86 16:34:54 - Jacks - Added code for recognizing image faults in StatusChangeWatcher and dealing correctly with markFailure in Queue; requeue restart docs to FRONT of spooled queue.