Search code examples
cmacossignalsalarmsystem-calls

read() system call doesn't fail when an alarm signal is received


This is (part of) my server-side code

void timeout_handler(int value) {
    printf("Handler\n");
    return;
}

int main (int argc, char **argv) {
    [...]
    signal(SIGALRM, timeout_handler);
    alarm(seconds);
    int result = read(input_socket, buffer, sizeof(buffer));
    if (result == -1 && errno == EINTR) {
        printf("read() failed\n");
    }
    [...]
}

where input_socket is a TCP socket correctly connected with a client (if I send data from the client, the server receives them).

As a test of the alarm signal, I tried just to open and connect the socket client-side without send any data. I would expect an output like

Handler
read() failed

but the result is only the Handler message, and then the process is still active.

Why the read() doesn't fail with errno=EINTR?


Solution

  • Also on OSX certain system calls are restarted by default when having been interupted by a signal.

    siginterrupt() can be used to change this behaviour. The following line (somewhere before alarm() is called) should do the job to let the program behave as expected by the OP:

    siginterrupt(SIGALRM, 1);
    

    From the OSX documentation (emphasis by me):

    For some system calls, if a signal is caught while the call is executing and the call is prematurely terminated, the call is automatically restarted. Any handler installed with signal(3) will have the SA_RESTART flag set, meaning that any restartable system call will not return on receipt of a signal. The affected system calls include read(2), write(2), sendto(2), recvfrom(2), sendmsg(2), and recvmsg(2) on a communications channel or a low speed device and during a ioctl(2) or wait(2). However, calls that have already committed are not restarted, but instead return a partial success (for example, a short read count). These semantics could be changed with siginterrupt(3).

    This is different on Linux for example, where restarting of system call possibly interupted needs to explicitly be requested by the signal sent.