來自「signalfd(2)」的檔案描述子永遠無法讀取

來自「signalfd(2)」的檔案描述子永遠無法讀取

我有一個相當大的應用程式正在處理。作為其工作的一部分,它會產生一些子進程並需要監視它們的狀態(正在運行、崩潰)。

SIGCHLD透過設定使用的訊號處理程序來偵測子進程死亡signal(2)。前段時間我把它移轉到了signalfd(2).我所做的很簡單:

  1. 刪除了訊號處理程序SIGCHLD
  2. 阻止SIGCHLD並創建一個signalfd(2)捕獲SIGCHLD

我的問題是我創建的文件描述符似乎沒有捕獲SIGCHLD.但是,如果我忽略該描述符上的呼叫的返回值read(2)並呼叫waitpid(-1, &status, WNOHANG)I取得有關退出的子進程的資訊。所以看起來通知已發送,但我的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)也會失敗,這意味著 a必須已傳遞到我的主進程。我知道這可能會返回非阻塞文件描述符,並且代碼說明了這一點。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

您的read(2)回傳是因為您使用(與)EAGAIN以非阻塞模式開啟檔案。signalfd(..., SFD_NONBLOCK | ...)SFD_NONBLOCKO_NONBLOCK

如果您想對檔案描述符進行阻塞讀取,請不要開啟檔案描述符或將其設定為非阻塞模式。

相關內容