Returning EINTR from close()
The close() system call is capable of returning errors, but those error codes are often completely ignored. It's often considered a bad practice to do so, but lots of code has been written that way. Though, for Linux at least, there is a real question about what, if anything, can be done when close() returns an error—to the point where some say most close() error returns make no sense.
Ondřej Bílka posted to the libc-alpha mailing list (the development mailing list for the GNU C library or glibc) with a suggestion: turn any EINTR (system call interrupted) returns from close() on Linux into EINPROGRESS (operation in progress). It turns out that The Austin Group (which maintains POSIX) added language to clarify the behavior of close() in August 2012. Previously, the state of the file descriptor was undefined if an EINTR was returned, but the new interpretation says that an EINTR return requires that the descriptor still be open. EINPROGRESS should be returned if the system call is interrupted but the file descriptor is closed; thus Bílka's suggestion.
But others are not at all sure that close() should ever return an error (except for EBADF when passed an invalid file descriptor). As David Miller noted, close() returning errors is downright hazardous:
The widespread overwhelming belief is that close() is just going to always succeed, and there is more harm than good from signalling errors at all from that function.
In fact, it is difficult to even return EINTR from close() on Linux, according to Christoph Hellwig. If the driver or filesystem's release() method returns an error, it is explicitly ignored. The only path that would allow a driver to return EINTR is if it provides a flush() method that does so. Hellwig plans to post a patch that would enforce a no-EINTR policy on that path as well.
If EINTR can never be returned, there is no real reason to map it to EINPROGRESS in glibc. But, since glibc may be used on an older kernel that can return EINTR in some rare situations, mapping it to something probably makes sense. That could be EINPROGRESS or, perhaps better still, just zero for success, as suggested by Rich Felker. There really isn't much the application programmer can do if close() returns an error. As Russ Allbery put it in a reply to Felker:
As Allbery said, the POSIX EINTR semantics are not really possible on Linux. The file descriptor passed to close() is de-allocated early in the processing of the system call and the same descriptor could already have been handed out to another thread by the time close() returns. The Linux behavior could be changed if there were a sufficiently good reason to do so, but, so far, that reason has been elusive.
So the POSIX-suggested handling of an EINTR, which is to retry the close(), could actually be quite dangerous on Linux. For that reason, Mark Mentovai suggested a change to the glibc manual to avoid recommending retrying close() on Linux.
The topic came up on the linux-kernel mailing list back in 2005; Linus Torvalds was fairly adamant that an EINTR return should only be used to show that some other error has occurred (like the data was not flushed to the file), not that the descriptor was still open. In fact, Torvalds said that he didn't believe retrying close() is right for almost any Unix system, not just Linux. Any application that really needs to catch I/O errors when the data gets flushed, should do so using fsync(), he said.
Perhaps there are POSIX systems out there that have a close() that may not actually de-allocate the file descriptor when it gets interrupted, but it's a little hard to see what the advantage of that would be. In many cases, the return code from close() is completely ignored (for good or ill), so leaving it open would just lead to a file descriptor leak. Even if the error is caught, the application can't really do anything to repair the situation, it can only retry the close(), which seems a little pointless. But, evidently, it wasn't pointless to The Austin Group.
Posted Dec 12, 2013 10:21 UTC (Thu)
by sorokin (guest, #88478)
[Link] (3 responses)
1. flush pending writes
First operation may fail and should be handled the same way errors in write() are handled.
This separation is handy when I'm writing file and write() returns error. I should free file descriptor, but I don't want to flush pending data (and handle corresponding errors).
WRT to EINTR: first operation may return EINTR (if necessary), second operator should never return EINTR.
Posted Dec 14, 2013 19:26 UTC (Sat)
by giraffedata (guest, #1954)
[Link]
I agree, and I bristle every time I see someone make close() do anything other than declare that a session of file operations has ended. (It's not normal, by the way - a typical close() does leave pending writes pending). Declaring is something that cannot logically fail.
I think the philosophy of the passive destructor was not well known when Unix close() was defined, so I won't call the fact that close() has a return code a design mistake, but we should all understand that our direction should be consistently away from that.
There shouldn't even be a failure for bad file descriptor. It works better if that causes a signal.
There's an even more important philosophy of failures at issue here: when a call fails, it should fail completely; have no effect. EINTR failures in particular always respect that. If there is a close() anywhere that fails with EINTR after releasing the file descriptor, that's just a bug.
Posted Dec 19, 2013 22:08 UTC (Thu)
by silly_sad (guest, #94576)
[Link] (1 responses)
this is even bigger trouble than flushing writes in the close()
they suggested retry...
ERROR message must tell the application what it did wrong.
So, those who vote for "always return success" are totally right, there is absolutely nothing an application can do in case of a close()'s error.
Posted Dec 25, 2013 23:19 UTC (Wed)
by nix (subscriber, #2304)
[Link]
Posted Dec 12, 2013 10:33 UTC (Thu)
by roc (subscriber, #30627)
[Link] (2 responses)
Posted Dec 13, 2013 6:13 UTC (Fri)
by geofft (subscriber, #59789)
[Link]
Without it, it's possible for you to download mail from the mail server, fail to write it to your home directory because you're out of quota, have the error from close() be ignored, and just lose those messages.
Posted Dec 14, 2013 19:19 UTC (Sat)
by nix (subscriber, #2304)
[Link]
Posted Dec 12, 2013 13:47 UTC (Thu)
by jschrod (subscriber, #1646)
[Link]
Posted Dec 13, 2013 0:25 UTC (Fri)
by tstover (guest, #56283)
[Link]
1) http://en.wikipedia.org/?title=A/UX
Posted Dec 13, 2013 12:42 UTC (Fri)
by rwmj (subscriber, #5474)
[Link] (1 responses)
Posted Dec 16, 2013 6:37 UTC (Mon)
by jrn (subscriber, #64214)
[Link]
As I understand it, Linux should never return EINTR from close(). No one seems to disagree with this, and it sounds like soon glibc will guard against it (yay!). So I don't see how POSIX advocating one or another behavior on EINTR from close() could be harmful on Linux, given that it would never happen.
Returning EINTR from close()
2. return used file descriptor
The second operation may fail only due to error in program.
Returning EINTR from close()
Returning EINTR from close()
why in the first place they think that the close() or flush() failure is of application's concern?!
shall i wrap each syscall in a cycle?!
just do it yourself, and don't bother the application -- this is a philosophy of ROUTINE itself.
suggestion of "retry" implies that application did NOTHING WRONG.
Returning EINTR from close()
they suggested retry...
shall i wrap each syscall in a cycle?!
For syscalls that may return -EINTR like read() and write() this has always been true. That on local storage you can often get away without it doesn't make it any less necessary (e.g. on NFS both EINTRed and short reads and writes can and do happen).
Returning EINTR from close()
Returning EINTR from close()
http://debathena.mit.edu/trac/browser/trunk/debathena/thi...
Returning EINTR from close()
Returning EINTR from close()
Returning EINTR from close()
2) just kidding :)
Returning EINTR from close()
Returning EINTR from close()