Various fixes to OS vs Oberon file lifetime management in Files.Mod.

This commit is contained in:
David Brown 2016-11-29 15:27:30 +00:00
parent 51ae4c3241
commit 9f0cbccf55
4 changed files with 44 additions and 45 deletions

View file

@ -500,8 +500,6 @@ MODULE OPM; (* RC 6.3.89 / 28.6.89, J.Templ 10.7.89 / 22.7.96 *)
WHILE i > 0 DO LogW(" "); DEC(i) END; WHILE i > 0 DO LogW(" "); DEC(i) END;
LogVT100(VT100.Green); LogW("^"); LogVT100(VT100.ResetAll); LogVT100(VT100.Green); LogW("^"); LogVT100(VT100.ResetAll);
Files.Close(f);
END ShowLine; END ShowLine;
@ -597,7 +595,8 @@ MODULE OPM; (* RC 6.3.89 / 28.6.89, J.Templ 10.7.89 / 22.7.96 *)
oldSFile := Files.Old(fileName); done := oldSFile # NIL; oldSFile := Files.Old(fileName); done := oldSFile # NIL;
IF done THEN IF done THEN
Files.Set(oldSF, oldSFile, 0); Files.Read(oldSF, tag); Files.Read(oldSF, ver); Files.Set(oldSF, oldSFile, 0); Files.Read(oldSF, tag); Files.Read(oldSF, ver);
IF (tag # SFtag) OR (ver # SFver) THEN err(-306); (*possibly a symbol file from another Oberon implementation, e.g. HP-Oberon*) IF (tag # SFtag) OR (ver # SFver) THEN
err(-306); (*possibly a symbol file from another Oberon implementation, e.g. HP-Oberon*)
CloseOldSym; done := FALSE CloseOldSym; done := FALSE
END END
END END

View file

@ -18,14 +18,15 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
BufSize = 4096; BufSize = 4096;
NoDesc = -1; NoDesc = -1;
(* file states *) (* No file states, used when FileDesc.fd = NoDesc *)
open = 0; (* OS File has been opened *) open = 0; (* OS File has been opened *)
create = 1; (* OS file needs to be created *) create = 1; (* OS file needs to be created *)
close = 2; (* Register telling Create to use registerName directly: close = 2; (* Flag used by Files.Register to tell Create to create the
i.e. since we're closing and all data is still in file using it's registerName directly, rather than to
buffers bypass writing to temp file and then renaming create a temporary file: i.e. since we're closing and all
and just write directly to fianl register name *) data is still in buffers bypass writing to temp file and
then renaming and just write directly to final register
name *)
TYPE TYPE
FileName = ARRAY 101 OF CHAR; FileName = ARRAY 101 OF CHAR;
@ -37,7 +38,7 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
registerName: FileName; registerName: FileName;
tempFile: BOOLEAN; tempFile: BOOLEAN;
identity: Platform.FileIdentity; identity: Platform.FileIdentity;
fd-: Platform.FileHandle; fd: Platform.FileHandle;
len, pos: LONGINT; len, pos: LONGINT;
bufs: ARRAY NumBufs OF Buffer; bufs: ARRAY NumBufs OF Buffer;
swapper: INTEGER; swapper: INTEGER;
@ -63,7 +64,7 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
VAR VAR
files: File; (* List of files that have an OS file handle/descriptor assigned *) files: File; (* List of files backed by an OS file, whether open, registered or temporary. *)
tempno: INTEGER; tempno: INTEGER;
HOME: ARRAY 1024 OF CHAR; HOME: ARRAY 1024 OF CHAR;
SearchPath: POINTER TO ARRAY OF CHAR; SearchPath: POINTER TO ARRAY OF CHAR;
@ -122,6 +123,10 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
END GetTempName; END GetTempName;
PROCEDURE Create(f: File); PROCEDURE Create(f: File);
(* Makes sure there is an OS file backing this Oberon file.
Used when more data has been written to an unregistered new file than
buffers can hold, or when registering a new file whose data is all in
buffers. *)
VAR VAR
identity: Platform.FileIdentity; identity: Platform.FileIdentity;
done: BOOLEAN; done: BOOLEAN;
@ -137,16 +142,20 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
*) *)
IF f.fd = NoDesc THEN IF f.fd = NoDesc THEN
IF f.state = create THEN IF f.state = create THEN
(* New file with enough data written to exceed buffers, so we need to
create a temporary file to back it. *)
GetTempName(f.registerName, f.workName); f.tempFile := TRUE GetTempName(f.registerName, f.workName); f.tempFile := TRUE
ELSIF f.state = close THEN ELSE
ASSERT(f.state = close);
(* New file with all data in buffers being registered. No need for a
temp file, will just write the buffers to the registerName. *)
f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE
END; END;
error := Platform.Unlink(f.workName); (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*) error := Platform.Unlink(f.workName); (*unlink first to avoid stale NFS handles and to avoid reuse of inodes*)
error := Platform.New(f.workName, f.fd); error := Platform.New(f.workName, f.fd);
done := error = 0; done := error = 0;
IF done THEN IF done THEN
f.next := files; files := f; f.next := files; files := f; (* Link this file into the list of OS bakced files. *)
INC(Heap.FileCount); INC(Heap.FileCount);
Heap.RegisterFinalizer(f, Finalize); Heap.RegisterFinalizer(f, Finalize);
f.state := open; f.state := open;
@ -186,31 +195,12 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
IF error # 0 THEN Err("error writing file", f, error) END; IF error # 0 THEN Err("error writing file", f, error) END;
f.pos := buf.org + buf.size; f.pos := buf.org + buf.size;
buf.chg := FALSE; buf.chg := FALSE;
error := Platform.Identify(f.fd, f.identity); error := Platform.Identify(f.fd, f.identity); (* Update identity with new modification time. *)
IF error # 0 THEN Err("error identifying file", f, error) END; IF error # 0 THEN Err("error identifying file", f, error) END;
(*
error := Platform.Identify(f.fd, identity);
f.identity.mtime := identity.mtime;
*)
END END
END Flush; END Flush;
PROCEDURE CloseOSFile(f: File);
(* Close the OS file handle and remove f from 'files' *)
VAR prev: File; error: Platform.ErrorCode;
BEGIN
IF files = f THEN files := f.next
ELSE
prev := files;
WHILE (prev # NIL) & (prev.next # f) DO prev := prev.next END;
IF prev.next # NIL THEN prev.next := f.next END
END;
error := Platform.Close(f.fd);
f.fd := NoDesc; f.state := create; DEC(Heap.FileCount);
END CloseOSFile;
PROCEDURE Close* (f: File); PROCEDURE Close* (f: File);
VAR VAR
i: LONGINT; i: LONGINT;
@ -219,12 +209,6 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
IF (f.state # create) OR (f.registerName # "") THEN IF (f.state # create) OR (f.registerName # "") THEN
Create(f); i := 0; Create(f); i := 0;
WHILE (i < NumBufs) & (f.bufs[i] # NIL) DO Flush(f.bufs[i]); INC(i) END; WHILE (i < NumBufs) & (f.bufs[i] # NIL) DO Flush(f.bufs[i]); INC(i) END;
(* There's no reason to sync this file - we're about to close it. The OS
will sync if necessary. Further, sync will fail for a R/O file on Windows.
error := Platform.Sync(f.fd);
IF error # 0 THEN Err("error syncing file", f, error) END;
*)
CloseOSFile(f);
END END
END Close; END Close;
@ -323,7 +307,7 @@ MODULE Files; (* J. Templ 1.12. 89/12.4.95 Oberon files mapped onto Unix files
error := Platform.Identify(fd, identity); error := Platform.Identify(fd, identity);
f := CacheEntry(identity); f := CacheEntry(identity);
IF f # NIL THEN IF f # NIL THEN
(* error := Platform.Close(fd); DCWB: Either this should be removed or should call CloseOSFile. *) error := Platform.Close(fd); (* fd not needed - we'll be using f.fd. *)
RETURN f RETURN f
ELSE NEW(f); Heap.RegisterFinalizer(f, Finalize); ELSE NEW(f); Heap.RegisterFinalizer(f, Finalize);
f.fd := fd; f.state := open; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*) f.fd := fd; f.state := open; f.pos := 0; f.swapper := -1; (*all f.buf[i] = NIL*)
@ -579,7 +563,7 @@ Especially Length would become fairly complex.
END Rename; END Rename;
PROCEDURE Register* (f: File); PROCEDURE Register* (f: File);
VAR idx, errcode: INTEGER; f1: File; file: ARRAY 104 OF CHAR; VAR idx, errcode: INTEGER; f1: File;
BEGIN BEGIN
(* (*
Out.String("Files.Register f.registerName = "); Out.String(f.registerName); Out.String("Files.Register f.registerName = "); Out.String(f.registerName);
@ -595,7 +579,7 @@ Especially Length would become fairly complex.
Out.String(" to registerName "); Out.String(f.registerName); Out.String(" to registerName "); Out.String(f.registerName);
Out.String(" errorcode = "); Out.Int(errcode,1); Out.Ln; Out.String(" errorcode = "); Out.Int(errcode,1); Out.Ln;
*) *)
IF errcode # 0 THEN COPY(f.registerName, file); HALT(99) END; IF errcode # 0 THEN Err("Couldn't rename temp name as register name", f, errcode) END;
f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE f.workName := f.registerName; f.registerName := ""; f.tempFile := FALSE
END END
END Register; END Register;
@ -725,6 +709,20 @@ Especially Length would become fairly complex.
COPY (f.workName, name); COPY (f.workName, name);
END GetName; END GetName;
PROCEDURE CloseOSFile(f: File);
(* Close the OS file handle and remove f from 'files' *)
VAR prev: File; error: Platform.ErrorCode;
BEGIN
IF files = f THEN files := f.next
ELSE
prev := files;
WHILE (prev # NIL) & (prev.next # f) DO prev := prev.next END;
IF prev.next # NIL THEN prev.next := f.next END
END;
error := Platform.Close(f.fd);
f.fd := NoDesc; f.state := create; DEC(Heap.FileCount);
END CloseOSFile;
PROCEDURE Finalize(o: SYSTEM.PTR); PROCEDURE Finalize(o: SYSTEM.PTR);
VAR f: File; res: LONGINT; VAR f: File; res: LONGINT;
BEGIN BEGIN

View file

@ -530,7 +530,8 @@ MODULE Heap;
PROCEDURE GC*(markStack: BOOLEAN); PROCEDURE GC*(markStack: BOOLEAN);
VAR VAR
m: Module; m: Module;
i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11, i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23: S.ADDRESS; i0, i1, i2, i3, i4, i5, i6, i7, i8, i9, i10, i11,
i12, i13, i14, i15, i16, i17, i18, i19, i20, i21, i22, i23: S.ADDRESS;
cand: ARRAY 10000 OF S.ADDRESS; cand: ARRAY 10000 OF S.ADDRESS;
BEGIN BEGIN
IF (lockdepth = 0) OR (lockdepth = 1) & ~markStack THEN IF (lockdepth = 0) OR (lockdepth = 1) & ~markStack THEN

View file

@ -136,7 +136,7 @@ MODULE Modules; (* jt 6.1.96 *)
PROCEDURE Halt*(code: SYSTEM.INT32); PROCEDURE Halt*(code: SYSTEM.INT32);
BEGIN BEGIN
(*IF HaltHandler # NIL THEN HaltHandler(code) END;*) Heap.FINALL;
errstring("Terminated by Halt("); errint(code); errstring("). "); errstring("Terminated by Halt("); errint(code); errstring("). ");
IF code < 0 THEN DisplayHaltCode(code) END; IF code < 0 THEN DisplayHaltCode(code) END;
errstring(Platform.NL); errstring(Platform.NL);
@ -145,6 +145,7 @@ MODULE Modules; (* jt 6.1.96 *)
PROCEDURE AssertFail*(code: SYSTEM.INT32); PROCEDURE AssertFail*(code: SYSTEM.INT32);
BEGIN BEGIN
Heap.FINALL;
errstring("Assertion failure."); errstring("Assertion failure.");
IF code # 0 THEN errstring(" ASSERT code "); errint(code); errstring("."); END; IF code # 0 THEN errstring(" ASSERT code "); errint(code); errstring("."); END;
errstring(Platform.NL); errstring(Platform.NL);