<> <> <> DIRECTORY RTFlags USING [takingStatistics], RTQuanta USING[PagesPerQuantum, QuantumCount, QuantumIndex], RTZones USING [MapPtrZf, mzVacant], SafeStoragePrivate USING [], UnsafeStorage USING [NewUZone], VM USING[AddressForPageNumber, Allocate, CantAllocate, PagesForWords, PageNumber, Pin, wordsPerPage]; RTOSImpl: MONITOR -- protects the PrivateHeapZone data structures IMPORTS RTZones, UnsafeStorage, VM EXPORTS SafeStoragePrivate = BEGIN OPEN RTQuanta; <<-- Statistics>> stats: RECORD[ nPHZVMPages: INT _ 0, nPermanentVMPages: INT _ 0, nCollectibleVMPages: INT _ 0 ]; Bump: PROC[p: POINTER TO INT, delta: INT _ 1] = INLINE {IF RTFlags.takingStatistics THEN p^ _ p^+delta}; <<>> <> UZHandle: TYPE = LONG POINTER TO UZObject; UZObject: TYPE = MACHINE DEPENDENT RECORD [ procs(0:0..31): LONG POINTER TO UZProcs ]; UZProcs: TYPE = MACHINE DEPENDENT RECORD [ new(0): PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER], free(1): PROC[self: UZHandle, object: LONG POINTER] ]; DummySequenceType: TYPE = RECORD[seq: SEQUENCE length: CARDINAL OF CARDINAL]; <> InsufficientVM: PUBLIC SIGNAL = CODE; <> allocStarted: BOOLEAN _ FALSE; phzObjectsLost: INT _ 0; phzPage: LONG POINTER _ NIL; phzPageWordsUsed: INT _ 0; PrivateHeapZone: PUBLIC UNCOUNTED ZONE _ LOOPHOLE[LONG[@phzObject]]; phzProcs: UZProcs _ [new: PHZNew, free: PHZFree]; phzObject: UZObject _ [procs: @phzProcs]; cedarHeapZone: UNCOUNTED ZONE _ NIL; Gimme: ENTRY PROC[size: CARDINAL] RETURNS[lp: LONG POINTER] = { ENABLE UNWIND => NULL; IF phzPage = NIL OR size > (VM.wordsPerPage - phzPageWordsUsed) THEN { Bump[@stats.nPHZVMPages]; phzPage _ VM.AddressForPageNumber[VM.Allocate[count: 1].page]; phzPageWordsUsed _ 0; }; lp _ phzPage + phzPageWordsUsed; phzPageWordsUsed _ phzPageWordsUsed + size; }; PHZNew: PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER] = { IF allocStarted THEN { size _ size - SIZE[DummySequenceType]; RETURN[cedarHeapZone.NEW[DummySequenceType[size]]]; } ELSE { pgs: INT; IF size < VM.wordsPerPage THEN RETURN[Gimme[size]]; pgs _ VM.PagesForWords[size]; Bump[@stats.nPHZVMPages, pgs]; RETURN[ VM.AddressForPageNumber[VM.Allocate[count: pgs].page] ]; }; }; PHZFree: PROC[self: UZHandle, object: LONG POINTER] = { IF RTZones.MapPtrZf[object] = RTZones.mzVacant THEN phzObjectsLost _ phzObjectsLost + 1 --pilotHeapZone.FREE[@object] ELSE cedarHeapZone.FREE[@object]}; PermanentPageZone: PUBLIC UNCOUNTED ZONE _ LOOPHOLE[LONG[@ppzObject]]; ppzProcs: UZProcs _ [new: PPZNew, free: NIL]; ppzObject: UZObject _ [procs: @ppzProcs]; PPZNew: PROC[self: UZHandle, size: CARDINAL] RETURNS[LONG POINTER] = { RETURN[GetPermanentDataPages[(size + VM.wordsPerPage - 1)/VM.wordsPerPage]]; }; <> NotifyAllocatorReady: PUBLIC PROC = { cedarHeapZone _ UnsafeStorage.NewUZone[initialSize: 100000B--words--]; allocStarted _ TRUE; }; IsAllocatorReady: PUBLIC PROC RETURNS[BOOLEAN] = {RETURN[allocStarted]}; <> GetPermanentDataPages: PUBLIC PROC [nPages: CARDINAL, createUniformSwapUnits: BOOLEAN _ TRUE] RETURNS[lp: LONG POINTER] = { nPages _ ((nPages+PagesPerQuantum-1)/PagesPerQuantum)*PagesPerQuantum; Bump[@stats.nPermanentVMPages, nPages]; lp _ VM.AddressForPageNumber [VM.Allocate[count: nPages, alignment: 2 ! VM.CantAllocate => GOTO noVM ].page]; EXITS noVM => ERROR InsufficientVM; }; GetCollectibleQuanta: PUBLIC PROC[desired, needed: QuantumCount] RETURNS[qi: QuantumIndex, qc: QuantumCount] = { qc _ desired; qi _ VM.Allocate [count: qc * PagesPerQuantum, alignment: 2 ! VM.CantAllocate => {IF bestInterval.count >= needed * PagesPerQuantum THEN {qc _ needed; RETRY} ELSE GOTO noVM} ].page/PagesPerQuantum; Bump[@stats.nCollectibleVMPages, qc * PagesPerQuantum]; EXITS noVM => ERROR InsufficientVM; }; GetDataPagesForGCTables: PUBLIC PROC RETURNS[LONG POINTER] = { page: VM.PageNumber = VM.Allocate[count: 256, alignment: 8].page; VM.Pin[[page, 1]]; RETURN[VM.AddressForPageNumber[page]]; }; END.