1*d7ff2dedSPeter Holm#!/bin/sh 2*d7ff2dedSPeter Holm 3*d7ff2dedSPeter Holm# A kqueuex(KQUEUE_CPONFORK) test scenario 4*d7ff2dedSPeter Holm 5*d7ff2dedSPeter Holmset -u 6*d7ff2dedSPeter Holmprog=$(basename "$0" .sh) 7*d7ff2dedSPeter Holm 8*d7ff2dedSPeter Holmcat > /tmp/$prog.c <<EOF 9*d7ff2dedSPeter Holm/* \$Id: kqfork.c,v 1.4 2025/08/19 19:42:16 kostik Exp kostik $ */ 10*d7ff2dedSPeter Holm 11*d7ff2dedSPeter Holm#include <sys/param.h> 12*d7ff2dedSPeter Holm#include <sys/event.h> 13*d7ff2dedSPeter Holm#include <err.h> 14*d7ff2dedSPeter Holm#include <signal.h> 15*d7ff2dedSPeter Holm#include <stdbool.h> 16*d7ff2dedSPeter Holm#include <stdio.h> 17*d7ff2dedSPeter Holm#include <stdlib.h> 18*d7ff2dedSPeter Holm#include <string.h> 19*d7ff2dedSPeter Holm#include <unistd.h> 20*d7ff2dedSPeter Holm 21*d7ff2dedSPeter Holm#ifndef KQUEUE_CPONFORK 22*d7ff2dedSPeter Holm#define KQUEUE_CPONFORK 0x2 23*d7ff2dedSPeter Holm#endif 24*d7ff2dedSPeter Holm 25*d7ff2dedSPeter Holmstatic pid_t pid_pipe_beat; 26*d7ff2dedSPeter Holmstatic pid_t pid_controller; 27*d7ff2dedSPeter Holm 28*d7ff2dedSPeter Holmstatic void 29*d7ff2dedSPeter Holmsighup_handler(int sig __unused) 30*d7ff2dedSPeter Holm{ 31*d7ff2dedSPeter Holm kill(pid_pipe_beat, SIGKILL); 32*d7ff2dedSPeter Holm _exit(1); 33*d7ff2dedSPeter Holm} 34*d7ff2dedSPeter Holm 35*d7ff2dedSPeter Holmstatic void 36*d7ff2dedSPeter Holmpipe_beat(int wp) 37*d7ff2dedSPeter Holm{ 38*d7ff2dedSPeter Holm static const char a[1] = { 'a' }; 39*d7ff2dedSPeter Holm ssize_t s; 40*d7ff2dedSPeter Holm 41*d7ff2dedSPeter Holm for (;;) { 42*d7ff2dedSPeter Holm sleep(1); 43*d7ff2dedSPeter Holm s = write(wp, a, 1); 44*d7ff2dedSPeter Holm if (s < 0) 45*d7ff2dedSPeter Holm err(1, "pipe write"); 46*d7ff2dedSPeter Holm if (s == 0) 47*d7ff2dedSPeter Holm errx(1, "short pipe write"); 48*d7ff2dedSPeter Holm } 49*d7ff2dedSPeter Holm} 50*d7ff2dedSPeter Holm 51*d7ff2dedSPeter Holmstatic void 52*d7ff2dedSPeter Holmworker(int kq, int rp) 53*d7ff2dedSPeter Holm{ 54*d7ff2dedSPeter Holm struct kevent ev[1]; 55*d7ff2dedSPeter Holm char a[1]; 56*d7ff2dedSPeter Holm ssize_t s; 57*d7ff2dedSPeter Holm int n; 58*d7ff2dedSPeter Holm 59*d7ff2dedSPeter Holm for (;;) { 60*d7ff2dedSPeter Holm n = kevent(kq, NULL, 0, ev, nitems(ev), NULL); 61*d7ff2dedSPeter Holm if (n == -1) { 62*d7ff2dedSPeter Holm kill(pid_controller, SIGHUP); 63*d7ff2dedSPeter Holm err(1, "kqueue"); 64*d7ff2dedSPeter Holm } 65*d7ff2dedSPeter Holm if (n == 0) 66*d7ff2dedSPeter Holm continue; // XXXKIB 67*d7ff2dedSPeter Holm switch (ev[0].filter) { 68*d7ff2dedSPeter Holm case EVFILT_TIMER: 69*d7ff2dedSPeter Holm printf("tick\n"); 70*d7ff2dedSPeter Holm break; 71*d7ff2dedSPeter Holm case EVFILT_READ: 72*d7ff2dedSPeter Holm if (ev[0].ident != (uintptr_t)rp) { 73*d7ff2dedSPeter Holm kill(pid_controller, SIGHUP); 74*d7ff2dedSPeter Holm errx(1, "unknown read ident %d\n", (int)ev[0].ident); 75*d7ff2dedSPeter Holm } 76*d7ff2dedSPeter Holm s = read(rp, a, sizeof(a)); 77*d7ff2dedSPeter Holm if (s == -1) { 78*d7ff2dedSPeter Holm kill(pid_controller, SIGHUP); 79*d7ff2dedSPeter Holm err(1, "read"); 80*d7ff2dedSPeter Holm } 81*d7ff2dedSPeter Holm if (s == 0) { 82*d7ff2dedSPeter Holm kill(pid_controller, SIGHUP); 83*d7ff2dedSPeter Holm errx(1, "EOF"); 84*d7ff2dedSPeter Holm } 85*d7ff2dedSPeter Holm printf("%c\n", a[0]); 86*d7ff2dedSPeter Holm break; 87*d7ff2dedSPeter Holm default: 88*d7ff2dedSPeter Holm kill(pid_controller, SIGHUP); 89*d7ff2dedSPeter Holm errx(1, "unknown fiter %d\n", ev[0].filter); 90*d7ff2dedSPeter Holm break; 91*d7ff2dedSPeter Holm } 92*d7ff2dedSPeter Holm } 93*d7ff2dedSPeter Holm} 94*d7ff2dedSPeter Holm 95*d7ff2dedSPeter Holmstatic void 96*d7ff2dedSPeter Holmusage(void) 97*d7ff2dedSPeter Holm{ 98*d7ff2dedSPeter Holm fprintf(stderr, "Usage: kqfork [fork]\n"); 99*d7ff2dedSPeter Holm exit(2); 100*d7ff2dedSPeter Holm} 101*d7ff2dedSPeter Holm 102*d7ff2dedSPeter Holmint 103*d7ff2dedSPeter Holmmain(int argc, char *argv[]) 104*d7ff2dedSPeter Holm{ 105*d7ff2dedSPeter Holm struct kevent ev[2]; 106*d7ff2dedSPeter Holm struct sigaction sa; 107*d7ff2dedSPeter Holm int kq, n, pp[2]; 108*d7ff2dedSPeter Holm pid_t pid_worker; 109*d7ff2dedSPeter Holm bool do_fork; 110*d7ff2dedSPeter Holm 111*d7ff2dedSPeter Holm do_fork = false; 112*d7ff2dedSPeter Holm if (argc != 1 && argc != 2) 113*d7ff2dedSPeter Holm usage(); 114*d7ff2dedSPeter Holm if (argc == 2) { 115*d7ff2dedSPeter Holm if (strcmp(argv[1], "fork") != 0) 116*d7ff2dedSPeter Holm usage(); 117*d7ff2dedSPeter Holm do_fork = true; 118*d7ff2dedSPeter Holm } 119*d7ff2dedSPeter Holm 120*d7ff2dedSPeter Holm memset(&sa, 0, sizeof(sa)); 121*d7ff2dedSPeter Holm sa.sa_handler = sighup_handler; 122*d7ff2dedSPeter Holm if (sigaction(SIGHUP, &sa, NULL) == -1) 123*d7ff2dedSPeter Holm err(1, "sigaction(SIGHUP)"); 124*d7ff2dedSPeter Holm 125*d7ff2dedSPeter Holm memset(&sa, 0, sizeof(sa)); 126*d7ff2dedSPeter Holm sa.sa_flags = SA_NOCLDWAIT | SA_NOCLDSTOP; 127*d7ff2dedSPeter Holm sa.sa_handler = SIG_IGN; 128*d7ff2dedSPeter Holm if (sigaction(SIGCHLD, &sa, NULL) == -1) 129*d7ff2dedSPeter Holm err(1, "sigaction(SIGCHLD)"); 130*d7ff2dedSPeter Holm 131*d7ff2dedSPeter Holm if (pipe(pp) == -1) 132*d7ff2dedSPeter Holm err(1, "pipe"); 133*d7ff2dedSPeter Holm 134*d7ff2dedSPeter Holm pid_pipe_beat = fork(); 135*d7ff2dedSPeter Holm if (pid_pipe_beat == -1) 136*d7ff2dedSPeter Holm err(1, "fork"); 137*d7ff2dedSPeter Holm if (pid_pipe_beat == 0) { 138*d7ff2dedSPeter Holm close(pp[0]); 139*d7ff2dedSPeter Holm pipe_beat(pp[1]); 140*d7ff2dedSPeter Holm } 141*d7ff2dedSPeter Holm 142*d7ff2dedSPeter Holm kq = kqueuex(do_fork ? KQUEUE_CPONFORK : 0); 143*d7ff2dedSPeter Holm if (kq == -1) 144*d7ff2dedSPeter Holm err(1, "kqueuex"); 145*d7ff2dedSPeter Holm 146*d7ff2dedSPeter Holm EV_SET(&ev[0], 1, EVFILT_TIMER, EV_ADD, NOTE_SECONDS, 1, NULL); 147*d7ff2dedSPeter Holm EV_SET(&ev[1], pp[0], EVFILT_READ, EV_ADD, 0, 0, NULL); 148*d7ff2dedSPeter Holm n = kevent(kq, ev, nitems(ev), NULL, 0, NULL); 149*d7ff2dedSPeter Holm if (n == -1) { 150*d7ff2dedSPeter Holm kill(pid_pipe_beat, SIGKILL); 151*d7ff2dedSPeter Holm err(1, "kevent reg"); 152*d7ff2dedSPeter Holm } 153*d7ff2dedSPeter Holm if (n != 0) { 154*d7ff2dedSPeter Holm kill(pid_pipe_beat, SIGKILL); 155*d7ff2dedSPeter Holm errx(1, "kevent reg %d", n); 156*d7ff2dedSPeter Holm } 157*d7ff2dedSPeter Holm 158*d7ff2dedSPeter Holm pid_controller = getpid(); 159*d7ff2dedSPeter Holm 160*d7ff2dedSPeter Holm if (do_fork) { 161*d7ff2dedSPeter Holm pid_worker = fork(); 162*d7ff2dedSPeter Holm if (pid_worker == -1) { 163*d7ff2dedSPeter Holm kill(pid_pipe_beat, SIGKILL); 164*d7ff2dedSPeter Holm err(1, "fork"); 165*d7ff2dedSPeter Holm } 166*d7ff2dedSPeter Holm if (pid_worker == 0) { 167*d7ff2dedSPeter Holm close(pp[1]); 168*d7ff2dedSPeter Holm worker(kq, pp[0]); 169*d7ff2dedSPeter Holm } 170*d7ff2dedSPeter Holm 171*d7ff2dedSPeter Holm for (;;) 172*d7ff2dedSPeter Holm pause(); 173*d7ff2dedSPeter Holm } else { 174*d7ff2dedSPeter Holm worker(kq, pp[0]); 175*d7ff2dedSPeter Holm } 176*d7ff2dedSPeter Holm exit(0); // unreachable 177*d7ff2dedSPeter Holm} 178*d7ff2dedSPeter HolmEOF 179*d7ff2dedSPeter Holmcc -o /tmp/$prog -Wall -Wextra -O2 /tmp/$prog.c || exit 1 180*d7ff2dedSPeter Holm 181*d7ff2dedSPeter Holmecho "--> No fork" 182*d7ff2dedSPeter Holmtimeout 4s /tmp/$prog 183*d7ff2dedSPeter Holmecho "--> fork" 184*d7ff2dedSPeter Holmtimeout 4s /tmp/$prog fork 185*d7ff2dedSPeter Holm 186*d7ff2dedSPeter Holmrm -f /tmp/$prog.c $prog 187*d7ff2dedSPeter Holmexit 0 188