DIRECTORY
Basics: TYPE USING [LongNumber],
BasicTime: TYPE USING [GMT, Now, nullGMT],
BcdDefs: TYPE USING [VersionStamp],
FS: TYPE USING [Create, Delete, Error, Lock, Open, OpenFile, Rename],
Loader: TYPE USING [BCDBuildTime],
OSMiscOps: TYPE USING [Address, FileAccess],
PrincOpsUtils: TYPE USING [BITXOR, CodeBase],
ProcessorFace: TYPE USING [processorID],
Rope: TYPE USING [ROPE],
VM: TYPE USING [AddressForPageNumber, Allocate, Free, Interval, PageNumber, PageNumberForAddress];
OSMiscOpsImpl:
PROGRAM
IMPORTS BasicTime, FS, Loader, PrincOpsUtils, ProcessorFace, VM
EXPORTS OSMiscOps
SHARES ProcessorFace = {
bulk free storage management
intervals: LIST OF VM.Interval;
Pages:
PUBLIC
PROC [n:
CARDINAL]
RETURNS [base: OSMiscOps.Address] = {
IF n = 0 THEN base ← NIL
ELSE {
interval: VM.Interval = VM.Allocate[count: n];
intervals ← CONS[interval, intervals];
base ← VM.AddressForPageNumber[interval.page]};
RETURN};
FreePages:
PUBLIC
PROC [base: OSMiscOps.Address] = {
page: VM.PageNumber;
last: LIST OF VM.Interval;
IF base = NIL THEN RETURN;
page ← VM.PageNumberForAddress[base];
FOR list:
LIST
OF
VM.Interval ← intervals, list.rest
WHILE list #
NIL
DO
IF list.first.page # page THEN {last ← list; LOOP};
VM.Free[list.first];
IF last = NIL THEN intervals ← intervals.rest ELSE last.rest ← list.rest;
EXIT; ENDLOOP};
binary table management
GetTableBase:
PUBLIC
PROC [p:
PROGRAM]
RETURNS [
LONG
POINTER] = {
RETURN [PrincOpsUtils.CodeBase[LOOPHOLE[p]]]};
version stamp management
GetNetAndHost:
PROC
RETURNS [net, host:
CARDINAL] = {
sum:
WORD = PrincOpsUtils.
BITXOR[
ProcessorFace.processorID.a,
PrincOpsUtils.BITXOR[ProcessorFace.processorID.b, ProcessorFace.processorID.c]];
net ← sum/256; host ← sum MOD 256};
lastTime: BasicTime.GMT ← BasicTime.nullGMT;
GenerateUniqueId:
PUBLIC
PROC
RETURNS [BcdDefs.VersionStamp] = {
net, host: CARDINAL;
time: BasicTime.GMT;
[net, host] ← GetNetAndHost[];
DO
time ← BasicTime.Now[];
IF lastTime = BasicTime.nullGMT OR time # lastTime THEN EXIT;
ENDLOOP;
lastTime ← time;
RETURN [[net: net, host: host, time: LOOPHOLE[time, LONG CARDINAL]]]};
BcdCreateTime:
PUBLIC
PROC
RETURNS [time: BasicTime.
GMT] = {
RETURN [Loader.BCDBuildTime[]]};
ImageId: PUBLIC PROC RETURNS [TimeStamp.Stamp] = {
RETURN [[0, 0, BcdCreateTime[]]]};
new version stamp operations
StampSize: NAT = 3;
Stamp: PUBLIC TYPE = RECORD [word: ARRAY [0..StampSize) OF CARDINAL];
AddStamps:
PROC [s1, s2: Stamp]
RETURNS [sum: Stamp] = {
carry: [0..1] ← 0;
i: NAT;
FOR i
DECREASING
IN [0..StampSize)
DO
t: Basics.LongNumber ← [lc[LONG[s1.word[i]] + LONG[s2.word[i]] + LONG[carry]]];
sum.word[i] ← t.lowbits; carry ← t.highbits;
ENDLOOP;
FOR i
DECREASING
IN [0..StampSize)
WHILE carry # 0
DO
t: Basics.LongNumber ← [lc[LONG[sum.word[i]] + LONG[carry]]];
sum.word[i] ← t.lowbits; carry ← t.highbits;
ENDLOOP};
RotateStamp: PROC [s: Stamp] RETURNS [Stamp] = INLINE {RETURN [AddStamps[s, s]]};
MergeStamps:
PUBLIC
PROC [sum, item: Stamp]
RETURNS [Stamp] = {
RETURN [AddStamps[RotateStamp[sum], item]]};
exception processing
SignalArgs:
PUBLIC
PROC
RETURNS [signal, message:
UNSPECIFIED] = {
RETURN [0, 0]};
file interface
FileError: PUBLIC ERROR [name: Rope.ROPE] = CODE;
FindFile:
PUBLIC
PROC [name: Rope.
ROPE, access: OSMiscOps.FileAccess]
RETURNS [FS.OpenFile] = {
file: FS.OpenFile;
old: BOOL ← access = $read;
lock: FS.Lock ← IF access = $read THEN read ELSE write;
IF ~old
THEN {
file ←
FS.Create[name !
FS.Error => {
IF error.code = alreadyExists THEN GOTO fileExists
ELSE GOTO fileProblem}];
EXITS
fileExists => old ← TRUE};
IF old
THEN
file ←
FS.Open[name: name, lock: lock
! FS.Error => {GO TO fileProblem}];
RETURN [file]
EXITS
fileProblem => ERROR FileError[name]};
RenameFile:
PUBLIC
PROC [newName, oldName: Rope.
ROPE] = {
DeleteFile[newName]; -- in case one already exists
FS.Rename[oldName, newName ! FS.Error => {GOTO fileProblem}]
EXITS fileProblem =>
ERROR FileError[oldName]};
UnnameFile:
PUBLIC
PROC [oldName: Rope.
ROPE, file:
FS.OpenFile] = {};
DeleteFile:
PUBLIC
PROC [name: Rope.
ROPE] = {
-- this is an enormously robust delete routine!
IF name #
NIL
THEN {
failed: BOOL ← FALSE;
file: FS.OpenFile;
file ← FS.Open[name, write ! ANY => {failed ← TRUE; CONTINUE}];
IF ~failed
THEN
FS.Delete[name !
ANY =>
CONTINUE]}};
}.