OSMiscOpsImpl.mesa
Copyright Ó 1986, 1988, 1991 by Xerox Corporation. All rights reserved.
Satterthwaite, June 18, 1986 9:51:31 am PDT
Russ Atkinson (RRA) December 8, 1988 4:17:59 pm PST
DIRECTORY
BasicTime USING [GMT, Now, nullGMT],
File USING [wordsPerPage],
MimZones USING [],
MobDefs USING [NullVersion, VersionStamp],
OSMiscOps USING [Address],
ProcessorFace USING [ProcessorID, processorID],
SafeStorage USING [GetSystemZone],
UnsafeStorage USING [GetSystemUZone],
VM USING [AddressForPageNumber, Free, Interval, PagesForWords, PageNumber, PageNumberForAddress, SimpleAllocate];
OSMiscOpsImpl: PROGRAM
IMPORTS BasicTime, ProcessorFace, SafeStorage, UnsafeStorage, VM
EXPORTS MimZones, OSMiscOps = {
OPEN OSMiscOps;
exported to MimZones
permZone: PUBLIC ZONE ¬ SafeStorage.GetSystemZone[];
Objects allocated from this zone are never freed.
(we should use GetPermanentZone sometime)
tempZone: PUBLIC ZONE ¬ SafeStorage.GetSystemZone[];
Objects allocated from this zone are freed at the end of every compilation.
(provided that the temp zone is UNCOUNTED)
permUZ: PUBLIC UNCOUNTED ZONE ¬ UnsafeStorage.GetSystemUZone[];
Objects allocated from this zone are never freed.
tempUZ: PUBLIC UNCOUNTED ZONE ¬ UnsafeStorage.GetSystemUZone[];
Objects allocated from this zone are freed at the end of every compilation.
ResetTempZone: PUBLIC PROC = {};
This proc is called to free all of the objects in the temp zone.
(provided that the temp zone is UNCOUNTED)
RegisterForReset: PUBLIC PROC [resetProc: PROC] = {};
This proc is called to free all of the objects in the temp zone.
(provided that the temp zone is UNCOUNTED)
bulk free storage management
intervals: LIST OF VM.Interval ¬ NIL;
Pages: PUBLIC PROC [n: CARD] RETURNS [base: Address] = {
IF n = 0
THEN base ¬ NIL
ELSE {
interval: VM.Interval = VM.SimpleAllocate[n];
intervals ¬ CONS[interval, intervals];
base ¬ VM.AddressForPageNumber[interval.page];
};
};
FreePages: PUBLIC PROC [base: Address] = {
IF base # NIL THEN {
page: VM.PageNumber = VM.PageNumberForAddress[base];
last: LIST OF VM.Interval ¬ NIL;
FOR list: LIST OF VM.Interval ¬ intervals, list.rest UNTIL list = NIL DO
IF list.first.page = page THEN {
VM.Free[list.first];
IF last = NIL THEN intervals ¬ list.rest ELSE last.rest ¬ list.rest;
EXIT;
};
last ¬ list;
ENDLOOP;
};
};
Units: PUBLIC PROC [nUnits: CARD] RETURNS [base: Address] = {
RETURN [Pages[VM.PagesForWords[nUnits]]];
};
FreeUnits: PUBLIC PROC [base: Address] = {
FreePages[base];
};
bytesPerFilePage: PUBLIC NAT ¬ File.wordsPerPage*BYTES[WORD];
version stamp management
lastTime: BasicTime.GMT ¬ BasicTime.nullGMT;
GenerateUniqueId: PUBLIC PROC RETURNS [MobDefs.VersionStamp] = {
stamp: MobDefs.VersionStamp ¬ MobDefs.NullVersion;
id: ProcessorFace.ProcessorID ¬ ProcessorFace.processorID;
time: BasicTime.GMT;
{
words: NAT = MIN[MobDefs.VersionStamp.WORDS, ProcessorFace.ProcessorID.WORDS];
Ptr: TYPE = POINTER TO ARRAY [0..words) OF WORD;
LOOPHOLE[@stamp, Ptr]­ ¬ LOOPHOLE[@id, Ptr]­;
};
DO
time ¬ BasicTime.Now[];
IF lastTime = BasicTime.nullGMT OR time # lastTime THEN EXIT;
ENDLOOP;
lastTime ¬ time;
stamp[1] ¬ stamp[1] + LOOPHOLE[time, CARD];
RETURN [stamp];
};
Word Copy & Fill operations
WordPtr: TYPE = LONG POINTER TO WORD;
BlockPtr: TYPE = LONG POINTER TO Block;
Block: TYPE = ARRAY [0..8) OF WORD;
blockWords: NAT = Block.WORDS;
blockSize: NAT = Block.SIZE;
Copy: PUBLIC PROC [from: LONG POINTER, nwords: CARD, to: LONG POINTER] = {
Assumes non-overlapping blocks
IF nwords > CARD[INT.LAST] THEN ERROR;
WHILE nwords >= blockWords DO
nwords ¬ nwords - blockWords;
LOOPHOLE[to, BlockPtr]­ ¬ LOOPHOLE[from, BlockPtr]­;
to ¬ to + blockSize;
from ¬ from + blockSize;
ENDLOOP;
WHILE nwords # 0 DO
nwords ¬ nwords - 1;
LOOPHOLE[to, WordPtr]­ ¬ LOOPHOLE[from, WordPtr]­;
to ¬ to + WORD.SIZE;
from ¬ from + WORD.SIZE;
ENDLOOP;
};
Fill: PUBLIC PROC [where: LONG POINTER, nWords: CARD, value: WORD] = {
IF nWords > CARD[INT.LAST] THEN ERROR;
WHILE nWords >= blockWords DO
nWords ¬ nWords - blockWords;
LOOPHOLE[where, BlockPtr]­ ¬ ALL[value];
where ¬ where + blockSize;
ENDLOOP;
WHILE nWords # 0 DO
nWords ¬ nWords - 1;
LOOPHOLE[where, WordPtr]­ ¬ value;
where ¬ where + WORD.SIZE;
ENDLOOP;
};
new version stamp operations
stampElements: NAT = BITS[MobDefs.VersionStamp]/BITS[CARD32];
Stamp: PUBLIC TYPE = ARRAY [0..stampElements) OF CARD32;
TimeToStamp: PUBLIC PROC [time: MobDefs.VersionStamp] RETURNS [Stamp] = {
RETURN [time];
};
StampToTime: PUBLIC PROC [s: Stamp] RETURNS [MobDefs.VersionStamp] = {
RETURN [s];
};
AddStamps: PROC [s1, s2: Stamp] RETURNS [sum: Stamp] = {
carry: CARD32 ¬ 0;
FOR i: NAT DECREASING IN [0..stampElements) DO
w1: CARD32 ¬ s1[i];
w2: CARD32 ¬ s2[i];
w: CARD32 ¬ w1+w2+carry;
sum[i] ¬ w;
IF w < w1 OR w < carry THEN carry ¬ 1 ELSE carry ¬ 0;
ENDLOOP;
IF carry = 1 THEN
Ripple the carry through (1s complement addition)
FOR i: NAT DECREASING IN [0..stampElements) DO
w: CARD32 ¬ sum[i]+1;
sum[i] ¬ w;
IF w # 0 THEN EXIT;
ENDLOOP;
};
MergeStamps: PUBLIC PROC [sum, item: Stamp] RETURNS [Stamp] = {
RETURN [AddStamps[AddStamps[sum, sum], item]];
};
}.