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_PROCDESC) { 117 snprintf(buf, 1024, "fflags = %x (", kev->fflags); 118 KEVFFL_DUMP(NOTE_EXIT); 119 KEVFFL_DUMP(NOTE_FORK); 120 KEVFFL_DUMP(NOTE_EXEC); 121 buf[strlen(buf) - 1] = ')'; 122 } else if (kev->filter == EVFILT_VNODE) { 123 snprintf(buf, 1024, "fflags = %x (", kev->fflags); 124 KEVFFL_DUMP(NOTE_DELETE); 125 KEVFFL_DUMP(NOTE_WRITE); 126 KEVFFL_DUMP(NOTE_EXTEND); 127 #if HAVE_NOTE_TRUNCATE 128 KEVFFL_DUMP(NOTE_TRUNCATE); 129 #endif 130 KEVFFL_DUMP(NOTE_ATTRIB); 131 KEVFFL_DUMP(NOTE_LINK); 132 KEVFFL_DUMP(NOTE_RENAME); 133 #if HAVE_NOTE_REVOKE 134 KEVFFL_DUMP(NOTE_REVOKE); 135 #endif 136 buf[strlen(buf) - 1] = ')'; 137 } else { 138 snprintf(buf, 1024, "fflags = %x", kev->fflags); 139 } 140 141 return (buf); 142 } 143 144 char * 145 kevent_flags_dump(struct kevent *kev) 146 { 147 char *buf; 148 149 #define KEVFL_DUMP(attrib) \ 150 if (kev->flags & attrib) \ 151 strncat(buf, #attrib" ", 64); 152 153 if ((buf = calloc(1, 1024)) == NULL) 154 abort(); 155 156 snprintf(buf, 1024, "flags = %d (", kev->flags); 157 KEVFL_DUMP(EV_ADD); 158 KEVFL_DUMP(EV_ENABLE); 159 KEVFL_DUMP(EV_DISABLE); 160 KEVFL_DUMP(EV_DELETE); 161 KEVFL_DUMP(EV_ONESHOT); 162 KEVFL_DUMP(EV_CLEAR); 163 KEVFL_DUMP(EV_EOF); 164 KEVFL_DUMP(EV_ERROR); 165 #if HAVE_EV_DISPATCH 166 KEVFL_DUMP(EV_DISPATCH); 167 #endif 168 #if HAVE_EV_RECEIPT 169 KEVFL_DUMP(EV_RECEIPT); 170 #endif 171 buf[strlen(buf) - 1] = ')'; 172 173 return (buf); 174 } 175 176 /* Copied from ../kevent.c kevent_dump() and improved */ 177 const char * 178 kevent_to_str(struct kevent *kev) 179 { 180 char buf[512]; 181 182 snprintf(&buf[0], sizeof(buf), 183 "[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, " 184 "ext=[%jx %jx %jx %jx]", 185 (uintmax_t) kev->ident, 186 kev->filter, 187 kevent_flags_dump(kev), 188 kevent_fflags_dump(kev), 189 (uintmax_t)kev->data, 190 kev->udata, 191 (uintmax_t)kev->ext[0], 192 (uintmax_t)kev->ext[1], 193 (uintmax_t)kev->ext[2], 194 (uintmax_t)kev->ext[3]); 195 196 return (strdup(buf)); 197 } 198 199 void 200 kevent_add(int kqfd, struct kevent *kev, 201 uintptr_t ident, 202 short filter, 203 u_short flags, 204 u_int fflags, 205 intptr_t data, 206 void *udata) 207 { 208 EV_SET(kev, ident, filter, flags, fflags, data, NULL); 209 if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { 210 printf("Unable to add the following kevent:\n%s\n", 211 kevent_to_str(kev)); 212 err(1, "kevent(): %s", strerror(errno)); 213 } 214 } 215 216 void 217 kevent_cmp(struct kevent *k1, struct kevent *k2) 218 { 219 /* XXX- 220 Workaround for inconsistent implementation of kevent(2) 221 */ 222 #ifdef __FreeBSD__ 223 if (k1->flags & EV_ADD) 224 k2->flags |= EV_ADD; 225 #endif 226 if (k1->ident != k2->ident || k1->filter != k2->filter || 227 k1->flags != k2->flags || k1->fflags != k2->fflags || 228 k1->data != k2->data || k1->udata != k2->udata || 229 k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] || 230 k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) { 231 printf("kevent_cmp: mismatch:\n %s !=\n %s\n", 232 kevent_to_str(k1), kevent_to_str(k2)); 233 abort(); 234 } 235 } 236 237 void 238 test_begin(const char *func) 239 { 240 if (cur_test_id) 241 free(cur_test_id); 242 cur_test_id = strdup(func); 243 if (!cur_test_id) 244 err(1, "strdup failed"); 245 246 printf("\n\nTest %d: %s\n", testnum++, func); 247 } 248 249 void 250 success(void) 251 { 252 printf("%-70s %s\n", cur_test_id, "passed"); 253 free(cur_test_id); 254 cur_test_id = NULL; 255 } 256 257 void 258 test_kqueue(void) 259 { 260 test_begin("kqueue()"); 261 if ((kqfd = kqueue()) < 0) 262 err(1, "kqueue()"); 263 test_no_kevents(); 264 success(); 265 } 266 267 void 268 test_kqueue_close(void) 269 { 270 test_begin("close(kq)"); 271 if (close(kqfd) < 0) 272 err(1, "close()"); 273 success(); 274 } 275 276 int 277 main(int argc, char **argv) 278 { 279 int test_proc = 1; 280 int test_socket = 1; 281 int test_signal = 1; 282 int test_vnode = 1; 283 int test_timer = 1; 284 #ifdef __FreeBSD__ 285 int test_user = 1; 286 #else 287 /* XXX-FIXME temporary */ 288 int test_user = 0; 289 #endif 290 291 while (argc) { 292 if (strcmp(argv[0], "--no-proc") == 0) 293 test_proc = 0; 294 if (strcmp(argv[0], "--no-socket") == 0) 295 test_socket = 0; 296 if (strcmp(argv[0], "--no-timer") == 0) 297 test_timer = 0; 298 if (strcmp(argv[0], "--no-signal") == 0) 299 test_signal = 0; 300 if (strcmp(argv[0], "--no-vnode") == 0) 301 test_vnode = 0; 302 if (strcmp(argv[0], "--no-user") == 0) 303 test_user = 0; 304 argv++; 305 argc--; 306 } 307 308 /* 309 * Some tests fork. If output is fully buffered, 310 * the children inherit some buffered data and flush 311 * it when they exit, causing some data to be printed twice. 312 * Use line buffering to avoid this problem. 313 */ 314 setlinebuf(stdout); 315 setlinebuf(stderr); 316 317 test_kqueue(); 318 test_kqueue_close(); 319 320 if (test_socket) 321 test_evfilt_read(); 322 if (test_signal) 323 test_evfilt_signal(); 324 if (test_vnode) 325 test_evfilt_vnode(); 326 #if HAVE_EVFILT_USER 327 if (test_user) 328 test_evfilt_user(); 329 #endif 330 if (test_timer) 331 test_evfilt_timer(); 332 if (test_proc) 333 test_evfilt_proc(); 334 335 printf("\n---\n" 336 "+OK All %d tests completed.\n", testnum - 1); 337 return (0); 338 } 339