-- File: IFSFileList.mesa -- Last edited by Levin: 4-Feb-81 16:59:56 DIRECTORY IFSFilePrivate USING [ closedSeal, CopyString, FileHandle, FileObject, FSInstance, openSeal, underwaySeal], StringDefs USING [EquivalentString], VMDefs USING [AccessFailure, CantOpen, Error], VMStorage USING [shortTerm]; IFSFileList: MONITOR LOCKS fs.LOCK USING fs: IFSFilePrivate.FSInstance IMPORTS IFSFilePrivate, StringDefs, VMDefs, VMStorage EXPORTS IFSFilePrivate = BEGIN OPEN IFSFilePrivate; -- Miscellaneous -- FileListSmashed: ERROR = CODE; FileNotInList: ERROR = CODE; IllegalDestroy: ERROR = CODE; InvalidFile: ERROR = CODE; -- Procedures and Signals Exported to IFSFilePrivate -- InsertFile: PUBLIC PROCEDURE [fs: FSInstance, name: STRING, openProc: PROCEDURE [FileHandle] RETURNS [VMDefs.AccessFailure]] RETURNS [file: FileHandle] = BEGIN NewlyOpened: ENTRY PROCEDURE [fs: FSInstance] RETURNS [BOOLEAN] = INLINE -- 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. BEGIN file ← fs.fileList; UNTIL file = NIL DO IF StringDefs.EquivalentString[file.name, name] THEN BEGIN SELECT file.seal FROM openSeal => {file.openCount ← file.openCount + 1; RETURN[FALSE]}; underwaySeal => {WAIT fs.changeInOpenState; file ← fs.fileList}; ENDCASE => GO TO bogusList END ELSE -- ensure pointer validity SELECT file.seal FROM openSeal, underwaySeal => file ← file.link; ENDCASE => GO TO bogusList; REPEAT bogusList => ERROR FileListSmashed; ENDLOOP; file ← VMStorage.shortTerm.NEW[FileObject ← FileObject[ link: fs.fileList, name: CopyString[name], fs: fs]]; fs.fileList ← file; RETURN[TRUE] END; AnnounceOutcome: ENTRY PROCEDURE [ fs: FSInstance, outcome: VMDefs.AccessFailure] = -- INLINE -- BEGIN IF outcome = ok THEN file.seal ← openSeal ELSE RemoveFile[fs, file]; BROADCAST fs.changeInOpenState; SELECT outcome FROM ok => RETURN; io => RETURN WITH ERROR VMDefs.Error[io]; ENDCASE => RETURN WITH ERROR VMDefs.CantOpen[outcome]; END; IF NewlyOpened[fs] THEN AnnounceOutcome[fs, openProc[file]]; END; ReleaseFile: PUBLIC PROCEDURE [ file: FileHandle, closeProc: PROCEDURE [FileHandle]] = BEGIN IF LastReference[file.fs, file] THEN {closeProc[file]; FlushFile[file]}; END; PurgeFile: PUBLIC PROCEDURE [ file: FileHandle, destroyProc: PROCEDURE [FileHandle]] = BEGIN IF LastReference[file.fs, file] THEN {destroyProc[file]; FlushFile[file]} ELSE ERROR IllegalDestroy; END; -- Internal Procedures -- LastReference: ENTRY PROCEDURE [fs: FSInstance, file: FileHandle] RETURNS [last: BOOLEAN] = BEGIN 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] END; FlushFile: PROCEDURE [file: FileHandle] = BEGIN DoRemoveFile: ENTRY PROCEDURE [fs: FSInstance] = INLINE {RemoveFile[fs, file]; BROADCAST fs.changeInOpenState}; DoRemoveFile[file.fs]; VMStorage.shortTerm.FREE[@file]; END; RemoveFile: INTERNAL PROCEDURE [fs: FSInstance, file: FileHandle] = -- removes the file from the list. BEGIN IF file = fs.fileList THEN fs.fileList ← file.link ELSE BEGIN 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; END; file.seal ← closedSeal; -- try to catch dangling references END; END.