Ticket #35: kevent_proc.c

File kevent_proc.c, 3.5 KB (added by john, 13 years ago)

Test case

Line 
1#include <sys/types.h>
2#include <sys/event.h>
3#include <assert.h>
4#include <err.h>
5#include <stdint.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <unistd.h>
9
10static pid_t master;
11static int kq;
12
13static void
14watch(uintptr_t ident, short filter, u_short flags, u_int fflags,
15    intptr_t data, void *udata)
16{
17        struct kevent ev;
18
19        EV_SET(&ev, ident, filter, flags, fflags, data, udata);
20        if (kevent(kq, &ev, 1, NULL, 0, NULL) < 0)
21                err(1, "kevent");
22}
23
24static void
25dump_fflags(u_int fflags)
26{
27        int pipe;
28
29        assert(fflags != 0);
30        pipe = 0;
31#define DUMP_FLAG(FLAG) do {                                            \
32                if (fflags & FLAG) {                                    \
33                        printf("%s" #FLAG, pipe ? " | " : "");          \
34                        pipe = 1;                                       \
35                }                                                       \
36        } while (0)
37
38        DUMP_FLAG(NOTE_EXIT);
39        DUMP_FLAG(NOTE_FORK);
40        DUMP_FLAG(NOTE_EXEC);
41        DUMP_FLAG(NOTE_TRACK);
42        DUMP_FLAG(NOTE_TRACKERR);
43        DUMP_FLAG(NOTE_CHILD);
44
45        fflags &= ~(NOTE_EXIT | NOTE_FORK | NOTE_EXEC | NOTE_TRACK |
46            NOTE_TRACKERR | NOTE_CHILD);
47        if (fflags != 0)
48                printf("%s%u", pipe ? " | " : "", fflags);
49}
50
51static void
52dump_event(struct kevent *ev)
53{
54
55        assert(ev->filter == EVFILT_PROC);
56        printf("pid: %5d%s flags: ", (int)ev->ident,
57            ev->flags & EV_EOF ? " EV_EOF" : "");
58        dump_fflags(ev->fflags);
59        if (ev->data != 0)
60                printf(" data: %jd", (uintmax_t)ev->data);
61        printf("\n");
62}
63
64static void
65child(int fd)
66{
67        pid_t pid;
68        char c;
69
70        if (fd > 0)
71                (void)read(fd, &c, sizeof(c));
72        pid = fork();
73        if (pid == -1)
74                err(1, "fork");
75        usleep(5000);
76        exit(1);
77}
78
79static void
80waitfor(int count, const char *msg)
81{
82        struct timespec ts;
83        struct kevent ev;
84        int rv;
85
86        printf("%s:\n", msg);
87
88        /* Wait up to 250 ms before timing out. */
89        ts.tv_sec = 0;
90        ts.tv_nsec = 250 * 1000 * 1000;
91        for (;;) {
92                rv = kevent(kq, NULL, 0, &ev, 1, &ts);
93                if (rv < 0)
94                        err(1, "kevent");
95                if (rv == 0)
96                        break;
97                dump_event(&ev);
98                --count;
99        }
100
101        if (count > 0)
102                warnx("%d events missing for %s", count, msg);
103        else if (count < 0)
104                warnx("%d extra events for %s", -count, msg);
105}
106
107int
108main(int ac, char **av)
109{
110        pid_t pid;
111        int fds[2];
112        char c;
113
114        kq = kqueue();
115        if (kq < 0)
116                err(1, "kqueue");
117        if (pipe(fds) < 0)
118                err(1, "pipe");
119        master = getpid();
120        printf("master: %d\n", (int)master);
121
122        /* Simple fork case. */
123        pid = fork();
124        if (pid == -1)
125                err(1, "fork");
126        if (pid == 0)
127                child(fds[1]);
128        watch(pid, EVFILT_PROC, EV_ADD, NOTE_FORK | NOTE_EXIT, 0, 0);
129        write(fds[0], &c, sizeof(c));
130
131        /* Should get two events, FORK and then EXIT. */
132        waitfor(2, "simple fork");
133
134        /* Test NOTE_TRACK | NOTE_EXIT. */
135        watch(master, EVFILT_PROC, EV_ADD, NOTE_EXIT | NOTE_TRACK, 0, 0);
136        pid = fork();
137        if (pid == -1)
138                err(1, "fork");
139        if (pid == 0)
140                child(-1);
141
142        /* Should get four events: two NOTE_CHILD and two NOTE_EXIT. */
143        waitfor(4, "NOTE_TRACK | NOTE_EXIT");
144
145        /* Test NOTE_TRACK with everything. */
146        watch(master, EVFILT_PROC, EV_ADD, NOTE_FORK | NOTE_EXEC | NOTE_EXIT |
147            NOTE_TRACK, 0, 0);
148        pid = fork();
149        if (pid == -1)
150                err(1, "fork");
151        if (pid == 0)
152                child(-1);
153
154        /*
155         * Should get six events: two each of NOTE_FORK, NOTE_CHILD,
156         * and NOTE_EXIT.
157         */
158        waitfor(6, "TRACK | FORK | EXIT");
159
160        /* Test NOTE_EXEC. */
161        pid = fork();
162        if (pid == -1)
163                err(1, "fork");
164        if (pid == 0) {
165                usleep(5000);
166                execlp("sleep", "sleep", "0.005", (char *)0);
167                err(1, "execlp(\"sleep 0.005\")");
168        }
169
170        /* Should get four events: FORK, CHILD, EXEC, EXIT. */
171        waitfor(4, "simple exec");
172
173        /* Fast exec. */
174        pid = fork();
175        if (pid == -1)
176                err(1, "fork");
177        if (pid == 0) {
178                execlp("true", "true", (char *)0);
179                err(1, "execlp(\"true\")");
180        }
181
182        /* Up to four events, but probably fewer. */
183        waitfor(4, "fast exec");
184        return (0);
185}