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

긴 이야기 짧게로 마이그레이션할 때 에 대한 호출 등에 대한 코드를 확인하여 신호 마스크로 인해 엉망이 된 일부 코드 경로를 잊어버리지 않았는지 확인하세요 signal(2).sigaction(2)pthread_sigmask(2)signalfd(2)

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

답변2

귀하의 read(2)반환은 (and)를 사용하여 EAGAIN비차단 모드에서 파일을 열기 때문입니다.signalfd(..., SFD_NONBLOCK | ...)SFD_NONBLOCKO_NONBLOCK

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

관련 정보