DIRECTORY IFSFile USING [AccessFailure, CantOpen, Error], IFSFilePrivate USING [FileHandle, FileObject, FSInstance], Rope USING [Equal, ROPE]; IFSFileImplE: MONITOR LOCKS fs.LOCK USING fs: IFSFilePrivate.FSInstance IMPORTS IFSFile, Rope EXPORTS IFSFilePrivate = { OPEN IFSFilePrivate; ROPE: TYPE = Rope.ROPE; FileListSmashed: ERROR = CODE; FileNotInList: ERROR = CODE; IllegalDestroy: ERROR = CODE; InvalidFile: ERROR = CODE; InsertFile: PUBLIC PROC [fs: FSInstance, name: ROPE, openProc: PROC [FileHandle] RETURNS [IFSFile.AccessFailure]] RETURNS [file: FileHandle] = { NewlyOpened: ENTRY PROC [fs: FSInstance] RETURNS [BOOL] = { file _ fs.fileList; UNTIL file = NIL DO IF Rope.Equal[file.name, name, FALSE] THEN { SELECT file.seal FROM openSeal => {file.openCount _ file.openCount + 1; RETURN[FALSE]}; underwaySeal => {WAIT fs.changeInOpenState; file _ fs.fileList}; ENDCASE => GO TO bogusList } ELSE -- ensure pointer validity SELECT file.seal FROM openSeal, underwaySeal => file _ file.link; ENDCASE => GO TO bogusList; REPEAT bogusList => ERROR FileListSmashed; ENDLOOP; file _ NEW[FileObject _ FileObject[link: fs.fileList, name: name, fs: fs]]; fs.fileList _ file; RETURN[TRUE] }; AnnounceOutcome: ENTRY PROC [fs: FSInstance, outcome: IFSFile.AccessFailure] = { IF outcome = ok THEN file.seal _ openSeal ELSE RemoveFile[fs, file]; BROADCAST fs.changeInOpenState; SELECT outcome FROM ok => RETURN; io => RETURN WITH ERROR IFSFile.Error[io]; ENDCASE => RETURN WITH ERROR IFSFile.CantOpen[outcome]; }; IF NewlyOpened[fs] THEN AnnounceOutcome[fs, openProc[file]]; }; ReleaseFile: PUBLIC PROC [file: FileHandle, closeProc: PROC [FileHandle]] = { IF LastReference[file.fs, file] THEN {closeProc[file]; FlushFile[file]}; }; PurgeFile: PUBLIC PROC [file: FileHandle, destroyProc: PROC [FileHandle]] = { IF LastReference[file.fs, file] THEN {destroyProc[file]; FlushFile[file]} ELSE ERROR IllegalDestroy; }; LastReference: ENTRY PROC [fs: FSInstance, file: FileHandle] RETURNS [last: BOOL] = { IF file.seal ~= openSeal OR file.openCount = 0 THEN ERROR InvalidFile; IF (last _ file.openCount = 1) THEN file.seal _ underwaySeal ELSE file.openCount _ file.openCount - 1; RETURN[last] }; FlushFile: PROC [file: FileHandle] = { DoRemoveFile: ENTRY PROC [fs: FSInstance] = {RemoveFile[fs, file]; BROADCAST fs.changeInOpenState}; DoRemoveFile[file.fs]; }; RemoveFile: INTERNAL PROC [fs: FSInstance, file: FileHandle] = { IF file = fs.fileList THEN fs.fileList _ file.link ELSE { IF fs.fileList = NIL THEN GO TO Trouble; FOR prev: FileHandle _ fs.fileList, prev.link UNTIL prev.link = NIL DO IF prev.link = file THEN {prev.link _ file.link; EXIT}; REPEAT FINISHED => GO TO Trouble; ENDLOOP; EXITS Trouble => ERROR FileNotInList; }; file.seal _ closedSeal; -- try to catch dangling references }; }. ÖIFSFileImplE.mesa Levin - 2-Jul-81 10:14:42 Russ Atkinson, November 10, 1983 0:00 am Miscellaneous -- Procedures and Signals Exported to IFSFilePrivate -- checks to see if the file identified by 'name' has already been entered in the file list. If not, it enters it and indicates that the open operation is underway. If so, it waits for any previous open attempt to be resolved, then reports the outcome. Internal Procedures -- removes the file from the list. Ê”˜šœ™Jšœ™J™(—J˜šÏk ˜ Jšœœ"˜/Jšœœ&˜:Jšœœ œ˜J˜—šœ˜Jšœœœ˜1Jšœ˜Jšœ˜Jšœ˜J˜Jšœœœ˜J˜Jšœ™J˜Jšœœœ˜Jšœœœ˜Jšœœœ˜Jšœ œœ˜J˜J˜Jšœ4™4J˜šÏn œœ˜Jšœœ œœ˜YJšœ˜J˜š ž œœœœœ˜;Jšœû™ûJ˜šœœ˜šœœ˜%šœ˜šœ ˜Jšœ2œœ˜AJšœœ+˜@Jšœœœ ˜—Jšœ˜—šœÏc˜šœ ˜J˜+Jšœœœ ˜———š˜Jšœ œ˜#—Jšœ˜—JšœœA˜KJ˜Jšœœ˜ Jšœ˜J˜—šžœœœ5˜PJšœœœ˜DJš œ˜šœ ˜Jšœœ˜ Jšœœœœ˜*Jšœœœœ˜7—Jšœ˜J˜—Jšœœ%˜