Search code examples
c++cunixinterrupteintr

System call interrupted by a signal still has to be completed


A lot of system calls like close( fd ) Can be interrupted by a signal. In this case usually -1 is returned and errno is set EINTR.

The question is what is the right thing to do? Say, I still want this fd to be closed.

What I can come up with is:

while( close( fd ) == -1 )
  if( errno != EINTR ) {
    ReportError();
    break;
  }

Can anybody suggest a better/more elegant/standard way to handle this situation?

UPDATE: As noticed by mux, SA_RESTART flag can be used when installing the signal handler. Can somebody tell me which functions are guaranteed to be restartable on all POSIX systems(not only Linux)?


Solution

  • Some system calls are restartable, which means the kernel will restart the call if interrupted, if the SA_RESTART flag is used when installing the signal handler, the signal(7) man page says:

    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:

    It doesn't mention if close() is restartable, but these are:

    read(2), readv(2), write(2), writev(2), ioctl(2), open(2),wait(2), wait3(2), wait4(2), waitid(2), and waitpid,accept(2), connect(2), recv(2), recvfrom(2), recvmsg(2), send(2), sendto(2), and sendmsg(2) flock(2) and fcntl(2) mq_receive(3), mq_timedreceive(3), mq_send(3), and mq_timedsend(3) sem_wait(3) and sem_timedwait(3) futex(2)

    Note that those details, specifically the list of non-restartable calls, are Linux-specific

    I posted a relevant question about which system calls are restartable and if it's specified by POSIX somewhere, it is specified by POSIX but it's optional, so you should check the list of non-restartable calls for your OS, if it's not there it should be restartable. This is my question: How to know if a Linux system call is restartable or not?

    Update: Close is a special case it's not restartable and should not be retried in Linux, see this answer for more details: https://stackoverflow.com/a/14431867/1157444