xref: /openbsd-src/regress/sys/kern/kqueue/kqueue-process.c (revision c20d9ad407c19e76b866bffb8304aa598c583016)
1 /*	$OpenBSD: kqueue-process.c,v 1.2 2002/06/11 06:16:36 jsyn Exp $	*/
2 /*
3  *	Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain
4  */
5 
6 #include <sys/types.h>
7 #include <sys/event.h>
8 #include <sys/wait.h>
9 
10 #include <stdlib.h>
11 #include <stdio.h>
12 #include <err.h>
13 #include <unistd.h>
14 #include <signal.h>
15 
16 static int process_child(void);
17 
18 #define ASS(cond, mess) do { if (!(cond)) { mess; return 1; } } while (0)
19 
20 #define ASSX(cond) ASS(cond, warnx("assertion " #cond " failed on line %d", __LINE__))
21 
22 void
23 usr1handler(int signum)
24 {
25 	/* nada */
26 }
27 
28 int
29 do_process(void)
30 {
31 	struct kevent ke;
32 	int kq, status;
33 	pid_t pid, pid2;
34 	int didfork, didchild;
35 	int i;
36 	struct timespec ts;
37 
38 	/*
39 	 * Timeout in case something doesn't work.
40 	 */
41 	ts.tv_sec = 10;
42 	ts.tv_nsec = 0;
43 
44 	ASS((kq = kqueue()) >= 0, warn("kqueue"));
45 
46 	/*
47 	 * Install a signal handler so that we can use pause() to synchronize
48 	 * with the child with the parent.
49 	 */
50 	signal(SIGUSR1, usr1handler);
51 
52 	switch ((pid = fork())) {
53 	case -1:
54 		err(1, "fork");
55 	case 0:
56 		_exit(process_child());
57 	}
58 
59 	sleep(2);	/* wait for child to settle down. */
60 
61 	EV_SET(&ke, pid, EVFILT_PROC, EV_ADD|EV_ENABLE|EV_CLEAR,
62 	    NOTE_EXIT|NOTE_FORK|NOTE_EXEC|NOTE_TRACK, 0, NULL);
63 	ASS(kevent(kq, &ke, 1, NULL, 0, NULL) == 0,
64 	    warn("can't register events on kqueue"));
65 
66 	kill(pid, SIGUSR1);	/* sync 1 */
67 
68 	didfork = didchild = 0;
69 
70 	for (i = 0; i < 2; i++) {
71 		ASS(kevent(kq, NULL, 0, &ke, 1, &ts) == 1,
72 		    warnx("didn't receive event"));
73 		ASSX(ke.filter == EVFILT_PROC);
74 		switch (ke.fflags) {
75 		case NOTE_CHILD:
76 			didchild = 1;
77 			ASSX((pid_t)ke.data == pid);
78 			pid2 = ke.ident;
79 			fprintf(stderr, "child %d\n", pid2);
80 			break;
81 		case NOTE_FORK:
82 			didfork = 1;
83 			ASSX(ke.ident == pid);
84 			fprintf(stderr, "fork\n");
85 			break;
86 		case NOTE_TRACKERR:
87 			errx(1, "child tracking failed due to resource shortage");
88 		default:
89 			errx(1, "kevent returned weird event 0x%x pid %d",
90 			    ke.fflags, (pid_t)ke.ident);
91 		}
92 	}
93 
94 	/* Both children now sleeping. */
95 
96 	ASSX(didchild == didfork == 1);
97 
98 	kill(pid2, SIGUSR1);	/* sync 2.1 */
99 	kill(pid, SIGUSR1);	/* sync 2 */
100 
101 	if (wait(&status) < 0)
102 		err(1, "wait");
103 
104 	if (!WIFEXITED(status))
105 		errx(1, "child didn't exit?");
106 
107 	close(kq);
108 	return (WEXITSTATUS(status) != 0);
109 }
110 
111 static int
112 process_child(void)
113 {
114 	signal(SIGCHLD, SIG_IGN);	/* ignore our children. */
115 
116 	pause();
117 
118 	/* fork and see if tracking works. */
119 	switch (fork()) {
120 	case -1:
121 		err(1, "fork");
122 	case 0:
123 		/* sync 2.1 */
124 		pause();
125 		execl("/usr/bin/true", "true", NULL);
126 		err(1, "execl(true)");
127 	}
128 
129 	/* sync 2 */
130 	pause();
131 
132 	return 0;
133 }
134