CollectorWatchdogImpl.mesa
Russ Atkinson, May 9, 1984 12:42:39 pm PDT
DIRECTORY
CollectorWatchdog 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 CollectorWatchdog, PrincOpsUtils, Process, SafeStorage
EXPORTS CollectorWatchdog
= BEGIN
PDA: PrincOps.PDABase = PrincOps.PDA;
latency: PUBLIC CARDINAL ← 2000; -- milliseconds
timesBumped: INT ← 0;
enabled: BOOLTRUE;
ResetPriority: PROC
[psb: PrincOps.PsbHandle, new: PrincOps.Priority] RETURNS [success: BOOLTRUE] = {
This routine sets the priority of the specified process.
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 {
We need to preserve the number of state vectors at various priorities. The easiest way to do this is to transfer a state vector from the new priority list to the old priority list, which allows the current state vector to remain with the process.
nsv: PrincOps.StateVectorHandle ← PDA.state[new];
IF nsv = PrincOps.NullStateVectorHandle THEN GO TO fail;
If there is no available state vector at that priority, then we lose.
Remove the new state vector from its priority chain
PDA.state[new] ← LOOPHOLE[PDA[nsv].stk[0]];
Give the new state vector to the old priority chain.
PDA[nsv].stk[0] ← PDA.state[old];
PDA.state[old] ← nsv;
};
At this point we can alter the priority and assume success.
PDA[psb].link.priority ← new;
If the process that is getting its priority changed is on the ready queue we must remove it from the queue and put it back, thereby changing its position in the queue. If it was not on the ready queue, we hope that changing its priority did not upset someone who was depending on priorities being sorted within other kinds of queues. We will see what we will see!
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[CollectorWatchdog.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 the collector is not active OR is a different collection, then wait until it is
IF NOT active OR count # lag THEN LOOP;
At this point the collector is running and it has been running more than the required latency for being bumped. So bump the priority and try again.
{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]];
We could not change the priority because there were no state vectors at the target priority level, so we wait a brief while for either success or for something else to change about the collection.
[active, count] ← SafeStorage.IsCollectorActive[];
IF NOT active OR count # lag THEN EXIT;
ENDLOOP;
};
ENDLOOP;
};
Process.Detach[FORK BailOutCollector[]];
END.