Sourceware Bugzilla – Bug 14627
close() should set errno to EINPROGRESS when interrupted by a signal
Last modified: 2012-09-26 04:32:59 UTC
Background: Historically, there has been a disagreement over the behavior of close() when interrupted by a signal. Some implementations (e.g. HPUX) had it leave the file descriptor open when returning with EINTR; others (Linux, AIX) closed it unconditionally, but returned with EINTR if a signal arrived while close() was interrupted before returning. This ambiguity was acceptable for single-threaded applications, which could just unconditionally call close() again on EINTR, possibly getting EBADF if the file descriptor no longer existed due to the Linux/AIX behavior. It's not acceptable for multi-threaded applications, where calling close again could close a file descriptor just obtained by another thread - which can have far-reaching and extremely dangerous consequences.
The issue was referred to the Austin Group for interpretation (as defect #529, http://austingroupbugs.net/view.php?id=529), and was resolved by:
1) Requiring the HPUX behavior, leaving the file descriptor open, if close() returns with EINTR.
2) Allowing implementations that do not want to offer this behavior to return with EINPROGRESS instead of EINTR to indicate that close() did not finish waiting for the file/device to finish closing, but that the file descriptor has been deallocated.
3) Defining a new posix_close() function with a flag to control the behavior.
Reportedly, the Linux kernel developers are vehemently opposed to changing the behavior of close/EINTR to match HPUX, so I think it's safe to say the behavior of the kernel will not change. Some links to discussions and information on their opinions can be found here:
For what it's worth, I agree with them that having close() return without having deallocated the file descriptor is a highly undesirable behavior. However, it's also wrong (and now non-conformant, with the final accepted text from Austin Group defect #529 applied to POSIX) to return with EINTR, an error code which means the side effects of the function did not take place, when the side effects did in fact take place.
Fortunately, the revised text in POSIX gives an easy-out that should make everybody happy: the option to return with EINPROGRESS.
Since the kernel developers seem to be uninterested in changing the kernel to return EINPROGRESS (and even if they did, it would not fix the issue on older kernels), I propose that glibc catch the EINTR error from close() on Linux and remap it to EINPROGRESS. If Linux ever catches up and starts returning EINPROGRESS directly, nothing will break. The only possible breakage would be if, at some point in the future, Linux starts returning EINTR with the real EINTR semantics (HPUX semantics), but I'm pretty sure this is not going to happen given the developers' attitudes on the matter.