So I'm studying fclose manpage for quite I while and my conclusion is that if fclose is interrupted by some signal, according to the manpage there is no way to recover...? Am I missing some point?
Usually, with unbuffered POSIX functions (open, close, write, etc...) there is ALWAYS a way to recover from signal interruption (EINTR) by restarting the call; in contrast documentation of buffered calls states that after a failed fclose attempt another try has undefined behavior... no hint about HOW to recover instead. Am I just "unlucky" if a signal interrupts fclose? Data might be lost and I can't be sure whether the file descriptor is actually closed or not. I do know that the buffer is deallocated, but what about the file descriptor? Think about large scale applications that use lot's of fd's simultaneously and would run into problems if fd's are not properly freed -> I would assume there must be a CLEAN solution to this problem.
So let's assume I'm writing a library and it's not allowed to use sigaction and SA_RESTART and lots of signals are sent, how do I recover if fclose is interrupted? Would it be a good idea to call close in a loop (instead of fclose) after fclose failed with EINTR? Documentation of fclose simply doesn't mention the state of the file descriptor; UNDEFINED is not very helpful though... if fd is closed and I call close again, weird hard-to-debug side-effects could occur so naturally I would rather ignore this case as doing the wrong thing... then again, there is no unlimited number of file descriptors available, and resource leakage is some sort of bug (at least to me).
Of course I could check one specific implementation of fclose but I can't believe someone designed stdio and didn't think about this problem? Is it just the documentation that is bad or the design of this function?
This corner case really bugs me :(
fflush
first (and re-calling it if interrupted) before callingfclose
. – Damiandamianifclose(fileptr);
does up to three things: ensures all data is written to the file in files open for write/update, (possibly) unlocks the file before closing the file descriptor if it is locked (e.g. C11'sfopen(filename, "r+x");
for exclusive read/write access without truncating the file), and ensures that the file is closed. To that extent,fclose()
could fail duringfflush()
(basically a loop that callswrite()
until all buffered data is written or possiblyfsync()
); one offlock()
,lockf()
,fcntl()
, or an OS-specific lock (if a lock is used at all); orclose()
. – UppermostEINTR
appears forwrite()
,fsync()
, andclose()
, so it's impossible to determine which one failed. Perhaps you'd prefer avoidingfclose()
on POSIX systems to work around the issue? – Uppermostclose()
. Essentially, unless the return code is 0 (success) or the error isEBADF
(bad file descriptor — one which was not already open), there is no way to 'recover' from any other errors. The state of the underlying file descriptor is indeterminate. It might still be usable; it might simply be made available to another thread that happens to callopen()
at the wrong time — and you can't safely re-close the file descriptor because you don't know (in general). – Gomorrah