]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - tests/sys/kqueue/libkqueue/main.c
Remove EVFILT_PROCDESC block
[FreeBSD/stable/10.git] / tests / sys / kqueue / libkqueue / main.c
1 /*
2  * Copyright (c) 2009 Mark Heily <mark@heily.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  *
16  * $FreeBSD$
17  */
18
19 #include <sys/types.h>
20
21 #include "config.h"
22 #include "common.h"
23
24 int testnum = 1;
25 char *cur_test_id = NULL;
26 int kqfd;
27
28 extern void test_evfilt_read();
29 extern void test_evfilt_signal();
30 extern void test_evfilt_vnode();
31 extern void test_evfilt_timer();
32 extern void test_evfilt_proc();
33 #if HAVE_EVFILT_USER
34 extern void test_evfilt_user();
35 #endif
36
37 /* Checks if any events are pending, which is an error. */
38 void 
39 test_no_kevents(void)
40 {
41     int nfds;
42     struct timespec timeo;
43     struct kevent kev;
44
45     puts("confirming that there are no events pending");
46     memset(&timeo, 0, sizeof(timeo));
47     nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo);
48     if (nfds != 0) {
49         puts("\nUnexpected event:");
50         puts(kevent_to_str(&kev));
51         errx(1, "%d event(s) pending, but none expected:", nfds);
52     }
53 }
54
55 /* Retrieve a single kevent */
56 struct kevent *
57 kevent_get(int kqfd)
58 {
59     int nfds;
60     struct kevent *kev;
61
62     if ((kev = calloc(1, sizeof(*kev))) == NULL)
63         err(1, "out of memory");
64     
65     nfds = kevent(kqfd, NULL, 0, kev, 1, NULL);
66     if (nfds < 1)
67         err(1, "kevent(2)");
68
69     return (kev);
70 }
71
72 /* Retrieve a single kevent, specifying a maximum time to wait for it. */
73 struct kevent *
74 kevent_get_timeout(int kqfd, int seconds)
75 {
76     int nfds;
77     struct kevent *kev;
78     struct timespec timeout = {seconds, 0};
79
80     if ((kev = calloc(1, sizeof(*kev))) == NULL)
81         err(1, "out of memory");
82     
83     nfds = kevent(kqfd, NULL, 0, kev, 1, &timeout);
84     if (nfds < 0) {
85         err(1, "kevent(2)");
86     } else if (nfds == 0) {
87         free(kev);
88         kev = NULL;
89     }
90
91     return (kev);
92 }
93
94 char *
95 kevent_fflags_dump(struct kevent *kev)
96 {
97     char *buf;
98
99 #define KEVFFL_DUMP(attrib) \
100     if (kev->fflags & attrib) \
101         strncat(buf, #attrib" ", 64);
102
103     if ((buf = calloc(1, 1024)) == NULL)
104         abort();
105
106     /* Not every filter has meaningful fflags */
107     if (kev->filter == EVFILT_PROC) {
108         snprintf(buf, 1024, "fflags = %x (", kev->fflags);
109         KEVFFL_DUMP(NOTE_EXIT);
110         KEVFFL_DUMP(NOTE_FORK);
111         KEVFFL_DUMP(NOTE_EXEC);
112         KEVFFL_DUMP(NOTE_CHILD);
113         KEVFFL_DUMP(NOTE_TRACKERR);
114         KEVFFL_DUMP(NOTE_TRACK);
115         buf[strlen(buf) - 1] = ')';
116     } else if (kev->filter == EVFILT_VNODE) {
117         snprintf(buf, 1024, "fflags = %x (", kev->fflags);
118         KEVFFL_DUMP(NOTE_DELETE);
119         KEVFFL_DUMP(NOTE_WRITE);
120         KEVFFL_DUMP(NOTE_EXTEND);
121 #if HAVE_NOTE_TRUNCATE
122         KEVFFL_DUMP(NOTE_TRUNCATE);
123 #endif
124         KEVFFL_DUMP(NOTE_ATTRIB);
125         KEVFFL_DUMP(NOTE_LINK);
126         KEVFFL_DUMP(NOTE_RENAME);
127 #if HAVE_NOTE_REVOKE
128         KEVFFL_DUMP(NOTE_REVOKE);
129 #endif
130         buf[strlen(buf) - 1] = ')';
131     } else {
132         snprintf(buf, 1024, "fflags = %x", kev->fflags);
133     }
134
135     return (buf);
136 }
137
138 char *
139 kevent_flags_dump(struct kevent *kev)
140 {
141     char *buf;
142
143 #define KEVFL_DUMP(attrib) \
144     if (kev->flags & attrib) \
145         strncat(buf, #attrib" ", 64);
146
147     if ((buf = calloc(1, 1024)) == NULL)
148         abort();
149
150     snprintf(buf, 1024, "flags = %d (", kev->flags);
151     KEVFL_DUMP(EV_ADD);
152     KEVFL_DUMP(EV_ENABLE);
153     KEVFL_DUMP(EV_DISABLE);
154     KEVFL_DUMP(EV_DELETE);
155     KEVFL_DUMP(EV_ONESHOT);
156     KEVFL_DUMP(EV_CLEAR);
157     KEVFL_DUMP(EV_EOF);
158     KEVFL_DUMP(EV_ERROR);
159 #if HAVE_EV_DISPATCH
160     KEVFL_DUMP(EV_DISPATCH);
161 #endif
162 #if HAVE_EV_RECEIPT
163     KEVFL_DUMP(EV_RECEIPT);
164 #endif
165     buf[strlen(buf) - 1] = ')';
166
167     return (buf);
168 }
169
170 /* Copied from ../kevent.c kevent_dump() and improved */
171 const char *
172 kevent_to_str(struct kevent *kev)
173 {
174     char buf[512];
175
176     snprintf(&buf[0], sizeof(buf), 
177             "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]",
178             (u_int) kev->ident,
179             kev->filter,
180             kevent_flags_dump(kev),
181             kevent_fflags_dump(kev),
182             (int) kev->data,
183             kev->udata);
184
185     return (strdup(buf));
186 }
187
188 void
189 kevent_add(int kqfd, struct kevent *kev, 
190         uintptr_t ident,
191         short     filter,
192         u_short   flags,
193         u_int     fflags,
194         intptr_t  data,
195         void      *udata)
196 {
197     EV_SET(kev, ident, filter, flags, fflags, data, NULL);    
198     if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) {
199         printf("Unable to add the following kevent:\n%s\n",
200                 kevent_to_str(kev));
201         err(1, "kevent(): %s", strerror(errno));
202     }
203 }
204
205 void
206 kevent_cmp(struct kevent *k1, struct kevent *k2)
207 {
208 /* XXX-
209    Workaround for inconsistent implementation of kevent(2) 
210  */
211 #ifdef __FreeBSD__
212     if (k1->flags & EV_ADD)
213         k2->flags |= EV_ADD;
214 #endif
215     if (memcmp(k1, k2, sizeof(*k1)) != 0) {
216         printf("kevent_cmp: mismatch:\n  %s !=\n  %s\n", 
217               kevent_to_str(k1), kevent_to_str(k2));
218         abort();
219     }
220 }
221
222 void
223 test_begin(const char *func)
224 {
225     if (cur_test_id)
226         free(cur_test_id);
227     cur_test_id = strdup(func);
228     if (!cur_test_id)
229         err(1, "strdup failed");
230
231     printf("\n\nTest %d: %s\n", testnum++, func);
232 }
233
234 void
235 success(void)
236 {
237     printf("%-70s %s\n", cur_test_id, "passed");
238     free(cur_test_id);
239     cur_test_id = NULL;
240 }
241
242 void
243 test_kqueue(void)
244 {
245     test_begin("kqueue()");
246     if ((kqfd = kqueue()) < 0)
247         err(1, "kqueue()");
248     test_no_kevents();
249     success();
250 }
251
252 void
253 test_kqueue_close(void)
254 {
255     test_begin("close(kq)");
256     if (close(kqfd) < 0)
257         err(1, "close()");
258     success();
259 }
260
261 int 
262 main(int argc, char **argv)
263 {
264     int test_proc = 1;
265     int test_socket = 1;
266     int test_signal = 1;
267     int test_vnode = 1;
268     int test_timer = 1;
269 #ifdef __FreeBSD__
270     int test_user = 1;
271 #else
272     /* XXX-FIXME temporary */
273     int test_user = 0;
274 #endif
275
276     while (argc) {
277         if (strcmp(argv[0], "--no-proc") == 0)
278             test_proc = 0;
279         if (strcmp(argv[0], "--no-socket") == 0)
280             test_socket = 0;
281         if (strcmp(argv[0], "--no-timer") == 0)
282             test_timer = 0;
283         if (strcmp(argv[0], "--no-signal") == 0)
284             test_signal = 0;
285         if (strcmp(argv[0], "--no-vnode") == 0)
286             test_vnode = 0;
287         if (strcmp(argv[0], "--no-user") == 0)
288             test_user = 0;
289         argv++;
290         argc--;
291     }
292
293     /*
294      * Some tests fork.  If output is fully buffered,
295      * the children inherit some buffered data and flush
296      * it when they exit, causing some data to be printed twice.
297      * Use line buffering to avoid this problem.
298      */
299     setlinebuf(stdout);
300     setlinebuf(stderr);
301
302     test_kqueue();
303     test_kqueue_close();
304
305     if (test_socket) 
306         test_evfilt_read();
307     if (test_signal) 
308         test_evfilt_signal();
309     if (test_vnode) 
310         test_evfilt_vnode();
311 #if HAVE_EVFILT_USER
312     if (test_user) 
313         test_evfilt_user();
314 #endif
315     if (test_timer) 
316         test_evfilt_timer();
317     if (test_proc) 
318         test_evfilt_proc();
319
320     printf("\n---\n"
321             "+OK All %d tests completed.\n", testnum - 1);
322     return (0);
323 }