在BSD上使用sigtimedwait()捕获SIGCHLD

在BSD上使用sigtimedwait()捕获SIGCHLD,c,linux,signals,bsd,sigchld,C,Linux,Signals,Bsd,Sigchld,我在使用sigtimedwait()捕获FreeBSD上的SIGCHLD信号时遇到问题。以下源代码在Debian GNU/Linux 7上运行良好,但为我提供了FreeBSD 9.1上暂时不可用的资源: #include <stdio.h> #include <signal.h> #include <errno.h> #include <stdlib.h> #include <time.h> int main() {

我在使用sigtimedwait()捕获FreeBSD上的SIGCHLD信号时遇到问题。以下源代码在Debian GNU/Linux 7上运行良好,但为我提供了FreeBSD 9.1上暂时不可用的资源:

#include <stdio.h>
#include <signal.h>
#include <errno.h>
#include <stdlib.h>
#include <time.h>

int main() {
        sigset_t set;
        pid_t pid;

        printf("SIGCHLD is %i\n", SIGCHLD);

        sigemptyset(&set);
        sigaddset(&set, SIGCHLD);
        sigprocmask(SIG_BLOCK, &set, NULL);

        pid = fork();

        if(pid == -1) {
                printf("fork failed: %s\n", strerror(errno));
                exit(1);
        } else if(pid) {
                sigset_t set2;
                siginfo_t siginfo;
                struct timespec timeout = {3, 0};
                int signal;

                sigemptyset(&set2);
                sigaddset(&set2, SIGCHLD);

                signal = sigtimedwait(&set2, &siginfo, &timeout);

                if(signal == -1) {
                        printf("sigtimedwait failed: %s\n", strerror(errno));
                        exit(2);
                } else {
                        printf("received signal %i from %i with status %i\n", signal, siginfo.si_pid, siginfo.si_status);
                }
        } else {
                sleep(1);
                exit(123);
        }

        return 0;
}
FreeBSD上的输出:

SIGCHLD is 20
sigtimedwait failed: Resource temporarily unavailable

在BSD上使用signal()可以很好地工作,但这并不是我想要的。我遗漏了什么?

我认为这是FreeBSD中的内核/库错误。sigtimedwait似乎没有报告信号,因为默认情况下忽略了该信号。所以你可以做两件事

  • 为SIGCHLD事件安装信号处理程序。即使它永远不会被调用,因为你阻止了信号,它将解决这个错误

  • 使用带有EVFILT_信号的kqueue,该信号在这种情况下肯定有效,但不可移植(因此需要ifdef)

  • 对于2,这里是等效代码

         int kq = kqueue();
         struct kevent ke;
         EV_SET(&ke, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
         kevent(kq, &ke, 1, NULL, 0, NULL);
         if (kevent(kq, NULL, 0, &ke, 1, &timeout) == 1) {
              signal = ke.ident;
         }
         else {
             // Catches errors in the add, timeout, and kevent wait
             signal = -1;
         }
         close(kq);
         // note that siginfo is not populated, there is no way to populate it using kqueue.
    
         int kq = kqueue();
         struct kevent ke;
         EV_SET(&ke, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL);
         kevent(kq, &ke, 1, NULL, 0, NULL);
         if (kevent(kq, NULL, 0, &ke, 1, &timeout) == 1) {
              signal = ke.ident;
         }
         else {
             // Catches errors in the add, timeout, and kevent wait
             signal = -1;
         }
         close(kq);
         // note that siginfo is not populated, there is no way to populate it using kqueue.