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