2017-04-19 80 views
0

我有一個用戶定義的信號處理程序的父進程。每當收到一個信號,我設置一個全局變量,並在我的主循環中檢查是否在每次輸入處理之前收到信號。當進程在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內核

更新

如果有人打在未來這個問題請參考答案爲Why doesn't Linux accept() return EINTR?

+0

失去'WNOHANG'和'睡眠()' 。讓'waitpid()'塊直到孩子死亡或你得到信號。 'while(waitpid(cpid,&status,0)> 0 || errno == EINTR){if(g_signal_number);打破; '也許。 –

+0

@JonathanLeffler。我將quesiton.modified的SIGINT信號編輯爲SIGHUP。如果父進程收到SIGHUP,waidpid會將errno設置爲EINTR? –

+0

'EINTR'表示收到一個信號(任何信號),而不是特意接收到'SIGINT'。 –

回答

0

SA_RESTART處理的方式是bi t實現定義。我的Linux風格(類似RedHat的發行版,2.6.39內核)不遵從waitpid系統調用的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 

strace的輸出:

-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$