1200483Srwatson/* 2200483Srwatson * Copyright (c) 2009 Mark Heily <mark@heily.com> 3200483Srwatson * 4200483Srwatson * Permission to use, copy, modify, and distribute this software for any 5200483Srwatson * purpose with or without fee is hereby granted, provided that the above 6200483Srwatson * copyright notice and this permission notice appear in all copies. 7200483Srwatson * 8200483Srwatson * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9200483Srwatson * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10200483Srwatson * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11200483Srwatson * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12200483Srwatson * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13200483Srwatson * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14200483Srwatson * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15200483Srwatson * 16200483Srwatson * $FreeBSD: stable/10/tests/sys/kqueue/libkqueue/main.c 313507 2017-02-10 02:29:09Z ngie $ 17200483Srwatson */ 18200483Srwatson 19200483Srwatson#include <sys/types.h> 20200483Srwatson 21223845Sjonathan#include "config.h" 22200483Srwatson#include "common.h" 23200483Srwatson 24200483Srwatsonint testnum = 1; 25200483Srwatsonchar *cur_test_id = NULL; 26200483Srwatsonint kqfd; 27200483Srwatson 28200483Srwatsonextern void test_evfilt_read(); 29200483Srwatsonextern void test_evfilt_signal(); 30200483Srwatsonextern void test_evfilt_vnode(); 31200483Srwatsonextern void test_evfilt_timer(); 32200483Srwatsonextern void test_evfilt_proc(); 33200483Srwatson#if HAVE_EVFILT_USER 34200483Srwatsonextern void test_evfilt_user(); 35200483Srwatson#endif 36200483Srwatson 37200483Srwatson/* Checks if any events are pending, which is an error. */ 38200483Srwatsonvoid 39200483Srwatsontest_no_kevents(void) 40200483Srwatson{ 41200483Srwatson int nfds; 42200483Srwatson struct timespec timeo; 43200483Srwatson struct kevent kev; 44200483Srwatson 45200483Srwatson puts("confirming that there are no events pending"); 46200483Srwatson memset(&timeo, 0, sizeof(timeo)); 47200483Srwatson nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); 48200483Srwatson if (nfds != 0) { 49200483Srwatson puts("\nUnexpected event:"); 50200483Srwatson puts(kevent_to_str(&kev)); 51200483Srwatson errx(1, "%d event(s) pending, but none expected:", nfds); 52200483Srwatson } 53200483Srwatson} 54200483Srwatson 55200483Srwatson/* Retrieve a single kevent */ 56200483Srwatsonstruct kevent * 57200483Srwatsonkevent_get(int kqfd) 58200483Srwatson{ 59200483Srwatson int nfds; 60200483Srwatson struct kevent *kev; 61200483Srwatson 62200483Srwatson if ((kev = calloc(1, sizeof(*kev))) == NULL) 63200483Srwatson err(1, "out of memory"); 64200483Srwatson 65200483Srwatson nfds = kevent(kqfd, NULL, 0, kev, 1, NULL); 66200483Srwatson if (nfds < 1) 67200483Srwatson err(1, "kevent(2)"); 68200483Srwatson 69200483Srwatson return (kev); 70200483Srwatson} 71200483Srwatson 72295012Svangyzen/* Retrieve a single kevent, specifying a maximum time to wait for it. */ 73295012Svangyzenstruct kevent * 74295012Svangyzenkevent_get_timeout(int kqfd, int seconds) 75295012Svangyzen{ 76295012Svangyzen int nfds; 77295012Svangyzen struct kevent *kev; 78295012Svangyzen struct timespec timeout = {seconds, 0}; 79295012Svangyzen 80295012Svangyzen if ((kev = calloc(1, sizeof(*kev))) == NULL) 81295012Svangyzen err(1, "out of memory"); 82295012Svangyzen 83295012Svangyzen nfds = kevent(kqfd, NULL, 0, kev, 1, &timeout); 84295012Svangyzen if (nfds < 0) { 85295012Svangyzen err(1, "kevent(2)"); 86295012Svangyzen } else if (nfds == 0) { 87295012Svangyzen free(kev); 88295012Svangyzen kev = NULL; 89295012Svangyzen } 90295012Svangyzen 91295012Svangyzen return (kev); 92295012Svangyzen} 93295012Svangyzen 94200483Srwatsonchar * 95200483Srwatsonkevent_fflags_dump(struct kevent *kev) 96200483Srwatson{ 97200483Srwatson char *buf; 98200483Srwatson 99200483Srwatson#define KEVFFL_DUMP(attrib) \ 100200483Srwatson if (kev->fflags & attrib) \ 101200483Srwatson strncat(buf, #attrib" ", 64); 102200483Srwatson 103200483Srwatson if ((buf = calloc(1, 1024)) == NULL) 104200483Srwatson abort(); 105200483Srwatson 106200483Srwatson /* Not every filter has meaningful fflags */ 107295012Svangyzen if (kev->filter == EVFILT_PROC) { 108295012Svangyzen snprintf(buf, 1024, "fflags = %x (", kev->fflags); 109295012Svangyzen KEVFFL_DUMP(NOTE_EXIT); 110295012Svangyzen KEVFFL_DUMP(NOTE_FORK); 111295012Svangyzen KEVFFL_DUMP(NOTE_EXEC); 112295012Svangyzen KEVFFL_DUMP(NOTE_CHILD); 113295012Svangyzen KEVFFL_DUMP(NOTE_TRACKERR); 114295012Svangyzen KEVFFL_DUMP(NOTE_TRACK); 115295012Svangyzen buf[strlen(buf) - 1] = ')'; 116295012Svangyzen } else if (kev->filter == EVFILT_VNODE) { 117295012Svangyzen snprintf(buf, 1024, "fflags = %x (", kev->fflags); 118295012Svangyzen KEVFFL_DUMP(NOTE_DELETE); 119295012Svangyzen KEVFFL_DUMP(NOTE_WRITE); 120295012Svangyzen KEVFFL_DUMP(NOTE_EXTEND); 121200483Srwatson#if HAVE_NOTE_TRUNCATE 122295012Svangyzen KEVFFL_DUMP(NOTE_TRUNCATE); 123200483Srwatson#endif 124295012Svangyzen KEVFFL_DUMP(NOTE_ATTRIB); 125295012Svangyzen KEVFFL_DUMP(NOTE_LINK); 126295012Svangyzen KEVFFL_DUMP(NOTE_RENAME); 127200483Srwatson#if HAVE_NOTE_REVOKE 128295012Svangyzen KEVFFL_DUMP(NOTE_REVOKE); 129200483Srwatson#endif 130295012Svangyzen buf[strlen(buf) - 1] = ')'; 131295012Svangyzen } else { 132295012Svangyzen snprintf(buf, 1024, "fflags = %x", kev->fflags); 133295012Svangyzen } 134200483Srwatson 135200483Srwatson return (buf); 136200483Srwatson} 137200483Srwatson 138200483Srwatsonchar * 139200483Srwatsonkevent_flags_dump(struct kevent *kev) 140200483Srwatson{ 141200483Srwatson char *buf; 142200483Srwatson 143200483Srwatson#define KEVFL_DUMP(attrib) \ 144200483Srwatson if (kev->flags & attrib) \ 145200483Srwatson strncat(buf, #attrib" ", 64); 146200483Srwatson 147200483Srwatson if ((buf = calloc(1, 1024)) == NULL) 148200483Srwatson abort(); 149200483Srwatson 150200483Srwatson snprintf(buf, 1024, "flags = %d (", kev->flags); 151200483Srwatson KEVFL_DUMP(EV_ADD); 152200483Srwatson KEVFL_DUMP(EV_ENABLE); 153200483Srwatson KEVFL_DUMP(EV_DISABLE); 154200483Srwatson KEVFL_DUMP(EV_DELETE); 155200483Srwatson KEVFL_DUMP(EV_ONESHOT); 156200483Srwatson KEVFL_DUMP(EV_CLEAR); 157200483Srwatson KEVFL_DUMP(EV_EOF); 158200483Srwatson KEVFL_DUMP(EV_ERROR); 159200483Srwatson#if HAVE_EV_DISPATCH 160200483Srwatson KEVFL_DUMP(EV_DISPATCH); 161200483Srwatson#endif 162200483Srwatson#if HAVE_EV_RECEIPT 163200483Srwatson KEVFL_DUMP(EV_RECEIPT); 164200483Srwatson#endif 165200483Srwatson buf[strlen(buf) - 1] = ')'; 166200483Srwatson 167200483Srwatson return (buf); 168200483Srwatson} 169200483Srwatson 170200483Srwatson/* Copied from ../kevent.c kevent_dump() and improved */ 171200483Srwatsonconst char * 172200483Srwatsonkevent_to_str(struct kevent *kev) 173200483Srwatson{ 174200483Srwatson char buf[512]; 175200483Srwatson 176200483Srwatson snprintf(&buf[0], sizeof(buf), 177200483Srwatson "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]", 178200483Srwatson (u_int) kev->ident, 179200483Srwatson kev->filter, 180200483Srwatson kevent_flags_dump(kev), 181200483Srwatson kevent_fflags_dump(kev), 182200483Srwatson (int) kev->data, 183200483Srwatson kev->udata); 184200483Srwatson 185200483Srwatson return (strdup(buf)); 186200483Srwatson} 187200483Srwatson 188200483Srwatsonvoid 189200483Srwatsonkevent_add(int kqfd, struct kevent *kev, 190200483Srwatson uintptr_t ident, 191200483Srwatson short filter, 192200483Srwatson u_short flags, 193200483Srwatson u_int fflags, 194200483Srwatson intptr_t data, 195200483Srwatson void *udata) 196200483Srwatson{ 197200483Srwatson EV_SET(kev, ident, filter, flags, fflags, data, NULL); 198200483Srwatson if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { 199200483Srwatson printf("Unable to add the following kevent:\n%s\n", 200200483Srwatson kevent_to_str(kev)); 201200483Srwatson err(1, "kevent(): %s", strerror(errno)); 202200483Srwatson } 203200483Srwatson} 204200483Srwatson 205200483Srwatsonvoid 206200483Srwatsonkevent_cmp(struct kevent *k1, struct kevent *k2) 207200483Srwatson{ 208200483Srwatson/* XXX- 209200483Srwatson Workaround for inconsistent implementation of kevent(2) 210200483Srwatson */ 211200483Srwatson#ifdef __FreeBSD__ 212200483Srwatson if (k1->flags & EV_ADD) 213200483Srwatson k2->flags |= EV_ADD; 214200483Srwatson#endif 215200483Srwatson if (memcmp(k1, k2, sizeof(*k1)) != 0) { 216200483Srwatson printf("kevent_cmp: mismatch:\n %s !=\n %s\n", 217200483Srwatson kevent_to_str(k1), kevent_to_str(k2)); 218200483Srwatson abort(); 219200483Srwatson } 220200483Srwatson} 221200483Srwatson 222200483Srwatsonvoid 223200483Srwatsontest_begin(const char *func) 224200483Srwatson{ 225200483Srwatson if (cur_test_id) 226200483Srwatson free(cur_test_id); 227200483Srwatson cur_test_id = strdup(func); 228200483Srwatson if (!cur_test_id) 229200483Srwatson err(1, "strdup failed"); 230200483Srwatson 231200483Srwatson printf("\n\nTest %d: %s\n", testnum++, func); 232200483Srwatson} 233200483Srwatson 234200483Srwatsonvoid 235200483Srwatsonsuccess(void) 236200483Srwatson{ 237200483Srwatson printf("%-70s %s\n", cur_test_id, "passed"); 238200483Srwatson free(cur_test_id); 239200483Srwatson cur_test_id = NULL; 240200483Srwatson} 241200483Srwatson 242200483Srwatsonvoid 243200483Srwatsontest_kqueue(void) 244200483Srwatson{ 245200483Srwatson test_begin("kqueue()"); 246200483Srwatson if ((kqfd = kqueue()) < 0) 247200483Srwatson err(1, "kqueue()"); 248200483Srwatson test_no_kevents(); 249200483Srwatson success(); 250200483Srwatson} 251200483Srwatson 252200483Srwatsonvoid 253200483Srwatsontest_kqueue_close(void) 254200483Srwatson{ 255200483Srwatson test_begin("close(kq)"); 256200483Srwatson if (close(kqfd) < 0) 257200483Srwatson err(1, "close()"); 258200483Srwatson success(); 259200483Srwatson} 260200483Srwatson 261200483Srwatsonint 262200483Srwatsonmain(int argc, char **argv) 263200483Srwatson{ 264223845Sjonathan int test_proc = 1; 265200483Srwatson int test_socket = 1; 266200483Srwatson int test_signal = 1; 267200483Srwatson int test_vnode = 1; 268200483Srwatson int test_timer = 1; 269200573Srwatson#ifdef __FreeBSD__ 270200483Srwatson int test_user = 1; 271200573Srwatson#else 272200573Srwatson /* XXX-FIXME temporary */ 273200573Srwatson int test_user = 0; 274200573Srwatson#endif 275200483Srwatson 276200483Srwatson while (argc) { 277200483Srwatson if (strcmp(argv[0], "--no-proc") == 0) 278200483Srwatson test_proc = 0; 279200483Srwatson if (strcmp(argv[0], "--no-socket") == 0) 280200483Srwatson test_socket = 0; 281200483Srwatson if (strcmp(argv[0], "--no-timer") == 0) 282200483Srwatson test_timer = 0; 283200483Srwatson if (strcmp(argv[0], "--no-signal") == 0) 284200483Srwatson test_signal = 0; 285200483Srwatson if (strcmp(argv[0], "--no-vnode") == 0) 286200483Srwatson test_vnode = 0; 287200483Srwatson if (strcmp(argv[0], "--no-user") == 0) 288200483Srwatson test_user = 0; 289200483Srwatson argv++; 290200483Srwatson argc--; 291200483Srwatson } 292200483Srwatson 293295012Svangyzen /* 294295012Svangyzen * Some tests fork. If output is fully buffered, 295295012Svangyzen * the children inherit some buffered data and flush 296295012Svangyzen * it when they exit, causing some data to be printed twice. 297295012Svangyzen * Use line buffering to avoid this problem. 298295012Svangyzen */ 299295012Svangyzen setlinebuf(stdout); 300295012Svangyzen setlinebuf(stderr); 301295012Svangyzen 302200483Srwatson test_kqueue(); 303200483Srwatson test_kqueue_close(); 304200483Srwatson 305200483Srwatson if (test_socket) 306200483Srwatson test_evfilt_read(); 307200483Srwatson if (test_signal) 308200483Srwatson test_evfilt_signal(); 309200483Srwatson if (test_vnode) 310200483Srwatson test_evfilt_vnode(); 311200483Srwatson#if HAVE_EVFILT_USER 312200483Srwatson if (test_user) 313200483Srwatson test_evfilt_user(); 314200483Srwatson#endif 315200483Srwatson if (test_timer) 316200483Srwatson test_evfilt_timer(); 317200483Srwatson if (test_proc) 318200483Srwatson test_evfilt_proc(); 319200483Srwatson 320200483Srwatson printf("\n---\n" 321200483Srwatson "+OK All %d tests completed.\n", testnum - 1); 322200483Srwatson return (0); 323200483Srwatson} 324