ListerSysOpsImpl.mesa
Copyright Ó 1987, 1988, 1991 by Xerox Corporation. All rights reserved.
Russ Atkinson (RRA) December 13, 1988 1:39:28 am PST
JKF February 2, 1989 5:07:58 pm PST
Eduardo Pelegri-Llopart February 2, 1989 9:04:17 pm PST
Willie-s, September 26, 1991 2:16 pm PDT
DIRECTORY
BasicTime USING [GMT, nullGMT],
IO USING [Close, Error, GetLength, SetIndex, STREAM, UnsafeGetBlock],
ListerSysOps USING [Interceptor, MappedFile, MappedFileInner,
MappedFileInnerRecord, MappedFileRecord, OpenKind],
MobDefs USING [],
PFS USING [Delete, Error, GetInfo, OpenFile, OpenFileFromStream, PATH, PathFromRope, StreamOpen, UniqueID],
Rope USING [Concat, Equal, ROPE],
VM USING [AddressForPageNumber, BytesForPages, Free, Interval, nullInterval, PagesForBytes, SimpleAllocate];
ListerSysOpsImpl: CEDAR MONITOR
IMPORTS IO, PFS, Rope, VM
EXPORTS ListerSysOps
= BEGIN
GMT: TYPE = BasicTime.GMT;
nullGMT: GMT = BasicTime.nullGMT;
ROPE: TYPE = Rope.ROPE;
STREAM: TYPE = IO.STREAM;
currentInterceptor: ListerSysOps.Interceptor ¬ NIL;
openList: OpenStreamList ¬ NIL;
OpenStreamList: TYPE = LIST OF OpenStreamEntry;
OpenStreamEntry: TYPE = RECORD [stream: STREAM, kind: ListerSysOps.OpenKind];
Intercept: PUBLIC ENTRY PROC [interceptor: ListerSysOps.Interceptor] RETURNS [old: ListerSysOps.Interceptor] = {
old ¬ currentInterceptor;
currentInterceptor ¬ interceptor;
};
Open: PUBLIC PROC [name: ROPE, kind: ListerSysOps.OpenKind]
RETURNS [stream: STREAM ¬ NIL, err: ROPE ¬ NIL, time: GMT ¬ nullGMT] = {
interceptor: ListerSysOps.Interceptor ¬ currentInterceptor;
IF interceptor # NIL AND interceptor.open # NIL
THEN
[stream, err, time] ¬ interceptor.open[interceptor, name, kind]
ELSE {
PFS supplies the default operation
ENABLE PFS.Error => { err ¬ error.explanation; GO TO oops };
st: STREAM ¬ PFS.StreamOpen[
fileName: PFS.PathFromRope[name],
accessOptions: IF kind = read THEN $read ELSE $create];
time ¬ PFS.GetInfo[PFS.OpenFileFromStream[st]].uniqueID.egmt.gmt;
stream ¬ st;
};
IF err = NIL THEN AddToList[stream, kind];
EXITS oops => {};
};
Close: PUBLIC PROC [stream: STREAM, abortAndDelete: BOOL] RETURNS [err: ROPE] = {
interceptor: ListerSysOps.Interceptor ¬ currentInterceptor;
kind: ListerSysOps.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 {
PFS supplies the default operation
ENABLE {
PFS.Error => { err ¬ error.explanation; GO TO exit };
IO.Error => GO TO exit;
};
file: PFS.OpenFile ¬ PFS.OpenFileFromStream[stream];
uid: PFS.UniqueID;
namePath: PFS.PATH;
[fullFName: namePath, uniqueID: uid] ¬ PFS.GetInfo[file];
SELECT kind FROM
read, writeLog => IO.Close[stream];
ENDCASE => {
IO.Close[stream, abortAndDelete];
IF abortAndDelete THEN PFS.Delete[namePath, uid];
};
};
EXITS exit => {};
};
Delete: PUBLIC PROC [name: ROPE] RETURNS [err: ROPE] = {
interceptor: ListerSysOps.Interceptor ¬ currentInterceptor;
IF interceptor # NIL AND interceptor.delete # NIL
THEN err ¬ interceptor.delete[interceptor, name]
ELSE PFS.Delete[PFS.PathFromRope[name]
! PFS.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: ListerSysOps.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: ListerSysOps.OpenKind] = {
openList ¬ CONS[ [stream, kind], openList];
};
Mapped file support
mappedFiles: LIST OF MappedFileInner ¬ NIL;
MappedFile: TYPE = ListerSysOps.MappedFile;
MappedFileRecord: TYPE = ListerSysOps.MappedFileRecord;
MappedFileInner: TYPE = ListerSysOps.MappedFileInner;
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;
IF mfi.count > 0 THEN RETURN; -- new
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;
mfi: MappedFileInner;
IF bytes = 0 THEN
RETURN[mf: NIL, err: Rope.Concat["0 length stream for file: ", name]];
interval ¬ VM.SimpleAllocate[VM.PagesForBytes[bytes]];
mfi ¬ NEW[ListerSysOps.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]];
};
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.