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 17#include "common.h" 18 19extern int kqfd; 20 21/* Checks if any events are pending, which is an error. */ 22void 23test_no_kevents(int kqfd) 24{ 25 int nfds; 26 struct timespec timeo; 27 struct kevent kev; 28 29 memset(&timeo, 0, sizeof(timeo)); 30 nfds = kevent(kqfd, NULL, 0, &kev, 1, &timeo); 31 if (nfds < 0) 32 die("kevent(2)"); 33 if (nfds > 0) { 34 puts("\nUnexpected event:"); 35 die(kevent_to_str(&kev)); 36 } 37} 38 39/* Retrieve a single kevent */ 40struct kevent * 41kevent_get(int kqfd) 42{ 43 int nfds; 44 static struct kevent __thread kev; 45 46 nfds = kevent(kqfd, NULL, 0, &kev, 1, NULL); 47 if (nfds < 1) 48 die("kevent(2)"); 49 50 return (&kev); 51} 52 53char * 54kevent_fflags_dump(struct kevent *kev) 55{ 56 char *buf; 57 58#define KEVFFL_DUMP(attrib) \ 59 if (kev->fflags & attrib) \ 60 strncat(buf, #attrib" ", 64); 61 62 if ((buf = calloc(1, 1024)) == NULL) 63 abort(); 64 65 /* Not every filter has meaningful fflags */ 66 if (kev->filter != EVFILT_VNODE) { 67 snprintf(buf, 1024, "fflags = %d", kev->fflags); 68 return (buf); 69 } 70 71 snprintf(buf, 1024, "fflags = %d (", kev->fflags); 72 KEVFFL_DUMP(NOTE_DELETE); 73 KEVFFL_DUMP(NOTE_WRITE); 74 KEVFFL_DUMP(NOTE_EXTEND); 75#if HAVE_NOTE_TRUNCATE 76 KEVFFL_DUMP(NOTE_TRUNCATE); 77#endif 78 KEVFFL_DUMP(NOTE_ATTRIB); 79 KEVFFL_DUMP(NOTE_LINK); 80 KEVFFL_DUMP(NOTE_RENAME); 81#if HAVE_NOTE_REVOKE 82 KEVFFL_DUMP(NOTE_REVOKE); 83#endif 84 buf[strlen(buf) - 1] = ')'; 85 86 return (buf); 87} 88 89char * 90kevent_flags_dump(struct kevent *kev) 91{ 92 char *buf; 93 94#define KEVFL_DUMP(attrib) \ 95 if (kev->flags & attrib) \ 96 strncat(buf, #attrib" ", 64); 97 98 if ((buf = calloc(1, 1024)) == NULL) 99 abort(); 100 101 snprintf(buf, 1024, "flags = %d (", kev->flags); 102 KEVFL_DUMP(EV_ADD); 103 KEVFL_DUMP(EV_ENABLE); 104 KEVFL_DUMP(EV_DISABLE); 105 KEVFL_DUMP(EV_DELETE); 106 KEVFL_DUMP(EV_ONESHOT); 107 KEVFL_DUMP(EV_CLEAR); 108 KEVFL_DUMP(EV_EOF); 109 KEVFL_DUMP(EV_ERROR); 110#if HAVE_EV_DISPATCH 111 KEVFL_DUMP(EV_DISPATCH); 112#endif 113#if HAVE_EV_RECEIPT 114 KEVFL_DUMP(EV_RECEIPT); 115#endif 116 buf[strlen(buf) - 1] = ')'; 117 118 return (buf); 119} 120 121/* TODO - backport changes from src/common/kevent.c kevent_dump() */ 122const char * 123kevent_to_str(struct kevent *kev) 124{ 125 char buf[512]; 126 127 snprintf(&buf[0], sizeof(buf), 128 "[ident=%d, filter=%d, %s, %s, data=%d, udata=%p]", 129 (u_int) kev->ident, 130 kev->filter, 131 kevent_flags_dump(kev), 132 kevent_fflags_dump(kev), 133 (int) kev->data, 134 kev->udata); 135 136 return (strdup(buf)); 137} 138 139void 140kevent_update(int kqfd, struct kevent *kev) 141{ 142 if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { 143 printf("Unable to add the following kevent:\n%s\n", 144 kevent_to_str(kev)); 145 die("kevent"); 146 } 147} 148 149void 150kevent_add(int kqfd, struct kevent *kev, 151 uintptr_t ident, 152 short filter, 153 u_short flags, 154 u_int fflags, 155 intptr_t data, 156 void *udata) 157{ 158 EV_SET(kev, ident, filter, flags, fflags, data, NULL); 159 if (kevent(kqfd, kev, 1, NULL, 0, NULL) < 0) { 160 printf("Unable to add the following kevent:\n%s\n", 161 kevent_to_str(kev)); 162 die("kevent"); 163 } 164} 165 166void 167kevent_cmp(struct kevent *k1, struct kevent *k2) 168{ 169/* XXX- 170 Workaround for inconsistent implementation of kevent(2) 171 */ 172#if defined (__FreeBSD_kernel__) || defined (__FreeBSD__) 173 if (k1->flags & EV_ADD) 174 k2->flags |= EV_ADD; 175#endif 176 if (memcmp(k1, k2, sizeof(*k1)) != 0) { 177 printf("kevent_cmp: mismatch:\n expected %s\n but got %s\n", 178 kevent_to_str(k1), kevent_to_str(k2)); 179 abort(); 180 } 181} 182