<> <> DIRECTORY FSLock; FSPkgRefImpl: CEDAR MONITOR EXPORTS FSLock = BEGIN <> RecordREF: PUBLIC ENTRY PROC [r: REF] = BEGIN p: REF PRTEntry = NEW [PRTEntry]; hash: CARDINAL = Hash[r]; p.ref _ r; p.chain _ prt[hash]; prt[hash] _ p; recorded _ recorded + 1; END; RemoveREF: PUBLIC ENTRY PROC [r: REF] = BEGIN hash: CARDINAL = Hash[r]; p, q: REF PRTEntry; q _ prt[hash]; IF q.ref = r THEN prt[hash] _ q.chain ELSE DO p _ q; q _ q.chain; IF q.ref = r THEN {p.chain _ q.chain; EXIT}; ENDLOOP; q.ref _ NIL; removed _ removed + 1; END; <> buckets: CARDINAL = 251; PackageReferenceTable: TYPE = ARRAY [0..buckets) OF REF PRTEntry; PRTEntry: TYPE = RECORD [chain: REF PRTEntry, ref: REF]; prt: REF PackageReferenceTable _ NEW [PackageReferenceTable _ ALL[NIL]]; Hash: PROC [r: REF] RETURNS [CARDINAL] = INLINE { RETURN [ LOOPHOLE[r, LONG CARDINAL] MOD buckets] }; <> recorded, removed: INT _ 0; Stats: ENTRY PROC RETURNS [items, longestChain: INT, chains: ARRAY [0..10] OF CARDINAL] = BEGIN items _ 0; longestChain _ 0; chains _ ALL[0]; FOR i: CARDINAL IN [0 .. buckets) DO chainLength: INT _ 0; cIndex: CARDINAL; FOR p: REF PRTEntry _ prt[i], p.chain UNTIL p = NIL DO chainLength _ chainLength + 1; ENDLOOP; items _ items + chainLength; IF chainLength > longestChain THEN longestChain _ chainLength; cIndex _ MIN [chainLength, 10]; chains[cIndex] _ chains[cIndex] + 1; ENDLOOP; END; END.