简体   繁体   中英

Proper way of handling SIGCHLD, EINT, and accept() in Linux

I have a program that creates a TCP server. When the accept() connects to a client, I fork() it and handle the connection. When that client leaves it calls the waitpid() because of the SIGCHLD, but this causes a EINTR in the accept(). My question is how should this be handled? I've read so many different ways.

Most say to ignore it the EINT and try the accept() again. I've even seen a macro to do just that: TEMP_FAILURE_RETRY(). Some say to set the sigaction flags SA_RESTART and SA_NOCLDSTOP. I've tried that and it introduces other errors (errno = ECHILD). Also, how should the child exit? I've seen both _exit(0) and exit(0).

int main( int argc, char *argv[] )
{
   int sockfd, newsockfd, clilen;
   struct sockaddr_in cli_addr;
   int  pid;

   f_SigHandler();
   sockfd = f_SetupTCPSocket();
   clilen = sizeof(cli_addr);

   while (1)
   {
      newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen);
      if (newsockfd < 0)
      {
        if( errno == EINTR ) continue;
        else                 exit(1) ;
      }

      pid = fork();
      if (pid == 0)
      {
        close(sockfd);
        doprocessing();
        close(newsockfd);
        _exit(0);
      }
      else
      {
        close(newsockfd);
      }
   }
}

The SIGCHLD handling is:

void f_ChildHandler(int signal_number)
{
  while (waitpid(-1, NULL, WNOHANG) > 0)
  {
  }
}

void f_SigHandler(void)
{
    struct sigaction sa;

    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = f_ChildHandler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(SIGCHLD, &sa, NULL);
}

In your case, a plain SA_RESTART and the waitpid() in the handler probably suffices. When exit code is uninteresting, you can pass SA_NOCLDWAIT additionally.

When client exit must be handled in a more complex way, you can catch EINTR in the main program and call waitpid() there. To make it race free, you should use pselect() to block the signal. Alternatively, you can create a signalfd and use it in select/poll with your sockfd .

Child should use _exit() to prevent execution of atexit() handlers (eg which write termination entries into a file).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM