-- file OSMiscOpsImpl.Mesa
-- last modified by Satterthwaite, December 10, 1982 10:53 am
DIRECTORY
DCSFileTypes: TYPE USING [tLeaderPage],
Directory: TYPE USING [
CreateFile, DeleteFile, Error, Lookup, RemoveFile, Rename, UpdateDates,
defaultContext, fileMaxPermissions, ignore],
File: TYPE USING [Capability, nullCapability, Permissions, read],
Inline: TYPE USING [LongNumber, BITXOR],
KernelFile: TYPE USING [MakeTemporary],
OSMiscOps: TYPE USING [Address, FileAccess, Permissions],
ProcessorFace: TYPE USING [processorID],
Runtime: TYPE USING [GetBcdTime, GetTableBase],
Space: TYPE USING [
Create, Delete, GetHandle, Handle, LongPointer,
Map, PageFromLongPointer, virtualMemory, wordsPerPage],
Time: TYPE USING [Current],
TimeStamp: TYPE USING [Stamp];
OSMiscOpsImpl: PROGRAM
IMPORTS Directory, Inline, KernelFile, ProcessorFace, Runtime, Space, Time
EXPORTS OSMiscOps
SHARES ProcessorFace = {
PageSize: CARDINAL = Space.wordsPerPage;
-- bulk free storage management
Pages: PUBLIC PROC [n: CARDINAL] RETURNS [base: OSMiscOps.Address] = {
IF n = 0 THEN base ← NIL
ELSE {
space: Space.Handle = Space.Create[size: n, parent: Space.virtualMemory];
space.Map[];
base ← space.LongPointer};
RETURN};
FreePages: PUBLIC PROC [base: OSMiscOps.Address] = {
IF base # NIL THEN
Space.Delete[Space.GetHandle[Space.PageFromLongPointer[base]]]};
-- binary table management
GetTableBase: PUBLIC PROC [p: PROGRAM] RETURNS [LONG POINTER] = {
RETURN [Runtime.GetTableBase[p]]};
-- version stamp management
GetNetAndHost: PROC RETURNS [net, host: CARDINAL] = {
sum: WORD = Inline.BITXOR[
ProcessorFace.processorID.a,
Inline.BITXOR[ProcessorFace.processorID.b, ProcessorFace.processorID.c]];
net ← sum/256; host ← sum MOD 256};
lastTime: LONG CARDINAL ← 0;
GenerateUniqueId: PUBLIC PROC RETURNS [TimeStamp.Stamp] = {
net, host: CARDINAL;
time: LONG CARDINAL;
[net, host] ← GetNetAndHost[];
DO
time ← Time.Current[];
IF lastTime = 0 OR time # lastTime THEN EXIT;
ENDLOOP;
lastTime ← time;
RETURN [[net: net, host: host, time: time]]};
BcdCreateTime: PUBLIC PROC RETURNS [time: LONG CARDINAL] = {
RETURN [Runtime.GetBcdTime[]]};
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: Inline.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: Inline.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: LONG STRING] = CODE;
FindFile: PUBLIC PROC [name: LONG STRING, access: OSMiscOps.FileAccess]
RETURNS [File.Capability] = {
file: File.Capability;
permissions: File.Permissions = OSMiscOps.Permissions[access];
old: BOOL ← (permissions = File.read);
IF ~old THEN {
file ← Directory.CreateFile[name, DCSFileTypes.tLeaderPage, 0
! Directory.Error => {
IF type = fileAlreadyExists THEN GOTO fileExists
ELSE GO TO fileProblem}];
EXITS
fileExists => old ← TRUE};
IF old THEN
file ← Directory.Lookup[fileName: name, permissions: Directory.ignore
! Directory.Error => {GO TO fileProblem}];
RETURN [Directory.UpdateDates[file, permissions]]
EXITS
fileProblem => ERROR FileError[name]};
RenameFile: PUBLIC PROC [newName, oldName: LONG STRING] = {
DeleteFile[newName]; -- in case one already exists
Directory.Rename[oldName, newName, Directory.defaultContext
! Directory.Error => {GOTO fileProblem}]
EXITS
fileProblem => ERROR FileError[oldName]};
UnnameFile: PUBLIC PROC [oldName: LONG STRING, file: File.Capability] = {
IF file = File.nullCapability THEN
file ← Directory.Lookup[fileName: oldName, permissions: Directory.fileMaxPermissions
! Directory.Error => {GOTO fileProblem}];
KernelFile.MakeTemporary[file];
Directory.RemoveFile[oldName, file
! Directory.Error => {GOTO fileProblem}];
EXITS
fileProblem => NULL};
DeleteFile: PUBLIC PROC [name: LONG STRING] = {
-- this is an enormously robust delete routine!
IF name # NIL THEN {
OPEN Directory;
failed: BOOL ← FALSE;
file: File.Capability;
file ← Directory.Lookup[name, defaultContext, fileMaxPermissions
! ANY => {failed ← TRUE; CONTINUE}];
IF ~failed THEN
Directory.DeleteFile[name
! ANY => {Directory.RemoveFile[name, file ! ANY => {CONTINUE}]}]}};
}.