Can't catch SIGINT signal when using select ()

I am trying to handle signals while listening on a socket in syscall select.

Problem: I have a work cycle with a selected call. select is waiting for a socket descriptor. You need to break the loop into SIGINT or SIGQUIT and fix the closed resources and exit the program. Below is the code

#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <error.h>
#include <errno.h>
#include <signal.h>
#include <syslog.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <netinet/in.h>


bool bBreakJob = false;

void sig_handler(int sig)
{
    switch(sig)
    {
    case SIGHUP:
        //rneed to reload config
        break;
    case SIGINT:
        printf("SIGINT \n");
        bBreakJob = true;
        openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON);
        syslog(LOG_INFO, "Catched SIGINT");
        closelog();
        break;
    case SIGQUIT:
        printf("SIGQUIT \n");
        openlog("mydaemon", LOG_PID | LOG_CONS, LOG_DAEMON);
        syslog(LOG_INFO, "Catched SIGQUIT");
        bBreakJob = true;
        break;
    case SIGPIPE:
        printf("SIGPIPE \n");
        break;
    }
}

int main(int argc, char** argv)
{
    struct sigaction act, oact;
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, SIGINT);
    sigaddset(&set, SIGHUP);
    sigaddset(&set, SIGPIPE);
    sigaddset(&set, SIGQUIT);
    sigprocmask(SIG_UNBLOCK, &set, NULL);
    act.sa_mask = set;
    act.sa_handler = sig_handler;
    act.sa_flags = 0;
    sigaction(SIGINT, &act, NULL);
    sigaction(SIGHUP, &act, NULL);
    sigaction(SIGPIPE, &act, NULL);
    sigaction(SIGQUIT, &act, NULL);

    int fds[0], res, fmax;
    fd_set wset;
    fd_set rset;

    //next line code to open socket 
    int listen_socket = socket(AF_INET, SOCK_STREAM, 0); 
    int iFlags = fcntl(listen_socket, F_GETFL);
    iFlags |= O_NONBLOCK;
    fcntl(listen_socket, F_SETFL, iFlags);
    struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = htonl(INADDR_ANY);
    sin.sin_port = htons(4000);
    bind(listen_socket, (struct sockaddr *)&sin, sizeof(sin));
    listen(listen_socket, 20);

    fds[0] = listen_socket;
    FD_ZERO(&wset);
    FD_SET(fds[0], &wset);
    fmax = fds[0] + 1;
    while (FD_ISSET(fds[0], &wset))
    {
        rset = wset;
        res = select(fmax, &rset, NULL, NULL, NULL);
        if (res < 0)
        {
            if (errno == EINTR)
            {   //debug message  
                printf("Loop broken by select result EINTR");
                break;
            } else
            {
                printf("select(...) fails in listed loop. errno %d (%s)", errno, strerror(errno));
                exit(1);
            }

        }
        else if (res == 0)
        {
          //if timeout is handled
        }
        else if (res > 0)
        {
            if (FD_ISSET(fds[0], &rset))
            {
                //Handle socket input 
            }
        }
        if(bBreakJob)
        {
          printf("Loop broken by signal handler");
          break; 
        }
    } //while( 1 );
    FD_CLR(fds[0], &wset);
    if(bBreakJob)
    { //debug message 
      printf("signal SIGINT is handled ");
    }

}

      

SIGINT never reaches sig_handler. In the QtCreator IDE, I tried to debug. select only interrupted, then return to listening. The "if (errno == EINTR)" condition is not even met. Ther is not debug messages either in the console or not in syslog. And at the same time SIGQUIT works great: sig_handler is called and the "if (errno == EINTR)" condition is met.

As you can see I tried to check for SIGINT on path: with flag from signal handler and from select result

I tried to find the answer in the thread Failed to catch SIGINT signal when using select () . But can't find a solution. I meet this problem in other WEB-resources, but there is no solution.

The SIGINT signal is sent from the command line: "kill -s 2 (PID)"

UPD issue resolved. The problem was in the debugger. SIGINT does not work correctly in the debugger. Running the program without debugging works fine as expected.

+3


source to share


1 answer


The interplay of selections and signals is tricky because a signal can always appear before you choose select. Here are two ways to wake up a selection loop from a signal handler:



  • Self-propelled trick: create a feed and add the end of the reading to the selected reading set. From the signal handler, write one byte to the end of that channel's record, and it will immediately make a selection right away (because the input is ready).

  • Instead of passing NULL as the last argument for the selection, pass a pointer to timeval, which is a global variable. Within your signal handler, make the timeval 0 seconds. Hence, if a signal arrives before you choose select, select will ask for a 0 timeout and return immediately.

+1


source







All Articles