<> <> <> <> 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; <> Count: TYPE = INT; takingStatistics: BOOL = TRUE; Bump: PROC[p: POINTER TO Count, delta: Count _ 1] = 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 <> EnterRCOvAndCallBack: PUBLIC ENTRY PROC[proc: PROC] = {ENABLE UNWIND => NULL; proc[]; }; <> RCOvReset: PUBLIC --INTERNAL-- PROC = { rl: RCOverflowChain _ rcOverflowChain; UNTIL rl = NIL DO next: RCOverflowChain _ rl.rest; uz.FREE[@rl]; rl _ next; ENDLOOP; rcOverflowChain _ NIL; }; <> <> 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; }; <> <> <> 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; }; <> 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]; }; <> <> 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.