xref: /freebsd/tools/test/stress2/misc/kevent19.sh (revision d7ff2ded474871d69f19b0d03deed5f66d78435e)
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