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
DIRECTORY
BasicTime,
FS,
IO,
MimSysOps,
MimSysOpsPrivate,
Rope,
VM;
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];
};
END.