繁体   English   中英

进程在waitpid中等待时如何处理信号?

[英]How to handle signals when process is waiting in waitpid?

我有一个带有用户定义的信号处理程序的父进程。 每当接收到信号时,我都会设置一个全局变量,并在主循环中检查每次输入处理之前是否已接收到该信号。

我产生了一个处理用户输入并使用waitpid收集子等待状态的过程。 同时,如果父进程收到用户定义的信号,如何有效处理?

最小化我的应用程序中的代码片段

#include <stdio.h>
#include <signal.h>

volatile sig_atomic_t g_signal_number =0;

void sig_hup_handler()
{       
 g_signal_number = SIGHUP;
}

void do_process_cleanup() {

  //Execute 

}

int execute_user_input(char *str)
{

    pid_t cpid,w;
    cpid = fork();
    if (cpid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    }
    if (cpid == 0) { //Child may take 10-20 second to process the string.
      execute_command(str); 
      _exit(0);
    } else {
       w = waitpid(cpid, &status, 0); 
    }
}

main()
{
  char str[1024];
  signal(SIGHUP, sig_int_handler);

  while(1) {

      if(g_signal_number)
      {
          do_process_cleanup();
          break;
      }
      get_user_input(str);
      if(!strcmp(str,"end"))
          break;
      execute_user_input(str);

  }
      exit(0;)
}

我尝试了以下代码来解决此问题。 有人可以提出更好的方法来解决此问题吗?

while (1) {

   int ret = waitpid(cpid, &status, WNOHANG);

   if(ret > 0)
         break;
   if(ret < 0)
         if(errno == EINTR)
             continue;
   if(g_signal_number)  // break the loop if signal recieved
       break
    sleep(1);
}

也尝试过使用SA_RESTART标志,但是在我的Linux风格中,它对于waitpid系统调用无效。

   int main() {
   :
   sa.sa_handler = sig_hup;
   sigemptyset(&sa.sa_mask);
   sa.sa_flags = SA_RESTART;
   :
   while(1) {
        ret=waitpid(child_pid, &status, 0);
        /*
         *if waipid returns -1 and errno is set to
         *EINTR and g_signum is set,
         *break the loop.
         */
        if(ret == -1 && errno == EINTR && g_signum) {
             printf("signal is set, so break the loop\n");
             break;
        }
        printf("waitpid restart...\n");
   }

从strace输出中可以看到,将SIGHUP发送到PID 17618之后,waitpid也不会中断。

-bash-4.1$ strace -p 17618
Process 17618 attached
wait4(17619, 0x7ffc4a2e2c34, 0, NULL)   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=26521, si_uid=332691} ---
rt_sigreturn()                          = 61
wait4(17619,

环境:类似于RedHat的发行版2.6.39内核

更新

如果将来有人遇到此问题,请参考Linux为什么accept()不返回EINTR的答案

SA_RESTART的处理方式是一种定义的实现。 我的Linux版本(类似于RedHat的发行版,2.6.39内核)对于等待的系统调用不服从SA_RESTART。

但我能够通过在信号处理程序中设置sigaction来解决此问题。

/*
 *test_signal.c
 */
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static struct sigaction sa;
/****Set this variable when SIGHUP received****/
volatile sig_atomic_t g_signum = 0;

/****SIGHUP HANDLER****/
void sig_hup(int signum) {
    /****Set the signal number****/
    g_signum = signum;
    /****Time to intrupt the system call****/
    sigaction(SIGHUP, &sa, 0);

}
int main() {
    int status,ret;
    pid_t child_pid;
    sa.sa_handler = sig_hup;
    sigemptyset(&sa.sa_mask);
    sigaction(SIGHUP, &sa, 0);
    child_pid = fork();
    if(child_pid == 0) {
        sleep(1);//Let the parent print the msg first
        printf("pid:%d:child going to sleep in a loop\n",getpid());
        while(1) {
            sleep(10);
        }
    }
    else{
        printf("parent pid: %d child pid: %d\n",getpid(),child_pid);
        while(1) {
            ret=waitpid(child_pid, &status, 0);
            /*
             *if waitpid returns -1 and errno is set to
             *EINTR and g_signum is set,
             *break the loop.
             */
            if(ret == -1 && errno == EINTR && g_signum) {
                 printf("signal is set, so break the loop\n");
                 break;
            }
            printf("waitpid restart...\n");
       }
    }
return 0;
}

输出:

-bash-4.1$ ./test_signal
parent pid: 11122 child pid: 11123
pid:11123:child going to sleep in a loop
signal is set, so break the loop
-bash-4.1$

发送SIGHUP给父母:

-bash-4.1$ kill -s SIGHUP 11122

跟踪输出:

-bash-4.1$ strace -p 11122
Process 11122 attached
wait4(11123, 0x7ffca4b72c24, 0, NULL)   = ? ERESTARTSYS (To be restarted if SA_RESTART is set)
--- SIGHUP {si_signo=SIGHUP, si_code=SI_USER, si_pid=26521, si_uid=332691} ---
rt_sigaction(SIGHUP, {0x400714, [], SA_RESTORER, 0x33c6432660}, NULL, 8) = 0
rt_sigreturn()                          = -1 EINTR (Interrupted system call)
write(1, "signal is set, so break the loop"..., 33) = 33
exit_group(0)                           = ?
+++ exited with 0 +++
-bash-4.1$

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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