xref: /openbsd-src/regress/sys/kern/kqueue/kqueue-process.c (revision 1e522b7ed1a0747f70c841dcf5b973f4d8de556d)
1*1e522b7eSvisa /*	$OpenBSD: kqueue-process.c,v 1.13 2018/08/03 15:19:44 visa Exp $	*/
257ee2582Sart /*
357ee2582Sart  *	Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain
457ee2582Sart  */
557ee2582Sart 
657ee2582Sart #include <sys/types.h>
757ee2582Sart #include <sys/event.h>
8*1e522b7eSvisa #include <sys/time.h>
957ee2582Sart #include <sys/wait.h>
1057ee2582Sart 
1157ee2582Sart #include <err.h>
12b261876bSguenther #include <errno.h>
13bd35765dSbluhm #include <stdio.h>
14bd35765dSbluhm #include <stdlib.h>
15bd35765dSbluhm #include <unistd.h>
16bd35765dSbluhm 
17bd35765dSbluhm #include "main.h"
1857ee2582Sart 
1957ee2582Sart static int process_child(void);
2057ee2582Sart 
21*1e522b7eSvisa static int pfd1[2];
22*1e522b7eSvisa static int pfd2[2];
2357ee2582Sart 
2457ee2582Sart int
do_process(void)2557ee2582Sart do_process(void)
2657ee2582Sart {
2757ee2582Sart 	struct kevent ke;
28*1e522b7eSvisa 	struct timespec ts;
2957ee2582Sart 	int kq, status;
3057ee2582Sart 	pid_t pid, pid2;
3157ee2582Sart 	int didfork, didchild;
3257ee2582Sart 	int i;
33*1e522b7eSvisa 	char ch = 0;
3457ee2582Sart 
3557ee2582Sart 	/*
3657ee2582Sart 	 * Timeout in case something doesn't work.
3757ee2582Sart 	 */
3857ee2582Sart 	ts.tv_sec = 10;
3957ee2582Sart 	ts.tv_nsec = 0;
4057ee2582Sart 
41bd35765dSbluhm 	ASS((kq = kqueue()) >= 0,
42bd35765dSbluhm 	    warn("kqueue"));
4357ee2582Sart 
44*1e522b7eSvisa 	/* Open pipes for synchronizing the children with the parent. */
45*1e522b7eSvisa 	if (pipe(pfd1) == -1)
46*1e522b7eSvisa 		err(1, "pipe 1");
47*1e522b7eSvisa 	if (pipe(pfd2) == -1)
48*1e522b7eSvisa 		err(1, "pipe 2");
4957ee2582Sart 
5057ee2582Sart 	switch ((pid = fork())) {
5157ee2582Sart 	case -1:
5257ee2582Sart 		err(1, "fork");
5357ee2582Sart 	case 0:
5457ee2582Sart 		_exit(process_child());
5557ee2582Sart 	}
5657ee2582Sart 
5757ee2582Sart 	EV_SET(&ke, pid, EVFILT_PROC, EV_ADD|EV_ENABLE|EV_CLEAR,
5857ee2582Sart 	    NOTE_EXIT|NOTE_FORK|NOTE_EXEC|NOTE_TRACK, 0, NULL);
5957ee2582Sart 	ASS(kevent(kq, &ke, 1, NULL, 0, NULL) == 0,
6057ee2582Sart 	    warn("can't register events on kqueue"));
6157ee2582Sart 
62b261876bSguenther 	/* negative case */
63d27560bfSbluhm 	EV_SET(&ke, pid + (1ULL << 30), EVFILT_PROC, EV_ADD|EV_ENABLE|EV_CLEAR,
64b261876bSguenther 	    NOTE_EXIT|NOTE_FORK|NOTE_EXEC|NOTE_TRACK, 0, NULL);
65b261876bSguenther 	ASS(kevent(kq, &ke, 1, NULL, 0, NULL) != 0,
66b261876bSguenther 	    warnx("can register bogus pid on kqueue"));
67b261876bSguenther 	ASS(errno == ESRCH,
68b261876bSguenther 	    warn("register bogus pid on kqueue returned wrong error"));
69b261876bSguenther 
70*1e522b7eSvisa 	ASS(write(pfd1[1], &ch, 1) == 1,
71*1e522b7eSvisa 	    warn("write sync 1"));
7257ee2582Sart 
7357ee2582Sart 	didfork = didchild = 0;
7457ee2582Sart 
75544ebf79Smickey 	pid2 = -1;
7657ee2582Sart 	for (i = 0; i < 2; i++) {
7757ee2582Sart 		ASS(kevent(kq, NULL, 0, &ke, 1, &ts) == 1,
7857ee2582Sart 		    warnx("didn't receive event"));
7957ee2582Sart 		ASSX(ke.filter == EVFILT_PROC);
8057ee2582Sart 		switch (ke.fflags) {
8157ee2582Sart 		case NOTE_CHILD:
8257ee2582Sart 			didchild = 1;
8357ee2582Sart 			ASSX((pid_t)ke.data == pid);
8457ee2582Sart 			pid2 = ke.ident;
8559d8cb9eSguenther 			fprintf(stderr, "child %d (from %d)\n", pid2, pid);
8657ee2582Sart 			break;
8757ee2582Sart 		case NOTE_FORK:
8857ee2582Sart 			didfork = 1;
8957ee2582Sart 			ASSX(ke.ident == pid);
9057ee2582Sart 			fprintf(stderr, "fork\n");
9157ee2582Sart 			break;
9257ee2582Sart 		case NOTE_TRACKERR:
9357ee2582Sart 			errx(1, "child tracking failed due to resource shortage");
9457ee2582Sart 		default:
95c20d9ad4Sjsyn 			errx(1, "kevent returned weird event 0x%x pid %d",
9657ee2582Sart 			    ke.fflags, (pid_t)ke.ident);
9757ee2582Sart 		}
9857ee2582Sart 	}
9957ee2582Sart 
100bd35765dSbluhm 	ASSX(pid2 != -1);
101544ebf79Smickey 
10257ee2582Sart 	/* Both children now sleeping. */
10357ee2582Sart 
10459d8cb9eSguenther 	ASSX(didchild == 1);
10559d8cb9eSguenther 	ASSX(didfork == 1);
10657ee2582Sart 
107*1e522b7eSvisa 	ASS(write(pfd2[1], &ch, 1) == 1,
108*1e522b7eSvisa 	    warn("write sync 2.1"));
109*1e522b7eSvisa 	ASS(write(pfd1[1], &ch, 1) == 1,
110*1e522b7eSvisa 	    warn("write sync 2"));
11157ee2582Sart 
112*1e522b7eSvisa 	/*
113*1e522b7eSvisa 	 * Wait for child's exit. It also implies child-child has exited.
114*1e522b7eSvisa 	 * This should ensure that NOTE_EXIT has been posted for both children.
115*1e522b7eSvisa 	 * Child-child's events should get aggregated.
116*1e522b7eSvisa 	 */
11757ee2582Sart 	if (wait(&status) < 0)
11857ee2582Sart 		err(1, "wait");
11957ee2582Sart 
120a7c05c97Suebayasi 	for (i = 0; i < 2; i++) {
12159d8cb9eSguenther 		ASS(kevent(kq, NULL, 0, &ke, 1, &ts) == 1,
12259d8cb9eSguenther 		    warnx("didn't receive event"));
12359d8cb9eSguenther 		ASSX(ke.filter == EVFILT_PROC);
12459d8cb9eSguenther 		switch (ke.fflags) {
12559d8cb9eSguenther 		case NOTE_EXIT:
12659d8cb9eSguenther 			ASSX((pid_t)ke.ident == pid);
127a7c05c97Suebayasi 			fprintf(stderr, "child exit %d\n", pid);
128a7c05c97Suebayasi 			break;
129a7c05c97Suebayasi 		case NOTE_EXEC | NOTE_EXIT:
130a7c05c97Suebayasi 			ASSX((pid_t)ke.ident == pid2);
131a7c05c97Suebayasi 			fprintf(stderr, "child-child exec/exit %d\n", pid2);
13259d8cb9eSguenther 			break;
13359d8cb9eSguenther 		default:
13459d8cb9eSguenther 			errx(1, "kevent returned weird event 0x%x pid %d",
13559d8cb9eSguenther 			    ke.fflags, (pid_t)ke.ident);
13659d8cb9eSguenther 		}
137f3388f05Suebayasi 	}
13859d8cb9eSguenther 
13957ee2582Sart 	if (!WIFEXITED(status))
14057ee2582Sart 		errx(1, "child didn't exit?");
14157ee2582Sart 
14257ee2582Sart 	close(kq);
14357ee2582Sart 	return (WEXITSTATUS(status) != 0);
14457ee2582Sart }
14557ee2582Sart 
14657ee2582Sart static int
process_child(void)14757ee2582Sart process_child(void)
14857ee2582Sart {
149*1e522b7eSvisa 	int status;
150*1e522b7eSvisa 	char ch;
15157ee2582Sart 
152*1e522b7eSvisa 	ASS(read(pfd1[0], &ch, 1) == 1,
153*1e522b7eSvisa 	    warn("read sync 1"));
15457ee2582Sart 
15557ee2582Sart 	/* fork and see if tracking works. */
15657ee2582Sart 	switch (fork()) {
15757ee2582Sart 	case -1:
15857ee2582Sart 		err(1, "fork");
15957ee2582Sart 	case 0:
160*1e522b7eSvisa 		ASS(read(pfd2[0], &ch, 1) == 1,
161*1e522b7eSvisa 		    warn("read sync 2.1"));
16253408464Skrw 		execl("/usr/bin/true", "true", (char *)NULL);
16357ee2582Sart 		err(1, "execl(true)");
16457ee2582Sart 	}
16557ee2582Sart 
166*1e522b7eSvisa 	ASS(read(pfd1[0], &ch, 1) == 1,
167*1e522b7eSvisa 	    warn("read sync 2"));
168*1e522b7eSvisa 
169*1e522b7eSvisa 	if (wait(&status) < 0)
170*1e522b7eSvisa 		err(1, "wait 2");
171*1e522b7eSvisa 	if (!WIFEXITED(status))
172*1e522b7eSvisa 		errx(1, "child-child didn't exit?");
17357ee2582Sart 
17457ee2582Sart 	return 0;
17557ee2582Sart }
176