2017-04-19 7 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システムコールではうまくいきませんでした。 straceの出力から

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"); 
    } 

私は中断されませんwaitpidをもPID 17618にSIGHUPを送信した後、見ることができました。

-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。私はquititon.modifiedシグナルSIGINTをSIGHUPに編集しました。親プロセスがSIGHUPを受け取った場合、waidpidはerrnoをEINTRに設定しますか? –

+0

'EINTR'は、シグナル(任意のシグナル)が受信されたことを意味し、特に' SIGINT'が受信されたシグナルではありません。 –

答えて

0

SA_RESTARTの処理方法は、bi実装が定義されています。私の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$ 
関連する問題