<<>> <> <> <> <> <<>> DIRECTORY Finalize, FinalizeOps, Process; FinalizeOpsImpl: CEDAR MONITOR IMPORTS Finalize, Process EXPORTS FinalizeOps ~ BEGIN <<>> Handle: TYPE = FinalizeOps.Handle; FinalizeProc: TYPE = FinalizeOps.FinalizeProc; CallQueue: TYPE = REF CallQueueRep; CallQueueRep: PUBLIC TYPE = MONITORED RECORD [ finalize: FinalizeProc, priority: Process.Priority, active: BOOL ¬ FALSE, front: LIST OF Handle ¬ NIL, tail: LIST OF Handle ¬ NIL ]; fq: Finalize.FinalizationQueue ~ Finalize.NewFQ[]; IsCallQueue: PUBLIC PROC [x: REF] RETURNS [BOOL] = { RETURN [ISTYPE[x, CallQueue]] }; <<>> NarrowCallQueue: PUBLIC PROC [x: REF] RETURNS [CallQueue] = { RETURN [NARROW[x, CallQueue]] }; <<>> IsFinalizeOpsHandle: PUBLIC PROC [handle: Finalize.Handle] RETURNS [BOOL] = { WITH Finalize.GetClientData[handle] SELECT FROM cq: CallQueue => RETURN [TRUE]; ENDCASE => RETURN [FALSE]; }; EnableFinalization: PUBLIC PROC [object: REF, callQueue: FinalizeOps.CallQueue] RETURNS [handle: Handle] = { handle ¬ Finalize.EnableFinalization[object, fq, callQueue]; }; <<>> ReenableFinalization: PUBLIC PROC [handle: Handle] RETURNS [oldState: Finalize.FinalizationState] = { WITH Finalize.GetClientData[handle] SELECT FROM cq: CallQueue => oldState ¬ Finalize.ReenableFinalization[handle, fq]; ENDCASE => ERROR; }; <<>> CreateCallQueue: PUBLIC PROC [finalize: FinalizeProc, priority: Process.Priority ¬ Process.priorityForeground] RETURNS [cq: CallQueue] = { cq ¬ NEW[CallQueueRep ¬ [finalize: finalize, priority: priority]]; }; HandleToObject: PUBLIC PROC [handle: Handle] RETURNS [object: REF] = { RETURN [Finalize.HandleToObject[handle]] }; <<>> freeList: LIST OF Handle ¬ NIL; DisposeList: INTERNAL PROC [l: LIST OF Handle] = INLINE { l.first ¬ NIL; l.rest ¬ freeList; freeList ¬ l }; NewList: INTERNAL PROC [h: Handle] RETURNS [l: LIST OF Handle] = INLINE { l ¬ freeList; IF l=NIL THEN l ¬ LIST[h] ELSE {freeList ¬ l.rest; l.first ¬ h; l.rest ¬ NIL} }; Forward: ENTRY PROC [cq: CallQueue, h: Handle] RETURNS [mustFork: BOOL ¬ FALSE] = { <<--Assert h#NIL>> list: LIST OF Handle ¬ NewList[h]; IF cq.front=NIL THEN cq.front ¬ list ELSE cq.tail.rest ¬ list; cq.tail ¬ list; IF ~cq.active THEN cq.active ¬ mustFork ¬ TRUE; }; Fetch: ENTRY PROC [cq: CallQueue] RETURNS [h: Handle ¬ NIL] = { <<--If h=NIL the process is terminated>> l: LIST OF Handle ¬ cq.front; IF l#NIL THEN {h ¬ l.first; cq.front ¬ l.rest; DisposeList[l]} ELSE cq.active ¬ FALSE; }; CallQueueProcess: PROC [cq: CallQueue] = { Process.SetPriority[cq.priority]; DO ENABLE ABORTED => LOOP; DO h: Handle ¬ Fetch[cq]; IF h=NIL THEN RETURN; cq.finalize[h, Finalize.HandleToObject[h]]; ENDLOOP; ENDLOOP; }; MainQueueProcess: PROC [] = { Process.SetPriority[Process.priorityForeground]; DO handle: Handle ¬ Finalize.FQNextNoAbort[fq]; IF handle#NIL THEN { WITH Finalize.GetClientData[handle] SELECT FROM cq: CallQueue => { IF Forward[cq, handle].mustFork THEN TRUSTED { Process.Detach[FORK CallQueueProcess[cq]]; }; }; ENDCASE => {}; handle ¬ NIL; }; ENDLOOP; }; TRUSTED { Process.Detach[FORK MainQueueProcess[]]; }; END.