2 * Copyright (c) 2009 Mark Heily <mark@heily.com>
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.
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.
17 /* To get asprintf(3) */
27 #include <sys/queue.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
33 #include "sys/event.h"
37 kevent_filter_dump(const struct kevent *kev)
39 static char __thread buf[64];
41 snprintf(&buf[0], sizeof(buf), "%d (%s)",
42 kev->filter, filter_name(kev->filter));
47 kevent_fflags_dump(const struct kevent *kev)
49 static char __thread buf[1024];
51 #define KEVFFL_DUMP(attrib) \
52 if (kev->fflags & attrib) \
53 strncat(buf, #attrib" ", 64);
55 snprintf(buf, sizeof(buf), "fflags=0x%04x (", kev->fflags);
56 if (kev->filter == EVFILT_VNODE) {
57 KEVFFL_DUMP(NOTE_DELETE);
58 KEVFFL_DUMP(NOTE_WRITE);
59 KEVFFL_DUMP(NOTE_EXTEND);
60 KEVFFL_DUMP(NOTE_ATTRIB);
61 KEVFFL_DUMP(NOTE_LINK);
62 KEVFFL_DUMP(NOTE_RENAME);
63 } else if (kev->filter == EVFILT_USER) {
64 KEVFFL_DUMP(NOTE_FFNOP);
65 KEVFFL_DUMP(NOTE_FFAND);
66 KEVFFL_DUMP(NOTE_FFOR);
67 KEVFFL_DUMP(NOTE_FFCOPY);
68 KEVFFL_DUMP(NOTE_TRIGGER);
72 buf[strlen(buf) - 1] = ')';
80 kevent_flags_dump(const struct kevent *kev)
82 static char __thread buf[1024];
84 #define KEVFL_DUMP(attrib) \
85 if (kev->flags & attrib) \
86 strncat(buf, #attrib" ", 64);
88 snprintf(buf, sizeof(buf), "flags=0x%04x (", kev->flags);
90 KEVFL_DUMP(EV_ENABLE);
91 KEVFL_DUMP(EV_DISABLE);
92 KEVFL_DUMP(EV_DELETE);
93 KEVFL_DUMP(EV_ONESHOT);
97 KEVFL_DUMP(EV_DISPATCH);
98 KEVFL_DUMP(EV_RECEIPT);
99 buf[strlen(buf) - 1] = ')';
107 kevent_dump(const struct kevent *kev)
109 static char __thread buf[1024];
111 snprintf(buf, sizeof(buf),
112 "{ ident=%d, filter=%s, %s, %s, data=%d, udata=%p }",
114 kevent_filter_dump(kev),
115 kevent_flags_dump(kev),
116 kevent_fflags_dump(kev),
124 kevent_copyin_one(struct kqueue *kq, const struct kevent *src)
126 struct knote *kn = NULL;
130 if (src->flags & EV_DISPATCH && src->flags & EV_ONESHOT) {
135 if (filter_lookup(&filt, kq, src->filter) < 0)
138 //dbg_printf("src=%s\n", kevent_dump(src));
140 kn = knote_lookup(filt, src->ident);
142 if (src->flags & EV_ADD) {
143 if ((kn = knote_new()) == NULL) {
147 memcpy(&kn->kev, src, sizeof(kn->kev));
148 kn->kev.flags &= ~EV_ENABLE;
149 kn->kev.flags |= EV_ADD;//FIXME why?
150 assert(filt->kn_create);
151 if (filt->kn_create(filt, kn) < 0) {
152 knote_free(filt, kn);
156 knote_insert(filt, kn);
157 dbg_printf("created kevent %s\n", kevent_dump(src));
158 if (src->flags & EV_DISABLE) {
159 kn->kev.flags |= EV_DISABLE;
160 return (filt->kn_disable(filt, kn));
169 if (src->flags & EV_DELETE) {
170 rv = filt->kn_delete(filt, kn);
171 knote_free(filt, kn);
173 } else if (src->flags & EV_DISABLE) {
174 kn->kev.flags |= EV_DISABLE;
175 return (filt->kn_disable(filt, kn));
176 } else if (src->flags & EV_ENABLE) {
177 kn->kev.flags &= ~EV_DISABLE;
178 return (filt->kn_enable(filt, kn));
181 /* Implicit EV_ADD */
182 kn->kev.udata = src->udata;
183 return (filt->kn_modify(filt, kn, src));
186 /* Special case for EVFILT_USER:
187 Ignore user-generated events that are not of interest */
188 if (src->fflags & NOTE_TRIGGER) {
195 /** @return number of events added to the eventlist */
197 kevent_copyin(struct kqueue *kq, const struct kevent *src, int nchanges,
198 struct kevent *eventlist, int nevents)
202 dbg_printf("nchanges=%d nevents=%d", nchanges, nevents);
204 /* TODO: refactor, this has become convoluted to support EV_RECEIPT */
205 for (nret = 0; nchanges > 0; src++, nchanges--) {
207 if (kevent_copyin_one(kq, src) < 0) {
208 dbg_printf("errno=%s",strerror(errno));
212 if (src->flags & EV_RECEIPT) {
222 memcpy(eventlist, src, sizeof(*src));
223 eventlist->data = status;
235 int __attribute__((visibility("default")))
236 kevent(int kqfd, const struct kevent *changelist, int nchanges,
237 struct kevent *eventlist, int nevents,
238 const struct timespec *timeout)
245 kq = kqueue_get(kqfd);
251 rv = kqueue_validate(kq);
254 } else if (rv == 0) {
260 * Process each kevent on the changelist.
264 rv = kevent_copyin(kq, changelist, nchanges, eventlist, nevents);
266 dbg_printf("changelist: rv=%d", rv);
275 /* Determine if we need to wait for events. */
276 if (nevents > MAX_KEVENT)
277 nevents = MAX_KEVENT;
281 /* Handle spurious wakeups where no events are generated. */
282 for (nret = 0; nret == 0;)
284 /* Wait for one or more events. */
285 n = kevent_wait(kq, timeout);
287 dbg_puts("kevent_wait failed");
291 goto out; /* Timeout */
293 /* Copy the events to the caller */
295 nret = kevent_copyout(kq, n, eventlist, nevents);
300 dbg_printf("returning %d events", nret);
301 for (n = 0; n < nret; n++) {
302 dbg_printf("eventlist[%d] = %s", n, kevent_dump(&eventlist[n]));