`signalfd(2)`의 파일 설명자는 읽을 준비가 되어 있지 않습니다.

`signalfd(2)`의 파일 설명자는 읽을 준비가 되어 있지 않습니다.

나는 상당히 큰 응용 프로그램을 관리하고 있습니다. 작업의 일부로 일부 하위 프로세스를 생성하고 해당 상태(실행 중, 충돌)를 모니터링해야 합니다.

SIGCHLD을 사용하기 위한 신호 처리기를 설정하여 하위 프로세스 종료가 감지되었습니다 signal(2). 얼마 전에 signalfd(2). 내가 한 일은 간단했다:

  1. 신호 처리기를 제거했습니다.SIGCHLD
  2. 차단 SIGCHLD하고 signalfd(2)캡처하기 위해 생성했습니다.SIGCHLD

내 문제는 내가 만든 파일 설명자가 SIGCHLD. 그러나 read(2)해당 설명자에 대한 호출 의 반환 값을 무시 하고 waitpid(-1, &status, WNOHANG)호출 하면~할 수 있다종료된 하위 프로세스에 대한 정보를 얻습니다. 따라서 알림이 전달된 것처럼 보이지만 signalfd(2)설명자는 이를 무시합니다.

나는 프로그램에서 설명자 read(2)에서 호출되는 위치가 정확히 한 곳 signalfd(2), 호출되는 위치가 정확히 한 곳 waitpid(2), 신호 처리가 설정된 위치가 정확히 한 곳인지 확인했습니다.

설정 코드는 다음과 같습니다.

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).

TL;DR신호 마스크를 방해하는 일부 코드 경로를 잊지 않았는지 확인하기 위해 마이그레이션할 때 , 등에 signal(2)대한 sigaction(2)호출 에 대한 코드를 검사하십시오 .pthread_sigmask(2)signalfd(2)

(2년 반이 지나면 조금 늦을 수도 있지만, 답변이 누군가에게는 도움이 될 수도 있겠네요.)

답변2

( 는 와 동일 ) 을 사용하여 비차단 모드에서 파일을 열었기 때문에 반환 read(2)됩니다 .EAGAINsignalfd(..., SFD_NONBLOCK | ...)SFD_NONBLOCKO_NONBLOCK

읽기 차단을 수행하려면 파일 설명자를 열거나 비차단 모드로 설정하지 마세요.

관련 정보