-- RunsImpl.Mesa -- last edited 26-Mar-82 17:56:53 by Paul Rovner DIRECTORY Environment USING[wordsPerPage], RTFlags USING[checking], RTOS USING[GetPermanentDataPages], RTQuanta USING[PagesPerQuantum], Runs; RunsImpl: MONITOR -- protects runs IMPORTS RTOS EXPORTS Runs = BEGIN OPEN Environment, RTOS, RTQuanta, Runs; -- Signals OverlappingInterval: PUBLIC SIGNAL = CODE; MissingInterval: PUBLIC ERROR = CODE; CantFindInterval: PUBLIC ERROR = CODE; -- Global variables runs: Run _ NIL; RunAllocProc: ENTRY PROC RETURNS[run: Run] = INLINE {ENABLE UNWIND => NULL; IF runs = NIL THEN {p: Run _ GetPermanentDataPages[PagesPerQuantum]; -- NOTE arg must be a multiple of PagesPerQuantum FOR offset: CARDINAL _ 0, offset+SIZE[RunRec] UNTIL offset+SIZE[RunRec] > PagesPerQuantum*wordsPerPage DO q: Run = p+offset; q.rnNext _ runs; runs _ q ENDLOOP}; run _ runs; runs _ runs.rnNext}; RunFreeProc: ENTRY PROC[run: Run] = INLINE {ENABLE UNWIND => NULL; run.rnNext _ runs; runs _ run}; -- Initialization -- Add and delete intervals AddInterval: PUBLIC PROC[pRn: LONG POINTER TO Run, iFrom, n: RunValue] = {iTo: RunValue = iFrom+n; -- not included rn, rnNew: Run; IF RTFlags.checking AND n = 0 THEN ERROR; DO IF (rn _ pRn^) = NIL THEN EXIT; IF rn.iTo >= iFrom THEN -- stop here {SELECT rn.iFrom FROM > iTo => EXIT; -- insert before here = iTo => rn.iFrom _ iFrom; -- just lower iFrom ENDCASE => {IF rn.iTo # iFrom THEN SIGNAL OverlappingInterval[]; IF rn.rnNext # NIL AND rn.rnNext.iFrom <= iTo THEN -- merge {iFrom _ rn.iTo _ rn.rnNext.iTo; DelRun[@rn.rnNext]; LOOP} -- might extend further ELSE IF iTo > rn.iTo THEN rn.iTo _ iTo}; RETURN} ELSE pRn _ @rn.rnNext; ENDLOOP; rnNew _ RunAllocProc[]; -- allocate a new RunRec rnNew^ _ [iFrom: iFrom, iTo: iTo, rnNext: rn]; pRn^ _ rnNew}; -- insert it before rn DeleteInterval: PUBLIC PROC[pRn: LONG POINTER TO Run, iFrom, n: RunValue] = {iTo: RunValue = iFrom+n; rn: Run; IF RTFlags.checking AND n = 0 THEN ERROR; UNTIL (rn _ pRn^) = NIL DO IF rn.iTo <= iFrom THEN {pRn _ @rn.rnNext; LOOP}; -- not there yet IF (iFrom < rn.iFrom) OR (iTo > rn.iTo) THEN ERROR MissingInterval[]; IF iTo = rn.iTo THEN {IF iFrom = rn.iFrom THEN DelRun[pRn] -- delete the entire run ELSE rn.iTo _ iFrom} -- delete a final segment of the run ELSE IF iFrom = rn.iFrom THEN rn.iFrom _ iTo -- delete an initial segment of the run ELSE -- remove a central segment of the run {rn1: Run = RunAllocProc[]; rn1^ _ [iFrom: iTo, iTo: rn.iTo, rnNext: rn.rnNext]; rn.iTo _ iFrom; rn.rnNext _ rn1}; RETURN; ENDLOOP; ERROR MissingInterval[]}; -- Internal procedures DelRun: PROC[pRn: LONG POINTER TO Run] = {rn: Run _ pRn^; pRn^ _ rn.rnNext; RunFreeProc[rn]}; -- Find and map intervals FindInterval: PUBLIC PROC[pRn: LONG POINTER TO Run, n: RunValue] RETURNS[iFrom: RunValue] = {rn: Run; iTo: RunValue; IF RTFlags.checking AND n = 0 THEN ERROR; UNTIL (rn _ pRn^) = NIL DO IF RTFlags.checking AND rn.iTo <= rn.iFrom THEN ERROR; IF rn.iTo >= (iTo _ rn.iFrom+n) THEN {iFrom _ rn.iFrom; IF iTo = rn.iTo THEN DelRun[pRn] ELSE rn.iFrom _ iTo; RETURN}; pRn _ @rn.rnNext; ENDLOOP; ERROR CantFindInterval[]}; MapIntervals: PUBLIC PROC[pRn: LONG POINTER TO Run, proc: PROC[iFrom, n: RunValue]] = {rn: Run; rnNext: Run _ pRn^; UNTIL (rn _ rnNext) = NIL DO rnNext _ rn.rnNext; -- OK if proc deletes rn, not OK if merge occurs IF RTFlags.checking AND rn.iTo <= rn.iFrom THEN ERROR; proc[rn.iFrom, rn.iTo-rn.iFrom]; ENDLOOP}; END.