RTOSImpl.Mesa
last edit by Paul Rovner, June 27, 1983 2:03 pm
Last Edited by: Levin, August 8, 1983 5:20 pm
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};
TYPEs
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];
Public signal
InsufficientVM: PUBLIC SIGNAL = CODE;
these variables are protected by the monitor
allocStarted: BOOLEANFALSE;
phzObjectsLost: INT ← 0;
phzPage: LONG POINTERNIL;
phzPageWordsUsed: INT ← 0;
PrivateHeapZone: PUBLIC UNCOUNTED ZONELOOPHOLE[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 ZONELOOPHOLE[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]];
};
Public procedures
NotifyAllocatorReady: PUBLIC PROC = {
cedarHeapZone ← UnsafeStorage.NewUZone[initialSize: 100000B--words--];
allocStarted ← TRUE;
};
IsAllocatorReady: PUBLIC PROC RETURNS[BOOLEAN] = {RETURN[allocStarted]};
PROCs for allocating blocks of data pages
GetPermanentDataPages: PUBLIC PROC
[nPages: CARDINAL,
createUniformSwapUnits: BOOLEANTRUE]
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.