Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)?

like image 460
Shamdor Avatar asked Nov 13 '12 06:11

Shamdor


People also ask

What does interrupted system call mean?

Interruption of a system call by a signal handler occurs only in the case of various blocking system calls, and happens when the system call is interrupted by a signal handler that was explicitly established by the programmer.

Can a system call be interrupted?

System calls can be interrupted by any signal, this includes such signals as SIGINT (generated by CTRL-C), SIGHUP, etc.

Which Sigaction flag is used to prevent a system call from being interrupted?

You can set sa_mask in your sigaction call to block certain signals while a particular signal handler runs. This way, the signal handler can run without being interrupted itself by signals.

What are system call for restarting the system?

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.


2 Answers

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

like image 171
iabdalkader Avatar answered Oct 18 '22 20:10

iabdalkader


Assuming you're after shorter code, you can try something like:

while (((rc = close (fd)) == -1) && (errno == EINTR));
if (rc == -1)
    complainBitterly (errno);

Assuming you're after more readable code in addition to shorter, just create a function:

int closeWithRetry (int fd);

and place your readable code in there. Then it doesn't really matter how long it is, it's still a one-liner where you call it, but you can make the function body itself very readable:

int closeWithRetry (int fd) {
    // Initial close attempt.

    int rc = close (fd);

    // As long as you failed with EINTR, keep trying.
    // Possibly with a limit (count or time-based).

    while ((rc == -1) && (errno == EINTR))
        rc = close (fd);

    // Once either success or non-retry failure, return error code.

    return rc;
}
like image 21
paxdiablo Avatar answered Oct 18 '22 20:10

paxdiablo