'signalfd(2)' のファイル記述子を読み取れません。

'signalfd(2)' のファイル記述子を読み取れません。

私が作業しているかなり大きなアプリケーションがあります。ジョブの一部としていくつかの子プロセスを作成し、その状態(実行中、競合)を監視する必要があります。

SIGCHLD使用されるシグナルハンドラを設定して、子プロセスの終了を検出しますsignal(2)。私はしばらく前にそれを移行しましたsignalfd(2)。私がしたことは簡単でした。

  1. 除去された信号ハンドラSIGCHLD
  2. ブロックとキャプチャのSIGCHLD作成signalfd(2)SIGCHLD

私の問題は、私が作成したファイル記述子ですSIGCHLDread(2)waitpid(-1, &status, WNOHANG)できる終了した子プロセスに関する情報を取得します。したがって、通知が送信されたように見えますが、signalfd(2)記述子はこれを無視します。

私はプログラムで記述子がread(2)呼び出される位置が正確に1つsignalfd(2)、呼び出された位置が正確に1箇所waitpid(2)、信号処理が設定された位置が正確に1箇所であることを確認しました。

設定コードは次のとおりです。

sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGCHLD);

sigprocmask(SIG_BLOCK, &mask, nullptr);

int signal_fd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
if (signal_fd == -1) {
    /* log failure and exit */
} else {
    /* log success */
}

読み取りコードは次のとおりです。

signalfd_siginfo info;
memset(&info, 0, sizeof(info));

if (read(signal_fd, &info, sizeof(info)) == -1) {
    /*
     * Log failure and return.
     * The file descriptor *always* returns EAGAIN, even in
     * presence of dead child processes.
     */
    return;
}

if (info.ssi_signo == SIGCHLD) {
    int status = 0;
    int child = waitpid(-1, &status, WNOHANG);

    /*
     * Process result of waitpid(2). The call is successful even if
     * the read of signalfd above returned an error.
     */
}

私は何が間違っていましたか?

編集する:問題は、-edする準備が整った死んだサブプロセスがあるにもかかわらずread(2)失敗することです。これは、私の基本プロセスにそのプロセスを渡す必要があることを意味します。私はこれが非ブロックファイル記述子を返すことができることを知っており、コードはそれを示しています。EAGAINwaitpid(2)SIGCHLDread(2)EAGAIN

答え1

信号処理から移行するときは、信号の受信方法に基づいて、または変更してsignal(2)くださいsigaction(2)signalfd(2)以前の方法では信号が妨げられずに流れることを許可していましたが、新しい方法では信号をブロックする必要があります。

特定のコード領域で信号干渉を望まない場合は、その領域をブロックする必要があります。

sigset_t mask;
sigemptyset(&mask);
sigaddset(&mask, SIGFOO);
pthread_sigmask(SIG_BLOCK, &mask, nullptr);

{
    /* not-to-be-disturbed code here */
}

後で必要です。やるそうでなければ、それを拾うsignal(2)方法がないからです。sigaction(2)

{
    /* not-to-be-disturbed code here */
}

pthread_sigmask(SIG_UNBLOCK, &mask, nullptr);

ただし、signalfd(2)信号はブロックされたままにする必要があるためです。長い間無視されたコードパスがあり、ほとんど見ておらず、特定の信号をブロックしてブロック解除する従来の方法に従うと、開始したものが壊れる可能性がありますsignalfd(2)

長い話を短くに移行するときの呼び出しなどのコードを調べて、信号マスクのために混乱したコードパスを忘れていないことを確認してくださいsignal(2)sigaction(2)pthread_sigmask(2)signalfd(2)

(2年半が過ぎると少し遅れるかもしれませんが、答えが誰かに役立つかもしれませんね。)

答え2

あなたのread(2)リターンは(and)を使用して非EAGAINブロックモードでファイルを開くからです。signalfd(..., SFD_NONBLOCK | ...)SFD_NONBLOCKO_NONBLOCK

ファイル記述子のブロック読み取りを実行するには、ファイル記述子を開いたり、非ブロックモードに設定しないでください。

関連情報