-- CedarSnapshotRegistry.mesa -- last edited by Levin: September 7, 1982 1:00 pm DIRECTORY CedarSnapshot USING [CheckpointProc, RollbackProc], CedarSnapshotPrivate USING [], Heap USING [systemZone], Inline USING [LongCOPY]; CedarSnapshotRegistry: MONITOR IMPORTS Heap, Inline EXPORTS CedarSnapshot, CedarSnapshotPrivate = BEGIN Registry: TYPE = LONG POINTER TO Procs; Procs: TYPE = RECORD [ nProcs: CARDINAL ← 0, procs: SEQUENCE nSlots: CARDINAL OF RegisteredProc ← NULL]; RegisteredProc: TYPE = PROC; initialProcs: CARDINAL = 10; incrementProcs: CARDINAL = 5; checkpointRegistry, rollbackRegistry: Registry ← NIL; ProcAlreadyRegistered: ERROR = CODE; ProcNotRegistered: ERROR = CODE; -- Procedures exported to CedarSnapshot Register: PUBLIC ENTRY PROC [ c: CedarSnapshot.CheckpointProc ← NIL, r: CedarSnapshot.RollbackProc ← NIL] = {AddProc[@checkpointRegistry, LOOPHOLE[c]]; AddProc[@rollbackRegistry, LOOPHOLE[r]]}; Deregister: PUBLIC ENTRY PROC [ c: CedarSnapshot.CheckpointProc ← NIL, r: CedarSnapshot.RollbackProc ← NIL] = {RemoveProc[@checkpointRegistry, LOOPHOLE[c]]; RemoveProc[@rollbackRegistry, LOOPHOLE[r]]}; -- Procedures exported to CedarSnapshotPrivate -- The enumerators call the caller-supplied procedure outside the monitor, permitting -- Register/Deregister to be called from within the enumeration. EnumerateCheckpointProcs: PUBLIC PROC [proc: PROC [CedarSnapshot.CheckpointProc]] = { i: CARDINAL ← LAST[CARDINAL]; p: CedarSnapshot.CheckpointProc; GetNext: ENTRY PROC RETURNS [p: CedarSnapshot.CheckpointProc] = INLINE { p ← NIL; i ← MIN[i, checkpointRegistry.nProcs]; IF i > 0 THEN { i ← i - 1; p ← LOOPHOLE[checkpointRegistry.procs[i]]; }; }; IF checkpointRegistry = NIL THEN RETURN; UNTIL (p ← GetNext[]) = NIL DO proc[p]; ENDLOOP; }; EnumerateRollbackProcs: PUBLIC PROC [proc: PROC [CedarSnapshot.RollbackProc]] = { i: CARDINAL ← 0; p: CedarSnapshot.RollbackProc; GetNext: ENTRY PROC RETURNS [p: CedarSnapshot.RollbackProc] = INLINE { p ← NIL; IF i < rollbackRegistry.nProcs THEN { p ← LOOPHOLE[rollbackRegistry.procs[i]]; i ← i + 1; }; }; IF rollbackRegistry = NIL THEN RETURN; UNTIL (p ← GetNext[]) = NIL DO proc[p]; ENDLOOP; }; -- Private Procedures AddProc: INTERNAL PROC [registry: LONG POINTER TO Registry, proc: RegisteredProc] = { IF proc = NIL THEN RETURN; IF registry↑ = NIL THEN registry↑ ← Heap.systemZone.NEW[Procs[initialProcs] ← []]; FOR i: CARDINAL IN [0..registry↑.nProcs) DO IF registry↑.procs[i] = proc THEN ERROR ProcAlreadyRegistered; ENDLOOP; IF registry↑.nProcs = registry↑.nSlots THEN { newRegistry: Registry ← Heap.systemZone.NEW[Procs[registry↑.nSlots+incrementProcs] ← [nProcs: registry↑.nProcs]]; Inline.LongCOPY[from: @registry↑.procs[0], to: @newRegistry.procs[0], nwords: registry↑.nSlots*SIZE[RegisteredProc]]; Heap.systemZone.FREE[registry]; registry↑ ← newRegistry; }; registry↑.procs[registry↑.nProcs] ← proc; registry↑.nProcs ← registry↑.nProcs + 1; }; RemoveProc: INTERNAL PROC [registry: LONG POINTER TO Registry, proc: RegisteredProc] = { state: {looking, compressing} ← looking; FOR i: CARDINAL IN [0..registry↑.nProcs) DO SELECT state FROM looking => IF registry↑.procs[i] = proc THEN state ← compressing; compressing => registry↑.procs[i - 1] ← registry↑.procs[i]; ENDCASE; ENDLOOP; IF state = looking THEN ERROR ProcNotRegistered; registry↑.nProcs ← registry↑.nProcs - 1; }; END.