Created
December 14, 2017 19:52
-
-
Save davmac314/422dff2caf0254f982955a8bdf2c5704 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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