PDInterpControlImpl.mesa
Michael Plass, November 11, 1983 2:14 pm
DIRECTORY PDInterpBasic, PDInterpControl, PDFileFormat, PDInterpInput, PDInterpPage, PDInterpReader, Process;
PDInterpControlImpl: MONITOR
IMPORTS PDInterpInput, PDInterpPage, PDInterpReader, Process
EXPORTS PDInterpControl
~ BEGIN OPEN PDInterpControl;
queueMaxSize: NAT ~ 10;
QueueEntry: TYPE ~ RECORD [
inputHandle: PDInterpInput.Handle,
pageSpec: PageSpec
];
queueSize: NAT ← 0;
queue: ARRAY [0..queueMaxSize) OF QueueEntry;
queueChange: CONDITION;
JobDone: ENTRY PROC ~ {
FOR i: NAT IN [1..queueSize) DO
queue[i-1] ← queue[i];
ENDLOOP;
queueSize ← queueSize - 1;
BROADCAST queueChange;
};
ReQueue: ENTRY PROC ~ {
queueEntry: QueueEntry ← queue[0];
FOR i: NAT IN [1..queueSize) DO
queue[i-1] ← queue[i];
ENDLOOP;
queue[queueSize-1] ← queueEntry;
BROADCAST queueChange;
};
UnQueue: ENTRY PROC [handle: PDInterpInput.Handle] ~ {
found: BOOLEANFALSE;
FOR i: NAT IN [1..queueSize) DO
IF found THEN queue[i-1] ← queue[i]
ELSE found ← queue[i].inputHandle = handle;
ENDLOOP;
IF found THEN {queueSize ← queueSize - 1; BROADCAST queueChange};
};
RequestService: PUBLIC ENTRY PROC [handle: PDInterpInput.Handle, pageSpec: PageSpec] ~ {
UNTIL queueSize < queueMaxSize DO WAIT queueChange ENDLOOP;
queue[queueSize] ← [handle, pageSpec];
queueSize ← queueSize + 1;
BROADCAST queueChange;
};
PrintOne: PROC [reader: PDInterpReader.Handle] ~ {
finished: BOOLEANFALSE;
FOR i: NAT IN [0..maxRanges) UNTIL finished DO
pageRange: PageRange ← queue[0].pageSpec[i];
skip: NAT ← pageRange.skipCount;
UNTIL finished OR skip = 0 DO
WITH PDInterpReader.Get[reader] SELECT FROM
stateChange: PDInterpReader.CommandBuffer.stateChange => {
SELECT stateChange.whatChanged FROM
imageStart => finished ← PDInterpInput.ReportStatus[reader.input, startImage, queueSize, 0, reader.page, reader.pass, reader.index].abort;
documentEnd => finished ← TRUE;
imageEnd => skip ← skip - 1;
ENDCASE => NULL;
};
ENDCASE => NULL;
ENDLOOP;
UNTIL finished OR pageRange.printCount = 0 DO
IF PDInterpPage.InterpretPage[reader].ok THEN {
finished ← PDInterpInput.ReportStatus[reader.input, startImage, queueSize, 0, reader.page, reader.pass, reader.index].abort;
pageRange.printCount ← pageRange.printCount - 1;
pageRange.skipCount ← pageRange.skipCount + 1;
}
ELSE finished ← TRUE;
ENDLOOP;
queue[0].pageSpec[i] ← pageRange;
ENDLOOP;
[] ← PDInterpInput.ReportStatus[reader.input, transmissionComplete, queueSize, 0, reader.page, reader.pass, reader.index];
};
WaitForOne: ENTRY PROC ~ {
UNTIL queueSize > 0 DO WAIT queueChange ENDLOOP;
};
PrintProcess: PROC ~ {
reader: PDInterpReader.Handle ← NIL;
ReportStatus: PROC [status: PDInterpBasic.Status] RETURNS [abort: BOOLEAN] ~ {
IF reader = NIL THEN {
abort ← PDInterpInput.ReportStatus[
handle: queue[0].inputHandle,
status: status,
queueSize: queueSize,
queuePosition: 0,
page: 0,
pass: 0,
sourceIndex: 0
]
}
ELSE {
abort ← PDInterpInput.ReportStatus[
handle: queue[0].inputHandle,
status: status,
queueSize: queueSize,
queuePosition: 0,
page: reader.page,
pass: reader.pass,
sourceIndex: reader.index
]
};
};
DO ENABLE PDInterpReader.Warning => {IF ReportStatus[code].abort THEN CONTINUE ELSE RESUME};
WaitForOne[];
reader ← PDInterpReader.Open[queue[0].inputHandle
! PDInterpReader.Error => {[]←ReportStatus[code]; CONTINUE}
];
IF reader # NIL THEN {
PrintOne[reader ! PDInterpReader.Error => {[] ← ReportStatus[code]; CONTINUE}];
reader ← PDInterpReader.Close[reader];
};
JobDone[];
ENDLOOP;
};
QueueWatch: PROC = {
snapshot: ARRAY [0..queueMaxSize) OF PDInterpInput.Handle;
count: NAT;
SnapshotQueue: ENTRY PROC ~ {
WAIT queueChange;
count ← queueSize;
FOR i: NAT IN [0..count) DO
snapshot[i] ← queue[i].inputHandle;
ENDLOOP;
};
DO
SnapshotQueue[];
FOR i: NAT IN [1..count) DO
IF PDInterpInput.ReportStatus[snapshot[i], queued, queueSize, i, 0, 0, 0].abort THEN UnQueue[snapshot[i]];
ENDLOOP;
ENDLOOP;
};
Process.Detach[FORK QueueWatch[]];
Process.Detach[FORK PrintProcess[]];
END.