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[];
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.