XNSPSSpoolerImpl.mesa
Copyright Ó 1986, 1987 by Xerox Corporation. All rights reserved.
Tim Diebert: February 9, 1987 4:10:10 pm PST
DIRECTORY
BasicTime USING [Now],
CrRPC USING [BulkDataCheckAbortProc, BulkDataSource, Handle],
FS USING [Delete, Error, StreamOpen],
IO USING [rope, card, Close, PutF, PutFR1, RopeFromROS, ROS, STREAM, Value],
PrintingP4V3Aux USING [ExposePrintAttributes, ExposePrintOptions],
Process USING [Detach],
Rope USING [ROPE],
PrintingP4V3,
XNSPSMessages USING [LogMessage],
XNSPSPrint USING [PrintFile],
XNSPSSpooler;
XNSPSSpoolerImpl:
CEDAR
MONITOR
IMPORTS BasicTime, FS, IO, PrintingP4V3Aux, Process, XNSPSMessages, XNSPSPrint
EXPORTS XNSPSSpooler, PrintingP4V3 ~ {
OPEN PrintingP4V3;
Copied Types
BulkDataSource: TYPE ~ CrRPC.BulkDataSource;
Handle: TYPE ~ CrRPC.Handle;
ROPE: TYPE ~ Rope.ROPE;
Global vars
properties: PrintingP4V3.PrinterProperties;
PrintQueue
spoolerBusy, formatterBusy, printerBusy: BOOL ← FALSE;
State: TYPE = {empty, spooling, spooled, printing, done, aborted};
maxQueue: CARDINAL = 10;
QueueIndex: TYPE = [0 .. maxQueue);
nextEmpty: QueueIndex ← 0; -- Next available.
queue: PrintQueue;
queueChanged: CONDITION;
queueCount: INTEGER ← 0;
PrintQueue: TYPE = ARRAY QueueIndex OF PrintQueueEntry;
PrintQueueEntry:
TYPE =
RECORD [
id: PrintingP4V3.RequestID ← [0, 0, 0, 0, 0],
fileName: ROPE ← NIL,
state: State ← empty,
printAttributes: PrintingP4V3.PrintAttributes ← NIL,
printOptions: PrintingP4V3.PrintOptions ← NIL
];
Helper PROCs
ConstructPrinterStatus:
PROC [spoolerBusy, formatterBusy, printerBusy:
BOOL]
RETURNS [printerStatus: PrinterStatus] ~ {
printerStatus ← NEW[ PrinterStatusObject[4] ];
TRUSTED {printerStatus.body[0] ← [spooler[IF spoolerBusy THEN busy ELSE available]]};
TRUSTED {printerStatus.body[1] ← [formatter[IF formatterBusy THEN busy ELSE available]]};
TRUSTED {printerStatus.body[2] ← [printer[IF printerBusy THEN busy ELSE available]]};
TRUSTED {printerStatus.body[3] ← [media[ConstructMedia[]]]};
};
I/O Procs
Logger:
ENTRY
PROC [format: Rope.
ROPE ←
NIL, v1, v2, v3, v4, v5:
IO.Value ← [null[]],
id: PrintingP4V3.RequestID] ~ {
out: IO.STREAM ← IO.ROS[]; r: ROPE;
IO.PutF[out, format, v1, v2, v3, v4, v5];
r ← IO.RopeFromROS[out];
XNSPSMessages.LogMessage[r, id];
};
Errors
Busy: PUBLIC ERROR ~ CODE;
ConnectionError: PUBLIC ERROR [problem: ConnectionProblem] ~ CODE;
InsufficientSpoolSpace: PUBLIC ERROR ~ CODE;
InvalidPrintParameters: PUBLIC ERROR ~ CODE;
MasterTooLarge: PUBLIC ERROR ~ CODE;
MediumUnavailable: PUBLIC ERROR ~ CODE;
ServiceUnavailable: PUBLIC ERROR ~ CODE;
SpoolingDisabled: PUBLIC ERROR ~ CODE;
SpoolingQueueFull: PUBLIC ERROR ~ CODE;
SystemError: PUBLIC ERROR ~ CODE;
TooManyClients: PUBLIC ERROR ~ CODE;
TransferError: PUBLIC ERROR [problem: TransferProblem] ~ CODE;
Undefined: PUBLIC ERROR [problem: CARDINAL] ~ CODE;
Active Procs
currentID: PrintingP4V3.RequestID ← [0, 0, 0, 0, 0];
GetNextID:
ENTRY PROC []
RETURNS [id: PrintingP4V3.RequestID] = {
ENABLE UNWIND => NULL;
md: MACHINE DEPENDENT RECORD [lo, hi: CARDINAL]; i: CARD;
md1: MACHINE DEPENDENT RECORD [lo, hi: CARDINAL] ← LOOPHOLE[BasicTime.Now[]];
md.lo ← currentID[4]; md.hi ← currentID[3];
i ← LOOPHOLE[md];
i ← i + 1;
md ← LOOPHOLE[i];
currentID[4] ← md.lo; currentID[3] ← md.hi;
currentID[2] ← md1.lo; currentID[1] ← md1.hi;
RETURN [currentID];
};
GetPrinterProperties:
PUBLIC
PROC [h: Handle]
RETURNS [PrinterProperties] ~ {
REPORTS [ServiceUnavailable, SystemError, Undefined]
RETURN[properties];
};
ConvertToRequestStatus:
PROC [s: State]
RETURNS [PrintingP4V3.InterpressMasterStatus] = {
RETURN [
SELECT s
FROM
empty => unknown,
spooling => pending,
spooled => pending,
printing => inProgress,
done => completed,
aborted => aborted,
ENDCASE => ERROR];
};
GetPrintRequestStatus:
PUBLIC
PROC [h: Handle, printRequestID: RequestID]
RETURNS [status: RequestStatus] ~
TRUSTED {
REPORTS [ServiceUnavailable, SystemError, Undefined]
FOR i: QueueIndex
IN QueueIndex
DO
IF queue[i].id = printRequestID
THEN {
status ← NEW[RequestStatusObject[1]];
status.body[0] ← [status[ConvertToRequestStatus[queue[i].state]]];
RETURN [status];
};
ENDLOOP;
status ← NEW[RequestStatusObject[1]];
status.body[0] ← [status[unknown]];
RETURN [status];
};
EnumerateQueue:
PUBLIC
PROC [
p:
PROC [id: PrintingP4V3.RequestID, status: PrintingP4V3.InterpressMasterStatus,
printAttributes: PrintingP4V3.PrintAttributes, printOptions: PrintingP4V3.PrintOptions]
RETURNS [continue:
BOOL]] =
BEGIN
FOR i: QueueIndex
IN QueueIndex
DO
cont: BOOL;
cont ← p[queue[i].id, ConvertToRequestStatus[queue[i].state], queue[i].printAttributes, queue[i].printOptions];
IF ~cont THEN EXIT;
ENDLOOP;
END;
GetPrinterStatus:
PUBLIC
PROC [h: Handle]
RETURNS [status: PrinterStatus] ~ {
REPORTS [ServiceUnavailable, SystemError, Undefined]
status ← ConstructPrinterStatus[spoolerBusy, formatterBusy, printerBusy];
RETURN[status];
};
FindQueueSlot:
ENTRY
PROC
RETURNS [slot: QueueIndex] = {
ENABLE UNWIND => NULL;
FOR i: QueueIndex
IN QueueIndex
DO
IF queue[i].state = empty
OR queue[i].state = done
OR queue[i].state = aborted
THEN {
queue[i].state ← spooling;
RETURN[i];
};
ENDLOOP;
ERROR SpoolingQueueFull;
};
Print:
PUBLIC
PROC [h: Handle, master: BulkDataSource, printAttributes: PrintAttributes, printOptions: PrintOptions]
RETURNS [printRequestID: RequestID] ~ {
REPORTS [Busy, ConnectionError, InsufficientSpoolSpace, InvalidPrintParameters, MasterTooLarge, MediumUnavailable, ServiceUnavailable, SpoolingDisabled, SpoolingQueueFull, SystemError, TooManyClients, TransferError, Undefined]
current: QueueIndex;
MarkQueued:
ENTRY
PROC = {
ENABLE UNWIND => NULL;
queue[current].state ← spooled;
queueCount ← queueCount + 1;
BROADCAST queueChanged;
};
aborted, sendAbort: BOOL ← FALSE;
out: IO.STREAM ← NIL;
CheckAbort: CrRPC.BulkDataCheckAbortProc ~ {abort ← sendAbort};
{
-- for exit
printRequestID ← GetNextID[];
Logger[format: "Print called:", id: printRequestID];
Logger[format: " printAttributes: %g", v1: IO.rope[PrintingP4V3Aux.ExposePrintAttributes[printAttributes, 2]], id: printRequestID];
Logger[format: " printOptions: %g", v1: IO.rope[PrintingP4V3Aux.ExposePrintOptions[printOptions, 2]], id: printRequestID];
current ← FindQueueSlot[];
queue[current].id ← printRequestID;
queue[current].state ← spooling;
spoolerBusy ← TRUE;
queue[current].printAttributes ← printAttributes;
queue[current].printOptions ← printOptions;
FS.Delete[queue[current].fileName ! FS.Error => CONTINUE];
out ← FS.StreamOpen[queue[current].fileName, $create];
aborted ← master[h, out, CheckAbort ! FS.Error => {sendAbort ← TRUE; GOTO Abort}];
IF out # NIL THEN IO.Close[out];
IF aborted THEN GOTO Abort;
spoolerBusy ← FALSE;
MarkQueued[];
EXITS Abort => {
FS.Delete[queue[current].fileName ! FS.Error => CONTINUE];
queue[current].state ← empty;
spoolerBusy ← FALSE;
ERROR TransferError[aborted];
};
}; -- for exit
};
DecomposeAndPrint:
PROC [] = {
Wait: ENTRY PROC [] ={ENABLE UNWIND => NULL; WAIT queueChanged};
current: QueueIndex ← 0; potential: QueueIndex; found, abort, ok: BOOL ← FALSE;
DO
-- Forever
WHILE queueCount <= 0 DO Wait[] ENDLOOP;
found ← FALSE;
FOR i: QueueIndex
IN QueueIndex
DO
potential ← (current + i) MOD maxQueue;
IF queue[potential].state = spooled THEN {current ← potential; found ← TRUE; EXIT};
ENDLOOP;
IF ~found THEN LOOP; -- Excess queueChanged
queue[current].state ← printing;
abort ← FALSE;
formatterBusy ← printerBusy ← TRUE;
ok ← XNSPSPrint.PrintFile[id: queue[current].id, fileName: queue[current].fileName, printAttributes: queue[current].printAttributes, printOptions: queue[current].printOptions ! ABORTED => {abort ← TRUE; CONTINUE}];
queue[current].state ← IF abort OR ~ok THEN aborted ELSE done;
formatterBusy ← printerBusy ← FALSE;
queueCount ← queueCount - 1;
ENDLOOP; -- Forever
};
Init Procs
ConstructPrinterProperties:
PROC []
RETURNS [properties: PrinterProperties] ~ {
properties ← NEW[ PrinterPropertiesObject[3] ];
TRUSTED { properties.body[0] ← [ppmedia[ConstructMedia[]]] };
TRUSTED { properties.body[1] ← [ppstaple[FALSE]] };
TRUSTED { properties.body[2] ← [pptwoSided[FALSE]] };
};
ConstructMedia:
PROC []
RETURNS [media: Media] ~ {
media ← NEW[ MediaObject[1] ];
TRUSTED { media.body[0] ← [paper[paper: [knownSize[usLetter]]]] };
TRUSTED { media.body[n] ← [paper[otherSize[width: mm, length: 0]]] }; -- zero is infinity!
};
SetUpQueue:
PROC [] = {
FOR i: QueueIndex
IN QueueIndex
DO
queue[i].fileName ← IO.PutFR1["///Spool/File%02g.ip", IO.card[i]];
FS.Delete[queue[i].fileName ! FS.Error => CONTINUE];
ENDLOOP;
};
Init:
ENTRY
PROC ~ {
properties ← ConstructPrinterProperties[];
SetUpQueue[];
TRUSTED {Process.Detach[FORK DecomposeAndPrint[]]};
};
Init[];
}...