<<>> <> <> <> <> <<>> DIRECTORY FinalizeOps, VMChunks; VMChunksImpl: CEDAR MONITOR LOCKS domain USING domain: Domain IMPORTS FinalizeOps EXPORTS VMChunks = BEGIN OPEN VMChunks; DomainRep: PUBLIC TYPE = DomainRec; ChunkRep: PUBLIC TYPE = ChunkClientRec; Domain: TYPE = REF DomainRec; DomainRec: TYPE = MONITORED RECORD [ root: REF ChunkRealRec --contains the first address ! ]; Chunk: TYPE = REF ChunkClientRec; ChunkRealRec: TYPE = PRIVATE RECORD [ addr: CARD, size: CARD, prev, next: REF ChunkRealRec, occupied: BOOL ¬ FALSE ]; ChunkClientRec: TYPE = RECORD [ c: REF ChunkRealRec, dom: Domain ]; IsChunk: PUBLIC PROC [x: REF ANY] RETURNS [BOOL] = { RETURN [x#NIL AND ISTYPE[x, REF ChunkClientRec]] }; NarrowChunk: PUBLIC PROC [x: REF ANY] RETURNS [Chunk] = { RETURN [NARROW[x, REF ChunkClientRec]] }; AddressOfChunk: PUBLIC PROC [chunk: Chunk] RETURNS [CARD] = { RETURN [chunk.c.addr] }; SizeOfChunk: PUBLIC PROC [chunk: Chunk] RETURNS [CARD] = { RETURN [chunk.c.size] }; DomainOfChunk: PUBLIC PROC [chunk: Chunk] RETURNS [Domain] = { RETURN [chunk.dom] }; CreateDomain: PUBLIC PROC [startAddress: CARD, size: CARD] RETURNS [d: Domain] = { InitRoot: PROC [startAddress: CARD, size: CARD] RETURNS [c: REF ChunkRealRec] = { c ¬ NEW[ChunkRealRec]; c.size ¬ size; c.addr ¬ startAddress; c.next ¬ c.prev ¬ c; }; d ¬ NEW[DomainRec]; d.root ¬ InitRoot[startAddress, size]; }; alignRestrict: CARD = 8;--hardest alignment on sparc NewChunk: PROC [domain: Domain, c: REF ChunkRealRec] RETURNS [ch: Chunk] = { ch ¬ NEW[ChunkClientRec ¬ [dom: domain, c: c]]; c.occupied ¬ TRUE; [] ¬ FinalizeOps.EnableFinalization[ch, finalizationQueue] }; AllocateChunk: PUBLIC ENTRY PROC [domain: Domain, size: CARD] RETURNS [Chunk] = { root: REF ChunkRealRec ~ domain.root; c: REF ChunkRealRec ¬ root; size ¬ (size+alignRestrict-1)/alignRestrict*alignRestrict; IF size=0 THEN RETURN [NIL]; <<--try exact hole>> c ¬ root; DO IF ~c.occupied AND c.size=size THEN {RETURN[NewChunk[domain, c]]}; c ¬ c.next; IF c=root THEN EXIT; ENDLOOP; <<--try larger hole>> c ¬ root; DO IF ~c.occupied AND c.size>size THEN { SplitNCreateNext[c, size]; RETURN [NewChunk[domain, c]]; }; c ¬ c.next; IF c=root THEN EXIT; ENDLOOP; RETURN [NIL]; }; Free: ENTRY PROC [domain: Domain, c: REF ChunkRealRec] = { IF ~c.occupied THEN ERROR; c.occupied ¬ FALSE; IF ~c.next.occupied THEN JoinNRemoveNext[domain, c]; <<--order matters! JoinNRemoveNext of c.prev might clubber c>> IF ~c.prev.occupied THEN JoinNRemoveNext[domain, c.prev]; }; SplitNCreateNext: INTERNAL PROC [c: REF ChunkRealRec, nbytes: CARD] = { new: REF ChunkRealRec ~ NEW[ChunkRealRec]; IF c.occupied OR nbytes>=c.size THEN ERROR; --programming error new.size ¬ c.size - nbytes; c.size ¬ nbytes; new.addr ¬ c.addr + nbytes; new.next ¬ c.next; new.prev ¬ c; c.next.prev ¬ new; c.next ¬ new; }; JoinNRemoveNext: INTERNAL PROC [domain: Domain, c: REF ChunkRealRec] = { root: REF ChunkRealRec ~ domain.root; remove: REF ChunkRealRec ¬ c.next; IF remove=root THEN RETURN; --don't !!! memory is not circular IF c.occupied OR remove.occupied THEN ERROR; --programming error c.next ¬ remove.next; remove.next.prev ¬ c; c.size ¬ c.size+remove.size; }; finalizationQueue: FinalizeOps.CallQueue ~ FinalizeOps.CreateCallQueue[Finalizor]; Finalizor: FinalizeOps.FinalizeProc = { chunk: REF ChunkClientRec ~ NARROW[object]; Free[chunk.dom, chunk.c]; }; END.