NextSafeStorage.Mesa
last edited December 13, 1983 5:27 pm by Paul Rovner
SafeStorage: CEDAR DEFINITIONS
= BEGIN
ZONEs
TrimSystemZone: PROC;
returns free VM pages to the operating system
GetSystemZone: PROC RETURNS[ZONE];
this is the default ZONE used by NEW
GetPermanentZone: PROC RETURNS[ZONE];
use this for NEW objects that will never be collected
Controlling the garbage collector
SetCollectionInterval: PROC[newInterval: INT--words--] RETURNS[previous: INT];
establishes the number of words allocated between collections
ReclaimCollectibleObjects:
PROC[suspendMe: BOOLTRUE, traceAndSweep: BOOLFALSE];
perform a garbage collection
Monitoring the garbage collector
ReclamationReason: TYPE =
{clientRequest, clientTAndSRequest, clientNoTraceRequest, rcTableOverflow, allocationInterval, quantaNeeded, finalizationThreshold};
IsCollectorActive: PROC RETURNS[active: BOOL, previousIncarnation: INT];
WaitForCollectorStart: PROC
RETURNS[
incarnation: INT,
reason: ReclamationReason,
wordsAllocated: INT, --since previous collection was initiated
objectsAllocated: INT];
WaitForCollectorDone: PROC
RETURNS[
incarnation: INT,
reason: ReclamationReason,
wordsReclaimed: INT,
objectsReclaimed: INT];
Statistics
NWordsAllocated: PROC RETURNS[INT]; -- returns total # words allocated
NWordsReclaimed: PROC RETURNS[INT]; -- returns total # words reclaimed
TYPEs
NOTE: Cedar provides a wired-in operation to convert a TYPE expression to a SafeStorage.Type ... CODE[<TYPE expression>]
TypeIndex: TYPE = [0..LAST[CARDINAL]/4]; -- 14 bits
Type: TYPE = RECORD[TypeIndex];
predefined Types. All of these are treated specially by the implemention
nullType: Type = [0];
unspecType: Type = [1]; -- the distinguished type of UNSPECIFIED
fhType: Type = [2]; -- the distinguished type of localFrames
gfhType: Type = [3]; -- the distinguished type of globalFrames
anyType: Type = [4]; -- the distinguished type of ANY
lastPredefinedTypeIndex: TypeIndex = 4;
There will be other predefined Types.
GetCanonicalReferentType: PROC[ref: REF ANY] RETURNS[type: Type];
EquivalentTypes: PROC[t1, t2: Type] RETURNS[BOOL];
GetCanonicalType: PROC[type: Type] RETURNS[Type];
IsReferentType: PROC[ref: REF ANY, type: Type] RETURNS[BOOL];
NarrowRef: PROC[ref: REF ANY, type: Type] RETURNS[REF ANY];
Raises NarrowRefFault
Package finalization
BEWARE
1. Establish finalization for a type BEFORE applying EnableFinalization to objects of the type.
2. Invoke EnableFinalization AFTER establishing the package refs to the new object.
3. Do not nilify the package refs to an object while IsFinalizationEnabled[objRef].
There are three kinds of finalization applications: ones with no package data structure, ones with a package data structure that is accessed only during object creation or object finalization, and ones with a package data structure that is used as a cache from which copies of refs to existing objects are handed out to clients. Use of the stuff below for the first two applications is straightforward, but the synchronization required for caching applications is somewhat subtle. For caching applications, a monitor must be used to synchronize finalization actions with access to the cache. The following example illustrates what is believed to be a correct framework for caching applications ...
*** START OF EXAMPLE
--START CODE
myQueue: SafeStorage.FinalizationQueue = SafeStorage.NewFQ[];
SafeStorage.EstablishFinalization[type: CODE[Object], npr: <whatever>, fq: myQueue];
Process.Detach[FORK[Finalizer[]]];
--Find a cache entry for key
Lookup: ENTRY PROC[key: Key]
RETURNS [handle: Handle] = {ENABLE UNWIND => NULL;
FOR list: LIST OF Handle ← table[Hash[key]], list.rest UNTIL list = NIL
DO IF Equal[list.first.key, key] THEN --found it--{handle ← list.first; EXIT};
REPEAT
FINISHED =>
handle ← CreateAndInsert[key];
--Make a new one and enter it in the hash table
ENDLOOP;
--now enable the object for insertion on myQueue when the collector finds that no client references to it exist.
--This also marks the object as (re)issued.
SafeStorage.EnableFinalization[handle];
-- no-op if IsFinalizationEnabled[handle]
};
Finalizer: PROC = { -- the finalization process
DO InternalFinalizer[SafeStorage.FQNext[myQueue]] ENDLOOP;
};
InternalFinalizer: ENTRY PROC[handle: Handle] = {ENABLE UNWIND => NULL;
IF SafeStorage.IsFinalizationEnabled[handle] THEN RETURN; -- it was reissued
Remove[handle]; -- remove it from the hash table, i.e. nilify the package refs
};
*** END OF EXAMPLE
maxNPackageRefs: CARDINAL = 2;
FinalizationQueue: TYPE = PRIVATE RECORD[REF ANY];
EstablishFinalization:
PROC[type: Type, npr: [0..maxNPackageRefs], fq: FinalizationQueue];
CantEstablishFinalization is raised if finalization was previously established for type.
ReEstablishFinalization:
PROC[type: Type, npr: [0..maxNPackageRefs], fq: FinalizationQueue];
Use this to specify a new FinalizationQueue for a previously established finalizable type. This is useful during the edit-compile-test loop for running new versions of a program that establishes finalization for type.
ReEstablishFinalization will raise CantEstablishFinalization if type was not previously finalizable or if the new number of package refs is different than before.
EnableFinalization: PROC[ref: REF ANY];
Use this for a new finalizable object after establishing its package refs.
IsFinalizationEnabled: PROC[ref: REF ANY] RETURNS[BOOL];
Use this in conjunction with a finalizable cache.
NewFQ: PROC[length: CARDINAL ← 10--refs--] RETURNS[FinalizationQueue];
FQNext: PROC[fq: FinalizationQueue] RETURNS[REF ANY]; -- waits 'till there is one
FQEmpty: PROC[fq: FinalizationQueue] RETURNS[BOOL];
Type attachments
PutTypeAttachment: PROC[type: Type, attachment: REF ANY];
GetTypeAttachment: PROC[type: Type] RETURNS[REF ANY];
SIGNALs and ERRORs
MemoryExhausted: ERROR;
NarrowFault: ERROR;
NarrowRefFault: ERROR[ref: REF ANY, targetType: Type];
UnsafeProcAssignment: SIGNAL[proc: PROC ANY RETURNS ANY];
InvalidType: ERROR[type: Type];
CantEstablishFinalization: ERROR[type: Type];
END.