<> <> 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: BOOLEAN _ FALSE; 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: BOOLEAN _ FALSE; 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.