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];
};