!['signalfd(2)'의 파일 설명자를 읽을 수 없습니다.](https://linux55.com/image/170587/'signalfd(2)'%EC%9D%98%20%ED%8C%8C%EC%9D%BC%20%EC%84%A4%EB%AA%85%EC%9E%90%EB%A5%BC%20%EC%9D%BD%EC%9D%84%20%EC%88%98%20%EC%97%86%EC%8A%B5%EB%8B%88%EB%8B%A4..png)
제가 작업하고 있는 꽤 큰 규모의 애플리케이션이 있습니다. 작업의 일부로 일부 하위 프로세스를 생성하고 해당 상태(실행 중, 충돌)를 모니터링해야 합니다.
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)
.
긴 이야기 짧게로 마이그레이션할 때 에 대한 호출 등에 대한 코드를 확인하여 신호 마스크로 인해 엉망이 된 일부 코드 경로를 잊어버리지 않았는지 확인하세요 signal(2)
.sigaction(2)
pthread_sigmask(2)
signalfd(2)
(2년 반이 지나면 조금 늦을 수도 있겠지만, 답변이 누군가에게는 도움이 될 수도 있겠네요.)
답변2
귀하의 read(2)
반환은 (and)를 사용하여 EAGAIN
비차단 모드에서 파일을 열기 때문입니다.signalfd(..., SFD_NONBLOCK | ...)
SFD_NONBLOCK
O_NONBLOCK
파일 설명자에 대해 차단 읽기를 수행하려면 파일 설명자를 열거나 비차단 모드로 설정하지 마세요.