Under Linux, it is probably the case that the close call is guaranteed to close a valid fd, even if it subsequently reports an error such as EINTR.
So we should not try to close the fd again.
The current code is fine (for the non-concurrent use case), but perhaps a bit misleading:
let rec close fd = try Unix.close fd with
| Unix.Unix_error (Unix.EINTR, _, _) -> close fd
Linux man page for close has:
This permits the behavior that occurs on Linux and many other
implementations, where, as with other errors that may be reported by
close(), the file descriptor is guaranteed to be closed. However, it
also permits another possibility: that the implementation returns an
EINTR error and keeps the file descriptor open. (According to its
documentation, HP-UX's close() does this.) The caller must then once
more use close() to close the file descriptor, to avoid file
descriptor leaks. This divergence in implementation behaviors
provides a difficult hurdle for portable applications, since on many
implementations, close() must not be called again after an EINTR
error, and on at least one, close() must be called again. There are
plans to address this conundrum for the next major release of the
POSIX.1 standard.
Which seems to imply that close must be special-cased to the architecture (but why isn't this handled by libc?)
Under Linux, it is probably the case that the close call is guaranteed to close a valid fd, even if it subsequently reports an error such as EINTR.
So we should not try to close the fd again.
The current code is fine (for the non-concurrent use case), but perhaps a bit misleading:
Linux man page for close has:
Which seems to imply that close must be special-cased to the architecture (but why isn't this handled by libc?)