RCOvImpl.mesa
Last Modified On December 6, 1983 11:14 am By Paul Rovner
DIRECTORY
Allocator USING[NHeaderP, RefCount],
AllocatorOps USING[REFToNHP],
UnsafeStorage USING[GetSystemUZone],
ZCT USING[IncrForUnderflow, DecrForOverflow];
RCOvImpl: MONITOR -- protects rcOverflowChain
IMPORTS AllocatorOps, UnsafeStorage, ZCT
EXPORTS ZCT
= BEGIN OPEN Allocator, AllocatorOps, ZCT;
rcDelta: RefCount = 16;
RCOverflowChain: TYPE = LONG POINTER TO RCOverflowChainRec;
RCOverflowChainRec: TYPE = RECORD[
nhp: NHeaderP,
count: NAT, -- count of rcDelta deposits in the bank for this REF
rest: RCOverflowChain
];
uz: UNCOUNTED ZONE = UnsafeStorage.GetSystemUZone[];
rcOverflowChain: RCOverflowChain ← NIL;
-- Statistics
Count: TYPE = INT;
takingStatistics: BOOL = TRUE;
Bump: PROC[p: POINTER TO Count, delta: Count ← 1] =
usage: Bump[@stats.nHandleRCUnderflow];
INLINE {IF takingStatistics THEN p^ ← p^+delta};
StatsRec: TYPE = RECORD
[ nHandleRCUnderflow: Count ← 0,
nHandleRCOverflow: Count ← 0,
nOldDeposit: Count ← 0,
nNewDeposit: Count ← 0,
nInnerWithdrawal: Count ← 0,
nLastWithdrawal: Count ← 0
];
stats: StatsRec ← []; -- the one and only
Called from the TAndS collector
EnterRCOvAndCallBack: PUBLIC ENTRY PROC[proc: PROC] = {ENABLE UNWIND => NULL;
proc[];
};
Called from the TAndS collector
RCOvReset: PUBLIC --INTERNAL-- PROC = {
rl: RCOverflowChain ← rcOverflowChain;
UNTIL rl = NIL DO
next: RCOverflowChain ← rl.rest;
uz.FREE[@rl];
rl ← next;
ENDLOOP;
rcOverflowChain ← NIL;
};
Called from the TAndS ... the decrement was NOT done
HandleRCUnderflow may pageFault
InnerHandleRCUnderflow: PUBLIC --INTERNAL-- PROC[ref: REF] = {
nhp: NHeaderP ← REFToNHP[ref];
Bump[@stats.nHandleRCUnderflow];
IF nhp.refCount # 0 OR NOT nhp.rcOverflowed THEN ERROR;
nhp.refCount ← nhp.refCount + rcDelta;
IF Withdraw[nhp].accountClosed THEN nhp.rcOverflowed ← FALSE;
};
Called from AssignRef and from ReclaimedRef ... the decrement was NOT done
HandleRCUnderflow may pageFault
This and the above proc are the only ones that set nhp.rcOverflowed ← FALSE
HandleRCUnderflow: PUBLIC ENTRY PROC[ref: REF] = {ENABLE UNWIND => NULL;
nhp: NHeaderP ← REFToNHP[ref];
Bump[@stats.nHandleRCUnderflow];
IF nhp.rcOverflowed
AND IncrForUnderflow[rcDelta, nhp].success
AND Withdraw[nhp].accountClosed
THEN nhp.rcOverflowed ← FALSE;
};
Called only from the TAndS ... NEITHER the increment nor the assignment was done
InnerHandleRCOverflow: PUBLIC --INTERNAL-- PROC[ref: REF] = {
nhp: NHeaderP ← REFToNHP[ref];
Bump[@stats.nHandleRCOverflow];
IF nhp.refCount # LAST[RefCount] THEN ERROR;
nhp.refCount ← nhp.refCount - rcDelta;
nhp.rcOverflowed ← TRUE; -- mark nhp as having an rc deposit
Deposit[nhp];
};
Called only from AssignRef ... NEITHER the increment nor the assignment was done
This and InnerHandleRCOverflow are the only procs that set nhp.rcOverflowed ← TRUE
HandleRCOverflow: PUBLIC ENTRY PROC[ref: REF] = {ENABLE UNWIND => NULL;
nhp: NHeaderP ← REFToNHP[ref];
Bump[@stats.nHandleRCOverflow];
IF NOT DecrForOverflow[rcDelta, nhp].success THEN RETURN;
nhp.rcOverflowed ← TRUE; -- mark nhp as having an rc deposit
Deposit[nhp];
};
Deposit: --INTERNAL-- PROC[nhp: Allocator.NHeaderP] = {
FOR rl: RCOverflowChain ← rcOverflowChain, rl.rest UNTIL rl = NIL
DO IF nhp = rl.nhp THEN {rl.count ← rl.count + 1; Bump[@stats.nOldDeposit]; RETURN} ENDLOOP;
Bump[@stats.nNewDeposit];
rcOverflowChain
← uz.NEW[RCOverflowChainRec ← [nhp: nhp, count: 1, rest: rcOverflowChain]];
};
Withdraw: --INTERNAL-- PROC[nhp: Allocator.NHeaderP] RETURNS[accountClosed: BOOL] = {
rl: RCOverflowChain;
prev: RCOverflowChain ← NIL;
FOR rl ← rcOverflowChain, rl.rest UNTIL rl = NIL DO
IF nhp = rl.nhp THEN {
rl.count ← rl.count - 1;
IF rl.count = 0 THEN { -- close the account
IF prev = NIL
THEN rcOverflowChain ← rl.rest
ELSE prev.rest ← rl.rest;
uz.FREE[@rl];
Bump[@stats.nLastWithdrawal];
RETURN[TRUE];
}
ELSE {Bump[@stats.nInnerWithdrawal]; RETURN[FALSE]};
}
ELSE prev ← rl;
ENDLOOP;
ERROR;
};
END.