17

My program goes through a loop like this:

...
while(1){
  read(sockfd,buf,sizeof(buf));
  ...
}

The read function blocks when it is waiting for input, which happens to be from a socket. I want to handle SIGINT and basically tell it to stop the read function if it is reading and then call an arbitrary function. What is the best way to do this?

kaykun
  • 2,247
  • 2
  • 24
  • 37

2 Answers2

18

From read(2):

   EINTR  The call was interrupted by a signal before any data
          was read; see signal(7).

If you amend your code to look more like:

cont = 1;
while (1 && cont) {
    ret = read(sockfd, buf, sizeof(buf));
    if (ret < 0 && errno == EINTR)
        cont = arbitrary_function();
}

This lets arbitrary_function() decide if the read(2) should be re-tried or not.

Update

You need to handle the signal in order to get the EINTR behavior from read(2):

#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<signal.h>
#include<errno.h>

int interrupted;

void handle_int(int num) {
  interrupted = 1;
}

int main(void){
  char buf[9001];
  struct sigaction int_handler = {.sa_handler=handle_int};
  sigaction(SIGINT,&int_handler,0);
  while(!interrupted){
    printf("interrupted: %d\n", interrupted);
    if(read(0,buf,sizeof(buf))<0){
      if(errno==EINTR){
        puts("eintr");
      }else{
        printf("%d\n",errno);
      }
      puts(".");
    }
  }
  puts("end");
  return 0;
}

Gives output:

$ ./foo
interrupted: 0
hello
interrupted: 0
^Ceintr
.
end
sarnold
  • 102,305
  • 22
  • 181
  • 238
  • With what you've provided, sending SIGINT (through Ctrl+C) just ends the program. – kaykun Jun 06 '11 at 09:06
  • @kaykun, only if that's the last line in the program. You could add more lines after the `while` block that re-start the transmission, you could drop that specific client and continue on with the mainloop of your program, you could start an interactive shell with the user to ask what actions to take next... nothing says this has to terminate the program. – sarnold Jun 06 '11 at 09:13
  • @sarnold Incorrect, at least for me the program terminates when SIGINT is sent no matter what I add after the while loop, which is the same for almost all other command-line programs as well. – kaykun Jun 06 '11 at 09:21
  • @kaykun, okay, I assumed you're currently not handling the signal; answer updated to show how to ignore or handle `SIGINT`. – sarnold Jun 06 '11 at 09:35
  • 3
    Using sigaction as you described with SIG_IGN only makes Ctrl+C do nothing; read still blocks. You can check for yourself: http://pastebin.com/ybVt79tQ – kaykun Jun 06 '11 at 09:47
  • @kaykun, excellent little test program. Pity there's only one +1 to give. – sarnold Jun 06 '11 at 10:03
  • Better answer to this problem is https://stackoverflow.com/a/51742996/1164753 – Petr Jan 28 '22 at 20:16
  • 1
    `handle_int(int num)` needs to specify the type for the parameter. Unfortunately, the edit queue is full for this answer... – darkdragon Oct 19 '22 at 16:25
  • @darkdragon, heh, I'm surprised I missed that. Thanks – sarnold Oct 20 '22 at 20:56
  • 1
    Another interesting discovery I made, is that registering the handler via [`std::signal()`](https://en.cppreference.com/w/cpp/utility/program/signal) doesn't work but using `sigaction()` does. Furthermore, it seems that `read()` isn't interrupted on all platforms (e.g. not in my tests for [NXP/Freescale](https://www.variscite.com/product/system-on-module-som/cortex-a9/dart-mx6-cpu-freescale-imx6/) using their Yocto BSP). – darkdragon Oct 22 '22 at 10:42
3

When your process receives a signal, read() will return and the value of errno will be set to EINTR.

Blagovest Buyukliev
  • 42,498
  • 14
  • 94
  • 130