Search code examples
clinuxsignalsinterrupt

Interrupting blocked read


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?


Solution

  • 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