Some system calls can be restarted transparently by the Kernel if the SA_RESTART
flag is used when installing the signal handler, according to man signal(7):
If a blocked call to one of the following interfaces is interrupted by a signal handler, then the call will be automatically restarted after the signal handler returns if the SA_RESTART flag was used; otherwise the call will fail with the error EINTR:
Then it mentions some system calls that can (and can not) be restarted, but does not mention close()
in either places, how would I know if close()
, or any other function, is restartable or not ? does POSIX
specify it or is it a Linux-specific behaviour ? where can I find more info ?
System calls are usually made when a process in user mode requires access to a resource. Then it requests the kernel to provide the resource via a system call. As can be seen from this diagram, the processes execute normally in the user mode until a system call interrupts this.
The return value is the return value from the system call, unless the system call failed. In that case, syscall returns -1 and sets errno to an error code that the system call returned. Note that system calls do not return -1 when they succeed. If you specify an invalid sysno , syscall returns -1 with errno = ENOSYS .
The restart_syscall() system call is used to restart certain system calls after a process that was stopped by a signal (e.g., SIGSTOP or SIGTSTP) is later resumed after receiving a SIGCONT signal. This system call is designed only for internal use by the kernel.
A system call number is a unique integer (i.e., whole number), from one to around 256, that is assigned to each system call in a Unix-like operating system.
close
is a rather special case. Not only is it not restartable on Linux; when close
returns with EINTR
on Linux, it has actually already succeeded, and making another call to close
will fail with EBADF
in single-threaded processes and cause extremely dangerous file-descriptor races in multi-threaded processes.
As of the published POSIX 2008, this behavior is permitted:
If close() is interrupted by a signal that is to be caught, it shall return -1 with errno set to [EINTR] and the state of fildes is unspecified.
This issue was raised with the Austin Group (as Issue #529) and it was resolved to revise the specification such that returning with EINTR
means the file descriptor is still open; this is contrary to the current Linux behavior. If the file descriptor has already been closed at the time the signal is handled, the close
function is now required to return with EINPROGRESS
instead of EINTR
. This can be fixed in userspace on Linux, and there is an open glibc bug report, #14627 for it, but as of this writing it has not received any response.
This issue also has serious implications for POSIX thread cancellation, the side effects of which are specified in terms of the side effects upon returning with EINTR
. There is a related issue on the Austin Group tracker, Issue #614.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With