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