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