IFSFileImplE.mesa
Levin - 2-Jul-81 10:14:42
Russ Atkinson, November 10, 1983 0:00 am
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;
Miscellaneous --
FileListSmashed: ERROR = CODE;
FileNotInList: ERROR = CODE;
IllegalDestroy: ERROR = CODE;
InvalidFile: ERROR = CODE;
Procedures and Signals Exported to IFSFilePrivate --
InsertFile: PUBLIC PROC
[fs: FSInstance, name: ROPE, openProc: PROC [FileHandle] RETURNS [IFSFile.AccessFailure]]
RETURNS [file: FileHandle] = {
NewlyOpened: ENTRY PROC [fs: FSInstance] RETURNS [BOOL] = {
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.
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;
};
Internal Procedures --
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] = {
removes the file from the list.
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
};
}.