/* * 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. */ #include "common.h" extern int kqfd; /* Checks if any events are pending, which is an error. */ void test_no_kevents(int kqfd) { int nfds; struct timespec timeo; struct kevent kev; memset(&timeo, 0, sizeof(timeo)); nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); if (nfds < 0) die("kevent(2)"); if (nfds > 0) { puts("\nUnexpected event:"); die(kevent_to_str(&kev)); } } /* Retrieve a single kevent */ struct kevent * kevent_get(int kqfd) { int nfds; static struct kevent __thread kev; nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); if (nfds < 1) die("kevent(2)"); return (&kev); } 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_VNODE) { snprintf(buf, 1024, "fflags = %d", kev->fflags); return (buf); } snprintf(buf, 1024, "fflags = %d (", 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] = ')'; return (buf); } 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); } /* TODO - backport changes from src/common/kevent.c kevent_dump() */ const char * kevent_to_str(struct kevent *kev) { char buf[512]; snprintf(&buf[0], sizeof(buf), "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]", (u_int) kev->ident, kev->filter, kevent_flags_dump(kev), kevent_fflags_dump(kev), (int) kev->data, kev->udata); return (strdup(buf)); } void kevent_update(int kqfd, struct kevent *kev) { if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { printf("Unable to add the following kevent:\n%s\n", kevent_to_str(kev)); die("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) { EV_SET(kev, ident, filter, flags, fflags, data, NULL); if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { printf("Unable to add the following kevent:\n%s\n", kevent_to_str(kev)); die("kevent"); } } void kevent_cmp(struct kevent *k1, struct kevent *k2) { /* XXX- Workaround for inconsistent implementation of kevent(2) */ #if defined (__FreeBSD_kernel__) || defined (__FreeBSD__) if (k1->flags & EV_ADD) k2->flags |= EV_ADD; #endif if (memcmp(k1, k2, sizeof(*k1)) != 0) { printf("kevent_cmp: mismatch:\n expected %s\n but got %s\n", kevent_to_str(k1), kevent_to_str(k2)); abort(); } }