Index: head/tests/sys/kqueue/libkqueue/Makefile =================================================================== --- head/tests/sys/kqueue/libkqueue/Makefile (revision 360072) +++ head/tests/sys/kqueue/libkqueue/Makefile (revision 360073) @@ -1,21 +1,20 @@ # $FreeBSD$ TESTSDIR= ${TESTSBASE}/sys/kqueue/libkqueue BINDIR= ${TESTSDIR} # libkqueue and test suite by Mark Heily TAP_TESTS_SH= kqueue_test PROGS= kqtest SRCS.kqtest= \ main.c \ read.c \ timer.c \ vnode.c \ proc.c \ signal.c \ user.c -WARNS?= 2 .include Index: head/tests/sys/kqueue/libkqueue/common.h =================================================================== --- head/tests/sys/kqueue/libkqueue/common.h (revision 360072) +++ head/tests/sys/kqueue/libkqueue/common.h (revision 360073) @@ -1,80 +1,88 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #ifndef _COMMON_H #define _COMMON_H #include "config.h" /* Needed for HAVE_* defines */ #if HAVE_ERR_H # include #else # define err(rc,msg,...) do { perror(msg); exit(rc); } while (0) # define errx(rc,msg,...) do { puts(msg); exit(rc); } while (0) #endif #include #include #include #include #include #include #include #include #include #include #include -extern char *cur_test_id; extern int vnode_fd; extern int kqfd; extern char * kevent_to_str(struct kevent *); struct kevent * kevent_get(int); struct kevent * kevent_get_timeout(int, int); void kevent_cmp(struct kevent *, struct kevent *); void kevent_add(int kqfd, struct kevent *kev, uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata); /* DEPRECATED: */ #define KEV_CMP(kev,_ident,_filter,_flags) do { \ if (kev.ident != (_ident) || \ kev.filter != (_filter) || \ kev.flags != (_flags)) \ err(1, "kevent mismatch: got [%d,%d,%d] but expecting [%d,%d,%d]", \ (int)_ident, (int)_filter, (int)_flags,\ (int)kev.ident, kev.filter, kev.flags);\ } while (0); /* Checks if any events are pending, which is an error. */ extern void test_no_kevents(void); extern void test_no_kevents_quietly(void); extern void test_begin(const char *); extern void success(void); + +extern void test_evfilt_read(void); +extern void test_evfilt_signal(void); +extern void test_evfilt_vnode(void); +extern void test_evfilt_timer(void); +extern void test_evfilt_proc(void); +#if HAVE_EVFILT_USER +extern void test_evfilt_user(void); +#endif #endif /* _COMMON_H */ Index: head/tests/sys/kqueue/libkqueue/main.c =================================================================== --- head/tests/sys/kqueue/libkqueue/main.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/main.c (revision 360073) @@ -1,379 +1,370 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include #include "config.h" #include "common.h" -int testnum = 1; -char *cur_test_id = NULL; int kqfd; +static char *cur_test_id = NULL; +static int testnum = 1; -extern void test_evfilt_read(); -extern void test_evfilt_signal(); -extern void test_evfilt_vnode(); -extern void test_evfilt_timer(); -extern void test_evfilt_proc(); -#if HAVE_EVFILT_USER -extern void test_evfilt_user(); -#endif - /* Checks if any events are pending, which is an error. */ -void +void test_no_kevents(void) { int nfds; struct timespec timeo; struct kevent kev; char *kev_str; puts("confirming that there are no events pending"); memset(&timeo, 0, sizeof(timeo)); nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); if (nfds != 0) { puts("\nUnexpected event:"); kev_str = kevent_to_str(&kev); puts(kev_str); free(kev_str); errx(1, "%d event(s) pending, but none expected:", nfds); } } /* Checks if any events are pending, which is an error. Do not print * out anything unless events are found. */ -void +void test_no_kevents_quietly(void) { int nfds; struct timespec timeo; struct kevent kev; char *kev_str; memset(&timeo, 0, sizeof(timeo)); nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); if (nfds != 0) { puts("\nUnexpected event:"); kev_str = kevent_to_str(&kev); puts(kev_str); free(kev_str); errx(1, "%d event(s) pending, but none expected:", nfds); } } /* Retrieve a single kevent */ struct kevent * -kevent_get(int kqfd) +kevent_get(int fd) { int nfds; struct kevent *kev; if ((kev = calloc(1, sizeof(*kev))) == NULL) err(1, "out of memory"); - nfds = kevent(kqfd, NULL, 0, kev, 1, NULL); + nfds = kevent(fd, NULL, 0, kev, 1, NULL); if (nfds < 1) err(1, "kevent(2)"); return (kev); } /* Retrieve a single kevent, specifying a maximum time to wait for it. */ struct kevent * -kevent_get_timeout(int kqfd, int seconds) +kevent_get_timeout(int fd, int seconds) { int nfds; struct kevent *kev; struct timespec timeout = {seconds, 0}; if ((kev = calloc(1, sizeof(*kev))) == NULL) err(1, "out of memory"); - nfds = kevent(kqfd, NULL, 0, kev, 1, &timeout); + nfds = kevent(fd, NULL, 0, kev, 1, &timeout); if (nfds < 0) { err(1, "kevent(2)"); } else if (nfds == 0) { free(kev); kev = NULL; } return (kev); } -char * +static char * kevent_fflags_dump(struct kevent *kev) { char *buf; #define KEVFFL_DUMP(attrib) \ if (kev->fflags & attrib) \ strncat(buf, #attrib" ", 64); if ((buf = calloc(1, 1024)) == NULL) abort(); /* Not every filter has meaningful fflags */ if (kev->filter == EVFILT_PROC) { snprintf(buf, 1024, "fflags = %x (", kev->fflags); KEVFFL_DUMP(NOTE_EXIT); KEVFFL_DUMP(NOTE_FORK); KEVFFL_DUMP(NOTE_EXEC); KEVFFL_DUMP(NOTE_CHILD); KEVFFL_DUMP(NOTE_TRACKERR); KEVFFL_DUMP(NOTE_TRACK); buf[strlen(buf) - 1] = ')'; } else if (kev->filter == EVFILT_PROCDESC) { snprintf(buf, 1024, "fflags = %x (", kev->fflags); KEVFFL_DUMP(NOTE_EXIT); KEVFFL_DUMP(NOTE_FORK); KEVFFL_DUMP(NOTE_EXEC); buf[strlen(buf) - 1] = ')'; } else if (kev->filter == EVFILT_VNODE) { snprintf(buf, 1024, "fflags = %x (", kev->fflags); KEVFFL_DUMP(NOTE_DELETE); KEVFFL_DUMP(NOTE_WRITE); KEVFFL_DUMP(NOTE_EXTEND); #if HAVE_NOTE_TRUNCATE KEVFFL_DUMP(NOTE_TRUNCATE); #endif KEVFFL_DUMP(NOTE_ATTRIB); KEVFFL_DUMP(NOTE_LINK); KEVFFL_DUMP(NOTE_RENAME); #if HAVE_NOTE_REVOKE KEVFFL_DUMP(NOTE_REVOKE); #endif buf[strlen(buf) - 1] = ')'; } else { snprintf(buf, 1024, "fflags = %x", kev->fflags); } return (buf); } -char * +static char * kevent_flags_dump(struct kevent *kev) { char *buf; #define KEVFL_DUMP(attrib) \ if (kev->flags & attrib) \ strncat(buf, #attrib" ", 64); if ((buf = calloc(1, 1024)) == NULL) abort(); snprintf(buf, 1024, "flags = %d (", kev->flags); KEVFL_DUMP(EV_ADD); KEVFL_DUMP(EV_ENABLE); KEVFL_DUMP(EV_DISABLE); KEVFL_DUMP(EV_DELETE); KEVFL_DUMP(EV_ONESHOT); KEVFL_DUMP(EV_CLEAR); KEVFL_DUMP(EV_EOF); KEVFL_DUMP(EV_ERROR); #if HAVE_EV_DISPATCH KEVFL_DUMP(EV_DISPATCH); #endif #if HAVE_EV_RECEIPT KEVFL_DUMP(EV_RECEIPT); #endif buf[strlen(buf) - 1] = ')'; return (buf); } /* Copied from ../kevent.c kevent_dump() and improved */ char * kevent_to_str(struct kevent *kev) { char buf[512]; char *flags_str = kevent_flags_dump(kev); char *fflags_str = kevent_fflags_dump(kev); snprintf(&buf[0], sizeof(buf), "[ident=%ju, filter=%d, %s, %s, data=%jd, udata=%p, " "ext=[%jx %jx %jx %jx]", (uintmax_t) kev->ident, kev->filter, flags_str, fflags_str, (uintmax_t)kev->data, kev->udata, (uintmax_t)kev->ext[0], (uintmax_t)kev->ext[1], (uintmax_t)kev->ext[2], (uintmax_t)kev->ext[3]); free(flags_str); free(fflags_str); return (strdup(buf)); } void -kevent_add(int kqfd, struct kevent *kev, +kevent_add(int fd, struct kevent *kev, uintptr_t ident, short filter, u_short flags, u_int fflags, intptr_t data, void *udata) { char *kev_str; - EV_SET(kev, ident, filter, flags, fflags, data, NULL); - if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { + EV_SET(kev, ident, filter, flags, fflags, data, udata); + if (kevent(fd, kev, 1, NULL, 0, NULL) < 0) { kev_str = kevent_to_str(kev); printf("Unable to add the following kevent:\n%s\n", kev_str); free(kev_str); err(1, "kevent(): %s", strerror(errno)); } } void kevent_cmp(struct kevent *k1, struct kevent *k2) { char *kev1_str; char *kev2_str; /* XXX- Workaround for inconsistent implementation of kevent(2) */ #ifdef __FreeBSD__ if (k1->flags & EV_ADD) k2->flags |= EV_ADD; #endif if (k1->ident != k2->ident || k1->filter != k2->filter || k1->flags != k2->flags || k1->fflags != k2->fflags || k1->data != k2->data || k1->udata != k2->udata || k1->ext[0] != k2->ext[0] || k1->ext[1] != k2->ext[1] || k1->ext[0] != k2->ext[2] || k1->ext[0] != k2->ext[3]) { kev1_str = kevent_to_str(k1); kev2_str = kevent_to_str(k2); printf("kevent_cmp: mismatch:\n %s !=\n %s\n", kev1_str, kev2_str); free(kev1_str); free(kev2_str); abort(); } } void test_begin(const char *func) { if (cur_test_id) free(cur_test_id); cur_test_id = strdup(func); if (!cur_test_id) err(1, "strdup failed"); printf("\n\nTest %d: %s\n", testnum++, func); } void success(void) { printf("%-70s %s\n", cur_test_id, "passed"); free(cur_test_id); cur_test_id = NULL; } -void +static void test_kqueue(void) { test_begin("kqueue()"); if ((kqfd = kqueue()) < 0) err(1, "kqueue()"); test_no_kevents(); success(); } -void +static void test_kqueue_close(void) { test_begin("close(kq)"); if (close(kqfd) < 0) err(1, "close()"); success(); } int main(int argc, char **argv) { int test_proc = 1; int test_socket = 1; int test_signal = 1; int test_vnode = 1; int test_timer = 1; #ifdef __FreeBSD__ int test_user = 1; #else /* XXX-FIXME temporary */ int test_user = 0; #endif while (argc) { if (strcmp(argv[0], "--no-proc") == 0) test_proc = 0; if (strcmp(argv[0], "--no-socket") == 0) test_socket = 0; if (strcmp(argv[0], "--no-timer") == 0) test_timer = 0; if (strcmp(argv[0], "--no-signal") == 0) test_signal = 0; if (strcmp(argv[0], "--no-vnode") == 0) test_vnode = 0; if (strcmp(argv[0], "--no-user") == 0) test_user = 0; argv++; argc--; } /* * Some tests fork. If output is fully buffered, * the children inherit some buffered data and flush * it when they exit, causing some data to be printed twice. * Use line buffering to avoid this problem. */ setlinebuf(stdout); setlinebuf(stderr); test_kqueue(); test_kqueue_close(); if (test_socket) test_evfilt_read(); if (test_signal) test_evfilt_signal(); if (test_vnode) test_evfilt_vnode(); #if HAVE_EVFILT_USER if (test_user) test_evfilt_user(); #endif if (test_timer) test_evfilt_timer(); if (test_proc) test_evfilt_proc(); printf("\n---\n" "+OK All %d tests completed.\n", testnum - 1); return (0); } Index: head/tests/sys/kqueue/libkqueue/proc.c =================================================================== --- head/tests/sys/kqueue/libkqueue/proc.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/proc.c (revision 360073) @@ -1,425 +1,425 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include #include #include "config.h" #include "common.h" static int sigusr1_caught = 0; static void -sig_handler(int signum) +sig_handler(__unused int signum) { sigusr1_caught = 1; } static void add_and_delete(void) { struct kevent kev; pid_t pid; /* Create a child that waits to be killed and then exits */ pid = fork(); if (pid == 0) { struct stat s; if (fstat(kqfd, &s) != -1) errx(1, "kqueue inherited across fork! (%s() at %s:%d)", __func__, __FILE__, __LINE__); pause(); exit(2); } printf(" -- child created (pid %d)\n", (int) pid); test_begin("kevent(EVFILT_PROC, EV_ADD)"); test_no_kevents(); kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL); test_no_kevents(); success(); test_begin("kevent(EVFILT_PROC, EV_DELETE)"); sleep(1); test_no_kevents(); kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_DELETE, 0, 0, NULL); if (kill(pid, SIGKILL) < 0) err(1, "kill"); sleep(1); test_no_kevents(); success(); } static void proc_track(int sleep_time) { char test_id[64]; struct kevent kev; pid_t pid; int pipe_fd[2]; ssize_t result; snprintf(test_id, sizeof(test_id), "kevent(EVFILT_PROC, NOTE_TRACK); sleep %d", sleep_time); test_begin(test_id); test_no_kevents(); if (pipe(pipe_fd)) { err(1, "pipe (parent) failed! (%s() at %s:%d)", __func__, __FILE__, __LINE__); } /* Create a child to track. */ pid = fork(); if (pid == 0) { /* Child */ pid_t grandchild = -1; /* * Give the parent a chance to start tracking us. */ result = read(pipe_fd[1], test_id, 1); if (result != 1) { err(1, "read from pipe in child failed! (ret %zd) (%s() at %s:%d)", result, __func__, __FILE__, __LINE__); } /* * Spawn a grandchild that will immediately exit. If the kernel has bug * 180385, the parent will see a kevent with both NOTE_CHILD and * NOTE_EXIT. If that bug is fixed, it will see two separate kevents * for those notes. Note that this triggers the conditions for * detecting the bug quite reliably on a 1 CPU system (or if the test * process is restricted to a single CPU), but may not trigger it on a * multi-CPU system. */ grandchild = fork(); if (grandchild == 0) { /* Grandchild */ if (sleep_time) sleep(sleep_time); exit(1); } else if (grandchild == -1) { /* Error */ err(1, "fork (grandchild) failed! (%s() at %s:%d)", __func__, __FILE__, __LINE__); } else { /* Child (Grandchild Parent) */ printf(" -- grandchild created (pid %d)\n", (int) grandchild); } if (sleep_time) sleep(sleep_time); exit(0); } else if (pid == -1) { /* Error */ err(1, "fork (child) failed! (%s() at %s:%d)", __func__, __FILE__, __LINE__); } printf(" -- child created (pid %d)\n", (int) pid); kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD | EV_ENABLE, NOTE_TRACK | NOTE_EXEC | NOTE_EXIT | NOTE_FORK, 0, NULL); printf(" -- tracking child (pid %d)\n", (int) pid); /* Now that we're tracking the child, tell it to proceed. */ result = write(pipe_fd[0], test_id, 1); if (result != 1) { err(1, "write to pipe in parent failed! (ret %zd) (%s() at %s:%d)", result, __func__, __FILE__, __LINE__); } /* * Several events should be received: * - NOTE_FORK (from child) * - NOTE_CHILD (from grandchild) * - NOTE_EXIT (from grandchild) * - NOTE_EXIT (from child) * * The NOTE_FORK and NOTE_EXIT from the child could be combined into a * single event, but the NOTE_CHILD and NOTE_EXIT from the grandchild must * not be combined. * * The loop continues until no events are received within a 5 second * period, at which point it is assumed that no more will be coming. The * loop is deliberately designed to attempt to get events even after all * the expected ones are received in case some spurious events are * generated as well as the expected ones. */ { int child_exit = 0; int child_fork = 0; int gchild_exit = 0; int gchild_note = 0; pid_t gchild_pid = -1; int done = 0; char *kev_str; while (!done) { int handled = 0; struct kevent *kevp; kevp = kevent_get_timeout(kqfd, 5); if (kevp == NULL) { done = 1; } else { kev_str = kevent_to_str(kevp); printf(" -- Received kevent: %s\n", kev_str); free(kev_str); if ((kevp->fflags & NOTE_CHILD) && (kevp->fflags & NOTE_EXIT)) { errx(1, "NOTE_CHILD and NOTE_EXIT in same kevent: %s", kevent_to_str(kevp)); } if (kevp->fflags & NOTE_CHILD) { if (kevp->data == pid) { if (!gchild_note) { ++gchild_note; gchild_pid = kevp->ident; ++handled; } else { errx(1, "Spurious NOTE_CHILD: %s", kevent_to_str(kevp)); } } } if (kevp->fflags & NOTE_EXIT) { - if ((kevp->ident == pid) && (!child_exit)) { + if ((kevp->ident == (uintptr_t)pid) && (!child_exit)) { ++child_exit; ++handled; - } else if ((kevp->ident == gchild_pid) && (!gchild_exit)) { + } else if ((kevp->ident == (uintptr_t)gchild_pid) && (!gchild_exit)) { ++gchild_exit; ++handled; } else { errx(1, "Spurious NOTE_EXIT: %s", kevent_to_str(kevp)); } } if (kevp->fflags & NOTE_FORK) { - if ((kevp->ident == pid) && (!child_fork)) { + if ((kevp->ident == (uintptr_t)pid) && (!child_fork)) { ++child_fork; ++handled; } else { errx(1, "Spurious NOTE_FORK: %s", kevent_to_str(kevp)); } } if (!handled) { errx(1, "Spurious kevent: %s", kevent_to_str(kevp)); } free(kevp); } } /* Make sure all expected events were received. */ if (child_exit && child_fork && gchild_exit && gchild_note) { printf(" -- Received all expected events.\n"); } else { errx(1, "Did not receive all expected events."); } } success(); } #ifdef TODO static void event_trigger(void) { struct kevent kev; pid_t pid; test_begin("kevent(EVFILT_PROC, wait)"); /* Create a child that waits to be killed and then exits */ pid = fork(); if (pid == 0) { pause(); printf(" -- child caught signal, exiting\n"); exit(2); } printf(" -- child created (pid %d)\n", (int) pid); test_no_kevents(); kevent_add(kqfd, &kev, pid, EVFILT_PROC, EV_ADD, 0, 0, NULL); /* Cause the child to exit, then retrieve the event */ printf(" -- killing process %d\n", (int) pid); if (kill(pid, SIGUSR1) < 0) err(1, "kill"); kevent_cmp(&kev, kevent_get(kqfd)); test_no_kevents(); success(); } -void +static void test_kevent_signal_disable(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGKILL) < 0) err(1, "kill"); test_no_kevents(); success(); } void test_kevent_signal_enable(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); kev.flags = EV_ADD | EV_CLEAR; #if LIBKQUEUE kev.data = 1; /* WORKAROUND */ #else kev.data = 2; // one extra time from test_kevent_signal_disable() #endif kevent_cmp(&kev, kevent_get(kqfd)); /* Delete the watch */ kev.flags = EV_DELETE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } void test_kevent_signal_del(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)"; struct kevent kev; test_begin(test_id); /* Delete the kevent */ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); test_no_kevents(); success(); } void test_kevent_signal_oneshot(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); kev.flags |= EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); /* Send another one and make sure we get no events */ if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); test_no_kevents(); success(); } #endif void -test_evfilt_proc() +test_evfilt_proc(void) { kqfd = kqueue(); signal(SIGUSR1, sig_handler); add_and_delete(); proc_track(0); /* Run without sleeping before children exit. */ proc_track(1); /* Sleep a bit in the children before exiting. */ #if TODO event_trigger(); #endif signal(SIGUSR1, SIG_DFL); #if TODO test_kevent_signal_add(); test_kevent_signal_del(); test_kevent_signal_get(); test_kevent_signal_disable(); test_kevent_signal_enable(); test_kevent_signal_oneshot(); #endif close(kqfd); } Index: head/tests/sys/kqueue/libkqueue/read.c =================================================================== --- head/tests/sys/kqueue/libkqueue/read.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/read.c (revision 360073) @@ -1,325 +1,325 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "common.h" -int sockfd[2]; +static int sockfd[2]; static void kevent_socket_drain(void) { char buf[1]; /* Drain the read buffer, then make sure there are no more events. */ puts("draining the read buffer"); if (read(sockfd[0], &buf[0], 1) < 1) err(1, "read(2)"); } static void kevent_socket_fill(void) { puts("filling the read buffer"); if (write(sockfd[1], ".", 1) < 1) err(1, "write(2)"); } -void +static void test_kevent_socket_add(void) { const char *test_id = "kevent(EVFILT_READ, EV_ADD)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_socket_get(void) { const char *test_id = "kevent(EVFILT_READ) wait"; struct kevent kev; test_begin(test_id); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kevent_socket_fill(); kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); kevent_socket_drain(); test_no_kevents(); kev.flags = EV_DELETE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_socket_clear(void) { const char *test_id = "kevent(EVFILT_READ, EV_CLEAR)"; struct kevent kev; test_begin(test_id); test_no_kevents(); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_CLEAR, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kevent_socket_fill(); kevent_socket_fill(); kev.data = 2; kevent_cmp(&kev, kevent_get(kqfd)); /* We filled twice, but drain once. Edge-triggered would not generate additional events. */ kevent_socket_drain(); test_no_kevents(); kevent_socket_drain(); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_socket_disable_and_enable(void) { const char *test_id = "kevent(EVFILT_READ, EV_DISABLE)"; struct kevent kev; test_begin(test_id); /* * Write to the socket before adding the event. This way we can verify that * enabling a triggered kevent causes the event to be returned immediately. */ kevent_socket_fill(); /* Add a disabled event. */ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISABLE, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); /* Re-enable the knote, then see if an event is generated */ kev.flags = EV_ENABLE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kev.flags = EV_ADD; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); kevent_socket_drain(); kev.flags = EV_DELETE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_socket_del(void) { const char *test_id = "kevent(EVFILT_READ, EV_DELETE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kevent_socket_fill(); test_no_kevents(); kevent_socket_drain(); success(); } -void +static void test_kevent_socket_oneshot(void) { const char *test_id = "kevent(EVFILT_READ, EV_ONESHOT)"; struct kevent kev; test_begin(test_id); /* Re-add the watch and make sure no events are pending */ puts("-- re-adding knote"); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); puts("-- getting one event"); kevent_socket_fill(); kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); puts("-- checking knote disabled"); test_no_kevents(); /* Try to delete the knote, it should already be deleted */ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) == 0) err(1, "%s", test_id); kevent_socket_drain(); success(); } #if HAVE_EV_DISPATCH -void +static void test_kevent_socket_dispatch(void) { const char *test_id = "kevent(EVFILT_READ, EV_DISPATCH)"; test_begin(test_id); struct kevent kev; /* Re-add the watch and make sure no events are pending */ puts("-- re-adding knote"); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_DISPATCH, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); /* The event will occur only once, even though EV_CLEAR is not specified. */ kevent_socket_fill(); kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); test_no_kevents(); /* Since the knote is disabled, the EV_DELETE operation succeeds. */ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kevent_socket_drain(); success(); } #endif /* HAVE_EV_DISPATCH */ #if BROKEN -void +static void test_kevent_socket_lowat(void) { const char *test_id = "kevent(EVFILT_READ, NOTE_LOWAT)"; struct kevent kev; test_begin(test_id); /* Re-add the watch and make sure no events are pending */ puts("-- re-adding knote, setting low watermark to 2 bytes"); EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD | EV_ONESHOT, NOTE_LOWAT, 2, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); puts("-- checking that one byte does not trigger an event.."); kevent_socket_fill(); test_no_kevents(); puts("-- checking that two bytes triggers an event.."); kevent_socket_fill(); if (kevent(kqfd, NULL, 0, &kev, 1, NULL) != 1) err(1, "%s", test_id); KEV_CMP(kev, sockfd[0], EVFILT_READ, 0); test_no_kevents(); kevent_socket_drain(); kevent_socket_drain(); success(); } #endif -void +static void test_kevent_socket_eof(void) { const char *test_id = "kevent(EVFILT_READ, EV_EOF)"; struct kevent kev; test_begin(test_id); /* Re-add the watch and make sure no events are pending */ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_ADD, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); if (close(sockfd[1]) < 0) err(1, "close(2)"); kev.flags |= EV_EOF; kevent_cmp(&kev, kevent_get(kqfd)); /* Delete the watch */ EV_SET(&kev, sockfd[0], EVFILT_READ, EV_DELETE, 0, 0, &sockfd[0]); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } void -test_evfilt_read() +test_evfilt_read(void) { /* Create a connected pair of full-duplex sockets for testing socket events */ if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockfd) < 0) abort(); kqfd = kqueue(); test_kevent_socket_add(); test_kevent_socket_del(); test_kevent_socket_get(); test_kevent_socket_disable_and_enable(); test_kevent_socket_oneshot(); test_kevent_socket_clear(); #if HAVE_EV_DISPATCH test_kevent_socket_dispatch(); #endif test_kevent_socket_eof(); close(kqfd); } Index: head/tests/sys/kqueue/libkqueue/signal.c =================================================================== --- head/tests/sys/kqueue/libkqueue/signal.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/signal.c (revision 360073) @@ -1,198 +1,198 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "common.h" -void +static void test_kevent_signal_add(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_ADD)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_signal_get(void) { const char *test_id = "kevent(EVFILT_SIGNAL, wait)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); kev.flags |= EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); success(); } -void +static void test_kevent_signal_disable(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_DISABLE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DISABLE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); test_no_kevents(); success(); } -void +static void test_kevent_signal_enable(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_ENABLE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ENABLE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); kev.flags = EV_ADD | EV_CLEAR; #if LIBKQUEUE kev.data = 1; /* WORKAROUND */ #else kev.data = 2; // one extra time from test_kevent_signal_disable() #endif kevent_cmp(&kev, kevent_get(kqfd)); /* Delete the watch */ kev.flags = EV_DELETE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_signal_del(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_DELETE)"; struct kevent kev; test_begin(test_id); /* Delete the kevent */ EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_DELETE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); test_no_kevents(); success(); } -void +static void test_kevent_signal_oneshot(void) { const char *test_id = "kevent(EVFILT_SIGNAL, EV_ONESHOT)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, SIGUSR1, EVFILT_SIGNAL, EV_ADD | EV_ONESHOT, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Block SIGUSR1, then send it to ourselves */ sigset_t mask; sigemptyset(&mask); sigaddset(&mask, SIGUSR1); if (sigprocmask(SIG_BLOCK, &mask, NULL) == -1) err(1, "sigprocmask"); if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); kev.flags |= EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); /* Send another one and make sure we get no events */ if (kill(getpid(), SIGUSR1) < 0) err(1, "kill"); test_no_kevents(); success(); } void -test_evfilt_signal() +test_evfilt_signal(void) { kqfd = kqueue(); test_kevent_signal_add(); test_kevent_signal_del(); test_kevent_signal_get(); test_kevent_signal_disable(); test_kevent_signal_enable(); test_kevent_signal_oneshot(); close(kqfd); } Index: head/tests/sys/kqueue/libkqueue/timer.c =================================================================== --- head/tests/sys/kqueue/libkqueue/timer.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/timer.c (revision 360073) @@ -1,528 +1,528 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "common.h" #include #define MILLION 1000000 #define THOUSAND 1000 #define SEC_TO_MS(t) ((t) * THOUSAND) /* Convert seconds to milliseconds. */ #define SEC_TO_US(t) ((t) * MILLION) /* Convert seconds to microseconds. */ #define MS_TO_US(t) ((t) * THOUSAND) /* Convert milliseconds to microseconds. */ #define US_TO_NS(t) ((t) * THOUSAND) /* Convert microseconds to nanoseconds. */ /* Get the current time with microsecond precision. Used for * sub-second timing to make some timer tests run faster. */ static long now(void) { struct timeval tv; gettimeofday(&tv, NULL); return SEC_TO_US(tv.tv_sec) + tv.tv_usec; } /* Sleep for a given number of milliseconds. The timeout is assumed to * be less than 1 second. */ -void +static void mssleep(int t) { struct timespec stime = { .tv_sec = 0, .tv_nsec = US_TO_NS(MS_TO_US(t)), }; nanosleep(&stime, NULL); } /* Sleep for a given number of microseconds. The timeout is assumed to * be less than 1 second. */ -void +static void ussleep(int t) { struct timespec stime = { .tv_sec = 0, .tv_nsec = US_TO_NS(t), }; nanosleep(&stime, NULL); } -void +static void test_kevent_timer_add(void) { const char *test_id = "kevent(EVFILT_TIMER, EV_ADD)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_timer_del(void) { const char *test_id = "kevent(EVFILT_TIMER, EV_DELETE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); success(); } -void +static void test_kevent_timer_get(void) { const char *test_id = "kevent(EVFILT_TIMER, wait)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, 1, EVFILT_TIMER, EV_ADD, 0, 1000, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kev.flags |= EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); EV_SET(&kev, 1, EVFILT_TIMER, EV_DELETE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } static void test_oneshot(void) { const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT)"; struct kevent kev; test_begin(test_id); test_no_kevents(); EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500,NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Retrieve the event */ kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); /* Check if the event occurs again */ sleep(3); test_no_kevents(); success(); } static void test_periodic(void) { const char *test_id = "kevent(EVFILT_TIMER, periodic)"; struct kevent kev; test_begin(test_id); test_no_kevents(); EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000,NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Retrieve the event */ kev.flags = EV_ADD | EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); /* Check if the event occurs again */ sleep(1); kevent_cmp(&kev, kevent_get(kqfd)); /* Delete the event */ kev.flags = EV_DELETE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } static void disable_and_enable(void) { const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)"; struct kevent kev; test_begin(test_id); test_no_kevents(); /* Add the watch and immediately disable it */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 2000,NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kev.flags = EV_DISABLE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); test_no_kevents(); /* Re-enable and check again */ kev.flags = EV_ENABLE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); success(); } static void test_abstime(void) { const char *test_id = "kevent(EVFILT_TIMER, EV_ONESHOT, NOTE_ABSTIME)"; struct kevent kev; long end, start, stop; const int timeout_sec = 3; test_begin(test_id); test_no_kevents(); start = now(); end = start + SEC_TO_US(timeout_sec); EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_ABSTIME | NOTE_USECONDS, end, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Retrieve the event */ kev.flags = EV_ADD | EV_ONESHOT; kev.data = 1; kev.fflags = 0; kevent_cmp(&kev, kevent_get(kqfd)); stop = now(); if (stop < end) err(1, "too early %jd %jd", (intmax_t)stop, (intmax_t)end); /* Check if the event occurs again */ sleep(3); test_no_kevents(); success(); } static void test_update(void) { const char *test_id = "kevent(EVFILT_TIMER (UPDATE), EV_ADD | EV_ONESHOT)"; struct kevent kev; long elapsed; long start; test_begin(test_id); test_no_kevents(); /* First set the timer to 1 second */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_USECONDS, SEC_TO_US(1), (void *)1); start = now(); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Now reduce the timer to 1 ms */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_USECONDS, MS_TO_US(1), (void *)2); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Wait for the event */ kev.flags |= EV_CLEAR; kev.fflags &= ~NOTE_USECONDS; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); elapsed = now() - start; /* Check that the timer expired after at least 1 ms, but less than * 1 second. This check is to make sure that the original 1 second * timeout was not used. */ printf("timer expired after %ld us\n", elapsed); if (elapsed < MS_TO_US(1)) errx(1, "early timer expiration: %ld us", elapsed); if (elapsed > SEC_TO_US(1)) errx(1, "late timer expiration: %ld us", elapsed); success(); } static void test_update_equal(void) { const char *test_id = "kevent(EVFILT_TIMER (UPDATE=), EV_ADD | EV_ONESHOT)"; struct kevent kev; long elapsed; long start; test_begin(test_id); test_no_kevents(); /* First set the timer to 1 ms */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_USECONDS, MS_TO_US(1), NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Sleep for a significant fraction of the timeout. */ ussleep(600); /* Now re-add the timer with the same parameters */ start = now(); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Wait for the event */ kev.flags |= EV_CLEAR; kev.fflags &= ~NOTE_USECONDS; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); elapsed = now() - start; /* Check that the timer expired after at least 1 ms. This check is * to make sure that the timer re-started and that the event is * not from the original add of the timer. */ printf("timer expired after %ld us\n", elapsed); if (elapsed < MS_TO_US(1)) errx(1, "early timer expiration: %ld us", elapsed); success(); } static void test_update_expired(void) { const char *test_id = "kevent(EVFILT_TIMER (UPDATE EXP), EV_ADD | EV_ONESHOT)"; struct kevent kev; long elapsed; long start; test_begin(test_id); test_no_kevents(); /* Set the timer to 1ms */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_USECONDS, MS_TO_US(1), NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Wait for 2 ms to give the timer plenty of time to expire. */ mssleep(2); /* Now re-add the timer */ start = now(); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Wait for the event */ kev.flags |= EV_CLEAR; kev.fflags &= ~NOTE_USECONDS; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); elapsed = now() - start; /* Check that the timer expired after at least 1 ms. This check * is to make sure that the timer re-started and that the event is * not from the original add (and expiration) of the timer. */ printf("timer expired after %ld us\n", elapsed); if (elapsed < MS_TO_US(1)) errx(1, "early timer expiration: %ld us", elapsed); /* Make sure the re-added timer does not fire. In other words, * test that the event received above was the only event from the * add and re-add of the timer. */ mssleep(2); test_no_kevents(); success(); } static void test_update_periodic(void) { const char *test_id = "kevent(EVFILT_TIMER (UPDATE), periodic)"; struct kevent kev; long elapsed; long start; long stop; test_begin(test_id); test_no_kevents(); EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(1), NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Retrieve the event */ kev.flags = EV_ADD | EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); /* Check if the event occurs again */ sleep(1); kevent_cmp(&kev, kevent_get(kqfd)); /* Re-add with new timeout. */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, SEC_TO_MS(2), NULL); start = now(); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Retrieve the event */ kev.flags = EV_ADD | EV_CLEAR; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); stop = now(); elapsed = stop - start; /* Check that the timer expired after at least 2 ms. */ printf("timer expired after %ld us\n", elapsed); if (elapsed < MS_TO_US(2)) errx(1, "early timer expiration: %ld us", elapsed); /* Delete the event */ kev.flags = EV_DELETE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } static void test_update_timing(void) { #define MIN_SLEEP 500 #define MAX_SLEEP 1500 const char *test_id = "kevent(EVFILT_TIMER (UPDATE TIMING), EV_ADD | EV_ONESHOT)"; struct kevent kev; int iteration; int sleeptime; long elapsed; long start; long stop; test_begin(test_id); test_no_kevents(); /* Re-try the update tests with a variety of delays between the * original timer activation and the update of the timer. The goal * is to show that in all cases the only timer event that is * received is from the update and not the original timer add. */ for (sleeptime = MIN_SLEEP, iteration = 1; sleeptime < MAX_SLEEP; ++sleeptime, ++iteration) { /* First set the timer to 1 ms */ EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, NOTE_USECONDS, MS_TO_US(1), NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Delay; the delay ranges from less than to greater than the * timer period. */ ussleep(sleeptime); /* Now re-add the timer with the same parameters */ start = now(); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Wait for the event */ kev.flags |= EV_CLEAR; kev.fflags &= ~NOTE_USECONDS; kev.data = 1; kevent_cmp(&kev, kevent_get(kqfd)); stop = now(); elapsed = stop - start; /* Check that the timer expired after at least 1 ms. This * check is to make sure that the timer re-started and that * the event is not from the original add of the timer. */ if (elapsed < MS_TO_US(1)) errx(1, "early timer expiration: %ld us", elapsed); /* Make sure the re-added timer does not fire. In other words, * test that the event received above was the only event from * the add and re-add of the timer. */ mssleep(2); test_no_kevents_quietly(); } success(); } void -test_evfilt_timer() +test_evfilt_timer(void) { kqfd = kqueue(); test_kevent_timer_add(); test_kevent_timer_del(); test_kevent_timer_get(); test_oneshot(); test_periodic(); test_abstime(); test_update(); test_update_equal(); test_update_expired(); test_update_timing(); test_update_periodic(); disable_and_enable(); close(kqfd); } Index: head/tests/sys/kqueue/libkqueue/user.c =================================================================== --- head/tests/sys/kqueue/libkqueue/user.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/user.c (revision 360073) @@ -1,128 +1,128 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "common.h" static void add_and_delete(void) { const char *test_id = "kevent(EVFILT_USER, EV_ADD and EV_DELETE)"; struct kevent kev; test_begin(test_id); kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL); test_no_kevents(); kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DELETE, 0, 0, NULL); test_no_kevents(); success(); } static void event_wait(void) { const char *test_id = "kevent(EVFILT_USER, wait)"; struct kevent kev; test_begin(test_id); test_no_kevents(); /* Add the event, and then trigger it */ kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, NULL); kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); kev.fflags &= ~NOTE_FFCTRLMASK; kev.fflags &= ~NOTE_TRIGGER; kev.flags = EV_CLEAR; kevent_cmp(&kev, kevent_get(kqfd)); test_no_kevents(); success(); } static void disable_and_enable(void) { const char *test_id = "kevent(EVFILT_USER, EV_DISABLE and EV_ENABLE)"; struct kevent kev; test_begin(test_id); test_no_kevents(); kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ADD, 0, 0, NULL); kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_DISABLE, 0, 0, NULL); /* Trigger the event, but since it is disabled, nothing will happen. */ kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); test_no_kevents(); kevent_add(kqfd, &kev, 1, EVFILT_USER, EV_ENABLE, 0, 0, NULL); kevent_add(kqfd, &kev, 1, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); kev.flags = EV_CLEAR; kev.fflags &= ~NOTE_FFCTRLMASK; kev.fflags &= ~NOTE_TRIGGER; kevent_cmp(&kev, kevent_get(kqfd)); success(); } static void oneshot(void) { const char *test_id = "kevent(EVFILT_USER, EV_ONESHOT)"; struct kevent kev; test_begin(test_id); test_no_kevents(); kevent_add(kqfd, &kev, 2, EVFILT_USER, EV_ADD | EV_ONESHOT, 0, 0, NULL); puts(" -- event 1"); kevent_add(kqfd, &kev, 2, EVFILT_USER, 0, NOTE_TRIGGER, 0, NULL); kev.flags = EV_ONESHOT; kev.fflags &= ~NOTE_FFCTRLMASK; kev.fflags &= ~NOTE_TRIGGER; kevent_cmp(&kev, kevent_get(kqfd)); test_no_kevents(); success(); } void -test_evfilt_user() +test_evfilt_user(void) { kqfd = kqueue(); add_and_delete(); event_wait(); disable_and_enable(); oneshot(); /* TODO: try different fflags operations */ close(kqfd); } Index: head/tests/sys/kqueue/libkqueue/vnode.c =================================================================== --- head/tests/sys/kqueue/libkqueue/vnode.c (revision 360072) +++ head/tests/sys/kqueue/libkqueue/vnode.c (revision 360073) @@ -1,265 +1,265 @@ /* * Copyright (c) 2009 Mark Heily * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * $FreeBSD$ */ #include "common.h" int vnode_fd; -void +static void test_kevent_vnode_add(void) { const char *test_id = "kevent(EVFILT_VNODE, EV_ADD)"; const char *testfile = "./kqueue-test.tmp"; struct kevent kev; test_begin(test_id); system("touch ./kqueue-test.tmp"); vnode_fd = open(testfile, O_RDONLY); if (vnode_fd < 0) err(1, "open of %s", testfile); else printf("vnode_fd = %d\n", vnode_fd); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD, NOTE_WRITE | NOTE_ATTRIB | NOTE_RENAME | NOTE_DELETE, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_vnode_note_delete(void) { const char *test_id = "kevent(EVFILT_VNODE, NOTE_DELETE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_DELETE, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); if (unlink("./kqueue-test.tmp") < 0) err(1, "unlink"); kevent_cmp(&kev, kevent_get(kqfd)); success(); } -void +static void test_kevent_vnode_note_write(void) { const char *test_id = "kevent(EVFILT_VNODE, NOTE_WRITE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_WRITE, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); if (system("echo hello >> ./kqueue-test.tmp") < 0) err(1, "system"); /* BSD kqueue adds NOTE_EXTEND even though it was not requested */ /* BSD kqueue removes EV_ENABLE */ kev.flags &= ~EV_ENABLE; // XXX-FIXME compatibility issue kev.fflags |= NOTE_EXTEND; // XXX-FIXME compatibility issue kevent_cmp(&kev, kevent_get(kqfd)); success(); } -void +static void test_kevent_vnode_note_attrib(void) { const char *test_id = "kevent(EVFILT_VNODE, NOTE_ATTRIB)"; struct kevent kev; int nfds; test_begin(test_id); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); if (nfds < 1) err(1, "%s", test_id); - if (kev.ident != vnode_fd || + if (kev.ident != (uintptr_t)vnode_fd || kev.filter != EVFILT_VNODE || kev.fflags != NOTE_ATTRIB) err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", test_id, (unsigned int)kev.ident, kev.filter, kev.flags); success(); } -void +static void test_kevent_vnode_note_rename(void) { const char *test_id = "kevent(EVFILT_VNODE, NOTE_RENAME)"; struct kevent kev; int nfds; test_begin(test_id); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_RENAME, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); if (system("mv ./kqueue-test.tmp ./kqueue-test2.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); if (nfds < 1) err(1, "%s", test_id); - if (kev.ident != vnode_fd || + if (kev.ident != (uintptr_t)vnode_fd || kev.filter != EVFILT_VNODE || kev.fflags != NOTE_RENAME) err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", test_id, (unsigned int)kev.ident, kev.filter, kev.flags); if (system("mv ./kqueue-test2.tmp ./kqueue-test.tmp") < 0) err(1, "system"); success(); } -void +static void test_kevent_vnode_del(void) { const char *test_id = "kevent(EVFILT_VNODE, EV_DELETE)"; struct kevent kev; test_begin(test_id); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, 0, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); success(); } -void +static void test_kevent_vnode_disable_and_enable(void) { const char *test_id = "kevent(EVFILT_VNODE, EV_DISABLE and EV_ENABLE)"; struct kevent kev; int nfds; test_begin(test_id); test_no_kevents(); /* Add the watch and immediately disable it */ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_ONESHOT, NOTE_ATTRIB, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); kev.flags = EV_DISABLE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); /* Confirm that the watch is disabled */ if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); test_no_kevents(); /* Re-enable and check again */ kev.flags = EV_ENABLE; if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); if (nfds < 1) err(1, "%s", test_id); - if (kev.ident != vnode_fd || + if (kev.ident != (uintptr_t)vnode_fd || kev.filter != EVFILT_VNODE || kev.fflags != NOTE_ATTRIB) err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", test_id, (unsigned int)kev.ident, kev.filter, kev.flags); success(); } #if HAVE_EV_DISPATCH -void +static void test_kevent_vnode_dispatch(void) { const char *test_id = "kevent(EVFILT_VNODE, EV_DISPATCH)"; struct kevent kev; int nfds; test_begin(test_id); test_no_kevents(); EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_ADD | EV_DISPATCH, NOTE_ATTRIB, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "%s", test_id); if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); if (nfds < 1) err(1, "%s", test_id); - if (kev.ident != vnode_fd || + if (kev.ident != (uintptr_t)vnode_fd || kev.filter != EVFILT_VNODE || kev.fflags != NOTE_ATTRIB) err(1, "%s - incorrect event (sig=%u; filt=%d; flags=%d)", test_id, (unsigned int)kev.ident, kev.filter, kev.flags); /* Confirm that the watch is disabled automatically */ puts("-- checking that watch is disabled"); if (system("touch ./kqueue-test.tmp") < 0) err(1, "system"); test_no_kevents(); /* Delete the watch */ EV_SET(&kev, vnode_fd, EVFILT_VNODE, EV_DELETE, NOTE_ATTRIB, 0, NULL); if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0) err(1, "remove watch failed: %s", test_id); success(); } #endif /* HAVE_EV_DISPATCH */ void -test_evfilt_vnode() +test_evfilt_vnode(void) { kqfd = kqueue(); test_kevent_vnode_add(); test_kevent_vnode_del(); test_kevent_vnode_disable_and_enable(); #if HAVE_EV_DISPATCH test_kevent_vnode_dispatch(); #endif test_kevent_vnode_note_write(); test_kevent_vnode_note_attrib(); test_kevent_vnode_note_rename(); test_kevent_vnode_note_delete(); close(kqfd); }