so i'm studying fclose manpage quite while , conclusion if fclose interrupted signal, according manpage there no way recover...? missing point?
usually, unbuffered posix functions (open, close, write, etc...) there way recover signal interruption (eintr) restarting call; in contrast documentation of buffered calls states after failed fclose attempt try has undefined behavior... no hint how recover instead. "unlucky" if signal interrupts fclose? data might lost , can't sure whether file descriptor closed or not. know buffer deallocated, file descriptor? think large scale applications use lot's of fd's simultaneously , run problems if fd's not freed -> assume there must clean solution problem.
so let's assume i'm writing library , it's not allowed use sigaction , sa_restart , lots of signals sent, how recover if fclose interrupted? idea call close in loop (instead of fclose) after fclose failed eintr? documentation of fclose doesn't mention state of file descriptor; undefined not helpful though... if fd closed , call close again, weird hard-to-debug side-effects occur naturally rather ignore case doing wrong thing... again, there no unlimited number of file descriptors available, , resource leakage sort of bug (at least me).
of course could check one specific implementation of fclose can't believe designed stdio , didn't think problem? documentation bad or design of function?
this corner case bugs me :(
eintr , close()
in fact, there problems close(), not fclose().
posix states close() returns eintr, means application may retry call. things more complicated in linux. see this article on lwn , this post.
[...]posixeintrsemantics not possible on linux. file descriptor passedclose()de-allocated in processing of system call , same descriptor have been handed out thread timeclose()returns.
this blog post , this answer explain why it's not idea retry close() failed eintr. in linux, can nothing meaningful if close() failed eintr (or einprogress).
also note close() asynchronous in linux. e.g., umount may return ebusy after closing last opened descriptor on filesystem since it's not yet released in kernel. see interesting discussion here: page 1, page 2.
eintr , fclose()
posix states fclose():
after call
fclose(), use of stream results in undefined behavior.whether or not call succeeds, stream shall disassociated file , buffer set
setbuf()orsetvbuf()function shall disassociated stream. if associated buffer automatically allocated, shall deallocated.
i believe means if close() failed, fclose() should free resources , produce no leaks. it's true @ least glibc , uclibc implementations.
reliable error handling
call
fflush()beforefclose().since can't determine if
fclose()failed when calledfflush()orclose(), have explicitly callfflush()beforefclose()ensure userspace buffer sent kernel.don't retry after
eintr.if
fclose()failedeintr, can not retryclose(), can not retryfclose().call
fsync()if need.- if care data integrity, should call
fsync()orfdatasync()before callingfclose()1. - if don't, ignore
eintrfclose().
- if care data integrity, should call
notes
if
fflush(),fsync()succeeded ,fclose()failedeintr, no data lost , no leaks occur.you should ensure
fileobject not used betweenfflush(),fclose()calls thread 2.
[1] see "everything wanted know fsync()" article explains why fsync() may asynchronous operation.
[2] can call flockfile() before calling fflush() , fclose(). should work fclose() correctly.
Comments
Post a Comment