Skip to content

Instantly share code, notes, and snippets.

@davmac314
Created December 14, 2017 19:52
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save davmac314/422dff2caf0254f982955a8bdf2c5704 to your computer and use it in GitHub Desktop.
Save davmac314/422dff2caf0254f982955a8bdf2c5704 to your computer and use it in GitHub Desktop.
#include <sys/types.h>
#include <sys/event.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
// Program to demonstrate kqueue bug on macOS (Sierra, possibly others). The
// kqueue mechanism can sometimes reports that a SIGCHLD signal has been
// received, but the signal does not yet report as pending.
//
// Running this program will output a message similar to the following, if the
// bug is present:
//
// Received SIGCHLD kevent but SIGCHLD is not (yet) pending; i = 273
//
// (The number is the number of loop iterations before the bug was hit).
void errout(const char * s)
{
perror(s);
exit(1);
}
void sighandler(int signo)
{
}
int main(int argc, char **argv)
{
int kq = kqueue();
if (kq == -1) errout("kqueue");
// Mask SIGCHLD (but establish a handler):
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset, SIGCHLD);
sigprocmask(SIG_BLOCK, &sigset, NULL);
struct sigaction sa;
sa.sa_handler = sighandler;
sigfillset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGCHLD, &sa, NULL) == -1) errout("sigaction");
struct timespec timeout;
timeout.tv_nsec = 0;
timeout.tv_sec = 0;
// Set up kqueue to report SIGCHLD:
struct kevent kev;
EV_SET(&kev, SIGCHLD, EVFILT_SIGNAL, EV_ADD, 0, 0, 0);
if (kevent(kq, &kev, 1, NULL, 0, &timeout) == -1) errout("kevent");
for (int i = 0; i < 10000; i++) {
// Fork a child, which immediately exits, to generate SIGCHLD:
pid_t child = fork();
if (child == 0) {
_exit(0);
}
// Retrieve event from kqueue, and make sure it refers to the SIGCHLD:
int r;
if ((r = kevent(kq, NULL, 0, &kev, 1, NULL)) == -1) errout("kevent");
if (r != 1) {
fprintf(stderr, "kevent: didn't receive one event?\n");
exit(1);
}
if (kev.filter != EVFILT_SIGNAL || kev.ident != SIGCHLD) {
fprintf(stderr, "kevent: received wrong event?\n");
exit(1);
}
// Now confirm that SIGCHLD is actually pending:
sigset_t pendingsigs;
sigpending(&pendingsigs);
if (! sigismember(&pendingsigs, SIGCHLD)) {
fprintf(stderr, "Received SIGCHLD kevent but SIGCHLD is not (yet) pending; i = %d\n", i);
exit(1);
}
int signo;
sigwait(&sigset, &signo);
int status;
wait(&status);
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment