<> <> <> DIRECTORY Collector USING [backgroundCollectorProcess], PrincOps USING [ NullStateVectorHandle, PDA, PDABase, Priority, PsbHandle, StateVectorHandle], PrincOpsUtils USING [DisableInterrupts, EnableInterrupts, PsbIndexToHandle, Requeue], Process USING [Detach, MsecToTicks, Pause, priorityClient3, SetPriority], SafeStorage USING [IsCollectorActive, WaitForCollectorStart]; CollectorWatchdogImpl: PROGRAM IMPORTS Collector, PrincOpsUtils, Process, SafeStorage EXPORTS Collector = BEGIN PDA: PrincOps.PDABase = PrincOps.PDA; latency: PUBLIC CARDINAL _ 2000; -- milliseconds timesBumped: INT _ 0; enabled: BOOL _ TRUE; ResetPriority: PROC [psb: PrincOps.PsbHandle, new: PrincOps.Priority] RETURNS [success: BOOL _ TRUE] = { <> old: PrincOps.Priority; PrincOpsUtils.DisableInterrupts[]; old _ PDA[psb].link.priority; IF old # new THEN { self: PrincOps.PsbHandle = PrincOpsUtils.PsbIndexToHandle[ PDA[PrincOpsUtils.PsbIndexToHandle[PDA.ready.tail]].link.next]; npsb: PrincOps.PsbHandle _ PrincOpsUtils.PsbIndexToHandle[PDA[self].link.next]; IF PDA[psb].link.vector THEN { <> nsv: PrincOps.StateVectorHandle _ PDA.state[new]; IF nsv = PrincOps.NullStateVectorHandle THEN GO TO fail; <> <> PDA.state[new] _ LOOPHOLE[PDA[nsv].stk[0]]; <> PDA[nsv].stk[0] _ LOOPHOLE[PDA.state[old]]; PDA.state[old] _ nsv; }; <> PDA[psb].link.priority _ new; <> DO IF npsb = self THEN EXIT; IF npsb = psb THEN { PrincOpsUtils.Requeue[@PDA.ready, @PDA.ready, psb]; EXIT; }; npsb _ PrincOpsUtils.PsbIndexToHandle[PDA[npsb].link.next]; ENDLOOP; EXITS fail => {success _ FALSE}; }; PrincOpsUtils.EnableInterrupts[]; }; BailOutCollector: PROC = { psb: PrincOps.PsbHandle _ PrincOpsUtils.PsbIndexToHandle[LOOPHOLE[Collector.backgroundCollectorProcess]]; lag: INT _ 0; Process.SetPriority[Process.priorityClient3]; WHILE enabled DO active: BOOL; count: INT; [incarnation: lag] _ SafeStorage.WaitForCollectorStart[]; Process.Pause[Process.MsecToTicks[latency]]; [active, count] _ SafeStorage.IsCollectorActive[]; <> IF NOT active OR count # lag THEN LOOP; <> {priority: PrincOps.Priority = PDA[psb].link.priority; IF priority < Process.priorityClient3 THEN THROUGH [0..100) DO IF ResetPriority[psb, priority + 1] THEN { timesBumped _ timesBumped + 1; EXIT; }; Process.Pause[Process.MsecToTicks[100]]; <> [active, count] _ SafeStorage.IsCollectorActive[]; IF NOT active OR count # lag THEN EXIT; ENDLOOP; }; ENDLOOP; }; Process.Detach[FORK BailOutCollector[]]; END.