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 { 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 { 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]; }; 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 }; 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. † 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 PFS supplies the default operation PFS supplies the default operation Mapped file support RETURN; Κ „•NewlineDelimiter –(cedarcode) style™code™Kšœ Οeœ=™HKšœΟkœž™4Kšžœ ™#KšΟy7™7K™(—K˜šž ˜ Kšœ žœžœ ˜Kšžœžœ%žœ˜EKšœ žœ_˜qKšœžœ˜Kšžœžœ8žœ&˜kKšœžœžœ˜!Kšžœžœd˜l—headšΟnœžœž˜Kšžœžœžœž˜Kšžœ ˜Kšœžœ˜K˜šžœžœ žœ˜Kšœ žœ˜!—Kšžœžœžœ˜Kšžœžœžœžœ˜K˜Kšœ/žœ˜3Kšœžœ˜K˜Kšœžœžœžœ˜/Kšœžœžœ žœ˜MK˜š   œžœžœžœ)žœ$˜pKšœ˜Kšœ!˜!K˜K™—š œžœžœžœžœ žœžœžœžœžœ˜„Kšœ;˜;šžœžœžœž˜/šž˜Kšœ?˜?—šžœ˜Kšžœ™"Kšžœžœ%žœžœ˜