나는 상당히 큰 응용 프로그램을 관리하고 있습니다. 작업의 일부로 일부 하위 프로세스를 생성하고 해당 상태(실행 중, 충돌)를 모니터링해야 합니다.
SIGCHLD
을 사용하기 위한 신호 처리기를 설정하여 하위 프로세스 종료가 감지되었습니다 signal(2)
. 얼마 전에 signalfd(2)
. 내가 한 일은 간단했다:
- 신호 처리기를 제거했습니다.
SIGCHLD
- 차단
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)
실패한다는 것입니다 . 이는 내 마스터 프로세스에 전달되어야 함을 의미합니다. 비차단 파일 설명자와 이에 대한 코드 계정이 반환될 수 있다는 것을 알고 있습니다 .EAGAIN
waitpid(2)
SIGCHLD
read(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)
됩니다 .EAGAIN
signalfd(..., SFD_NONBLOCK | ...)
SFD_NONBLOCK
O_NONBLOCK
읽기 차단을 수행하려면 파일 설명자를 열거나 비차단 모드로 설정하지 마세요.