私はユーザー定義のシグナルハンドラを持つ親プロセスを持っています。信号が受信されるたびに、私はグローバル変数を設定し、メインループでは、各入力処理の前に信号が受信されているかどうかを確認しています。プロセスが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?
のための答えを参照してください。
は '' WNOHANG'と '睡眠を()失います。子プロセスが終了するか、シグナルを受け取るまで、 'waitpid()'をブロックします。 'while(waitpid(cpid、&status、0)> 0 || errno == EINTR){if(g_signal_number);}ブレーク; } 'おそらく。 –
@ JonathanLeffler。私はquititon.modifiedシグナルSIGINTをSIGHUPに編集しました。親プロセスがSIGHUPを受け取った場合、waidpidはerrnoをEINTRに設定しますか? –
'EINTR'は、シグナル(任意のシグナル)が受信されたことを意味し、特に' SIGINT'が受信されたシグナルではありません。 –