main.c revision 313507
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: stable/10/tests/sys/kqueue/libkqueue/main.c 313507 2017-02-10 02:29:09Z ngie $
17 */
18
19#include <sys/types.h>
20
21#include "config.h"
22#include "common.h"
23
24int testnum = 1;
25char *cur_test_id = NULL;
26int kqfd;
27
28extern void test_evfilt_read();
29extern void test_evfilt_signal();
30extern void test_evfilt_vnode();
31extern void test_evfilt_timer();
32extern void test_evfilt_proc();
33#if HAVE_EVFILT_USER
34extern void test_evfilt_user();
35#endif
36
37/* Checks if any events are pending, which is an error. */
38void
39test_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 */
56struct kevent *
57kevent_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. */
73struct kevent *
74kevent_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
94char *
95kevent_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
138char *
139kevent_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 */
171const char *
172kevent_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
188void
189kevent_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
205void
206kevent_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
222void
223test_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
234void
235success(void)
236{
237    printf("%-70s %s\n", cur_test_id, "passed");
238    free(cur_test_id);
239    cur_test_id = NULL;
240}
241
242void
243test_kqueue(void)
244{
245    test_begin("kqueue()");
246    if ((kqfd = kqueue()) < 0)
247        err(1, "kqueue()");
248    test_no_kevents();
249    success();
250}
251
252void
253test_kqueue_close(void)
254{
255    test_begin("close(kq)");
256    if (close(kqfd) < 0)
257        err(1, "close()");
258    success();
259}
260
261int
262main(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}
324