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
-- 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: 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;
};
P
HZNew:
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]
];
};
};
P
HZFree:
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]];
};
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: 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.