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