MimSysOpsImpl.mesa
Copyright Ó 1987, 1988, 1991 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) December 13, 1988 1:39:28 am PST
JKF February 9, 1989 5:19:20 pm PST
MimSysOpsImpl:
CEDAR MONITOR
IMPORTS FS, IO, Rope, VM
EXPORTS MimSysOps
= BEGIN OPEN MimSysOps, MimSysOpsPrivate;
GMT:
TYPE = BasicTime.
GMT;
nullGMT: GMT = BasicTime.nullGMT;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
currentInterceptor: Interceptor ¬ NIL;
openList: OpenStreamList ¬ NIL;
OpenStreamList: TYPE = LIST OF OpenStreamEntry;
OpenStreamEntry: TYPE = RECORD [stream: STREAM, kind: OpenKind];
Intercept:
PUBLIC
ENTRY
PROC [interceptor: Interceptor]
RETURNS [old: Interceptor] = {
old ¬ currentInterceptor;
currentInterceptor ¬ interceptor;
};
Open:
PUBLIC
PROC [name:
ROPE, kind: OpenKind]
RETURNS [stream:
STREAM ¬
NIL, err:
ROPE ¬
NIL, time:
GMT ¬ nullGMT] = {
interceptor: Interceptor ¬ currentInterceptor;
IF interceptor #
NIL
AND interceptor.open #
NIL
THEN
[stream, err, time] ¬ interceptor.open[interceptor, name, kind]
ELSE {
FS supplies the default operation
ENABLE FS.Error => {err ¬ error.explanation; GO TO oops};
st: STREAM ¬ FS.StreamOpen[
fileName: name,
accessOptions: IF kind = read THEN $read ELSE $create];
time ¬ FS.GetInfo[FS.OpenFileFromStream[st]].created;
stream ¬ st;
};
IF err = NIL THEN AddToList[stream, kind];
EXITS oops => {};
};
Close:
PUBLIC
PROC [stream:
STREAM, abortAndDelete:
BOOL]
RETURNS [err:
ROPE] = {
interceptor: Interceptor ¬ currentInterceptor;
kind: OpenKind;
[stream, kind] ¬ RemFromList[stream];
IF stream = NIL THEN RETURN;
IF interceptor #
NIL
AND interceptor.close #
NIL
THEN
err ¬ interceptor.close[interceptor, stream, abortAndDelete]
ELSE {
FS supplies the default operation
ENABLE {
FS.Error => {err ¬ error.explanation; GO TO exit};
IO.Error => GO TO exit;
};
file: FS.OpenFile ¬ FS.OpenFileFromStream[stream];
name: ROPE ¬ FS.GetName[file].fullFName;
time: BasicTime.GMT ¬ FS.GetInfo[file].created;
SELECT kind
FROM
read, writeLog => IO.Close[stream];
ENDCASE => {
IO.Close[stream, abortAndDelete];
IF abortAndDelete THEN FS.Delete[name, time];
};
};
EXITS exit => {};
};
Delete:
PUBLIC
PROC [name:
ROPE]
RETURNS [err:
ROPE] = {
interceptor: Interceptor ¬ currentInterceptor;
IF interceptor #
NIL
AND interceptor.delete #
NIL
THEN err ¬ interceptor.delete[interceptor, name]
ELSE FS.Delete[name ! FS.Error => {err ¬ error.explanation; CONTINUE}];
};
Cleanup:
PUBLIC
PROC [abortAndDelete:
BOOL] = {
DO
sample: LIST OF MappedFileInner ¬ mappedFiles;
IF sample = NIL THEN EXIT;
[] ¬ RemMappedFileInner[sample.first, FALSE];
ENDLOOP;
DO
sample: OpenStreamList ¬ openList;
IF sample = NIL THEN EXIT;
[] ¬ Close[sample.first.stream, abortAndDelete];
ENDLOOP;
};
RemFromList:
ENTRY
PROC [stream:
STREAM]
RETURNS [st:
STREAM ¬
NIL, kind: OpenKind ¬ read] = {
lag: OpenStreamList ¬ openList;
IF lag #
NIL
THEN {
IF lag.first.stream = stream
THEN {
st ¬ stream;
kind ¬ lag.first.kind;
openList ¬ lag.rest;
RETURN;
};
DO
next: OpenStreamList ¬ lag.rest;
IF next = NIL THEN EXIT;
IF next.first.stream = stream
THEN {
st ¬ stream;
kind ¬ next.first.kind;
lag.rest ¬ next.rest;
RETURN;
};
lag ¬ next;
ENDLOOP;
};
};
AddToList:
ENTRY
PROC [stream:
STREAM, kind: OpenKind] = {
openList ¬ CONS[ [stream, kind], openList];
};
Mapped file support
mappedFiles: LIST OF MappedFileInner ¬ NIL;
MappedFile: TYPE = REF MappedFileRecord;
MappedFileRecord: PUBLIC TYPE = MimSysOpsPrivate.MappedFileRecord;
FindMappedFile:
ENTRY
PROC [name:
ROPE]
RETURNS [mf: MappedFile] = {
ENABLE UNWIND => NULL;
FOR each:
LIST
OF MappedFileInner ¬ mappedFiles, each.rest
WHILE each #
NIL
DO
mfi: MappedFileInner ¬ each.first;
IF Rope.Equal[name, mfi.name]
THEN {
mfi.count ¬ mfi.count + 1;
RETURN [NEW[MappedFileRecord ¬ [mfi]]];
};
ENDLOOP;
RETURN [NIL];
};
AddMappedFileInner:
ENTRY
PROC [mfi: MappedFileInner] = {
mappedFiles ¬ CONS[mfi, mappedFiles];
};
DestroyHandle:
ENTRY
PROC [mf: MappedFile]
RETURNS [mfi: MappedFileInner] = {
IF mf #
NIL
THEN {
mfi ¬ mf.mfi;
mf.mfi ¬ NIL;
};
};
RemMappedFileInner:
ENTRY
PROC [mfi: MappedFileInner, decr:
BOOL]
RETURNS [st:
STREAM] = {
ENABLE UNWIND => NULL;
lag: LIST OF MappedFileInner ¬ mappedFiles;
IF decr
THEN {
IF mfi.count > 0 THEN mfi.count ¬ mfi.count - 1;
RETURN;
};
IF lag #
NIL
THEN {
interval: VM.Interval ¬ mfi.interval;
st ¬ mfi.stream;
mfi.stream ¬ NIL;
mfi.interval ¬ VM.nullInterval;
mfi.base ¬ NIL;
IF interval # VM.nullInterval THEN TRUSTED {VM.Free[interval]};
IF lag.first = mfi THEN {mappedFiles ¬ lag.rest; RETURN};
FOR each:
LIST
OF MappedFileInner ¬ lag.rest, each.rest
WHILE each #
NIL
DO
IF each.first = mfi THEN {lag.rest ¬ each.rest; RETURN};
lag ¬ each;
ENDLOOP;
};
};
Map:
PUBLIC
PROC [name:
ROPE]
RETURNS [mf: MappedFile, err:
ROPE] = {
mf ¬ FindMappedFile[name];
IF mf =
NIL
THEN {
stream: STREAM;
time: BasicTime.GMT;
[stream, err, time] ¬ Open[name, read];
IF stream #
NIL
THEN {
bytes: INT ¬ IO.GetLength[stream];
interval: VM.Interval ¬ VM.SimpleAllocate[VM.PagesForBytes[bytes]];
mfi: MappedFileInner ¬
NEW[MappedFileInnerRecord ¬ [
name: name,
interval: interval,
count: 1,
stream: stream,
base: VM.AddressForPageNumber[interval.page],
bytes: bytes]];
TRUSTED {
wp: LONG POINTER TO CARD ¬ LOOPHOLE[mfi.base];
wn: CARD ¬ VM.BytesForPages[interval.count] / BYTES[CARD];
WHILE wn # 0
DO
wp ¬ CARD.LAST;
wn ¬ wn - 1;
ENDLOOP;
IO.SetIndex[stream, 0];
[] ¬ IO.UnsafeGetBlock[
self: stream,
block: [base: mfi.base, startIndex: 0, count: bytes]];
};
[] ¬ Close[stream, TRUE]; -- new
mfi.stream ¬ NIL; -- new
AddMappedFileInner[mfi];
mf ¬ NEW[MappedFileRecord ¬ [mfi]];
};
};
};
UnMap:
PUBLIC
PROC [mf: MappedFile] = {
mfi: MappedFileInner ¬ DestroyHandle[mf];
IF mfi #
NIL
THEN {
st: STREAM ¬ RemMappedFileInner[mfi, TRUE];
IF st #
NIL
THEN {
[] ¬ Close[st, TRUE];
};
};
};
MapBase:
PUBLIC
PROC [mf: MappedFile]
RETURNS [
LONG
POINTER] = {
RETURN [mf.base];
};
MapLength:
PUBLIC
PROC [mf: MappedFile]
RETURNS [
CARD] = {
RETURN [mf.bytes];
};