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.
19 #include <linux/sockios.h>
24 #include <sys/ioctl.h>
25 #include <sys/queue.h>
26 #include <sys/socket.h>
27 #include <sys/types.h>
31 #include <sys/epoll.h>
33 #include "sys/event.h"
38 epoll_event_dump(struct epoll_event *evt)
40 static char __thread buf[128];
45 #define EPEVT_DUMP(attrib) \
46 if (evt->events & attrib) \
47 strcat(&buf[0], #attrib" ");
49 snprintf(&buf[0], 128, " { data = %p, events = ", evt->data.ptr);
52 #if defined(HAVE_EPOLLRDHUP)
53 EPEVT_DUMP(EPOLLRDHUP);
55 EPEVT_DUMP(EPOLLONESHOT);
57 strcat(&buf[0], "}\n");
64 epoll_update(int op, struct filter *filt, struct knote *kn, struct epoll_event *ev)
66 dbg_printf("op=%d fd=%d events=%s", op, (int)kn->kev.ident,
67 epoll_event_dump(ev));
68 if (epoll_ctl(filt->kf_pfd, op, kn->kev.ident, ev) < 0) {
69 dbg_printf("epoll_ctl(2): %s", strerror(errno));
77 socket_knote_delete(int epfd, int fd)
79 return epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL);
83 evfilt_socket_init(struct filter *filt)
85 filt->kf_pfd = epoll_create(1);
89 dbg_printf("socket epollfd = %d", filt->kf_pfd);
94 evfilt_socket_destroy(struct filter *filt)
100 evfilt_socket_copyout(struct filter *filt,
104 struct epoll_event epevt[MAX_KEVENT];
105 struct epoll_event *ev;
110 nret = epoll_wait(filt->kf_pfd, &epevt[0], nevents, 0);
114 dbg_perror("epoll_wait");
121 for (i = 0, nevents = 0; i < nret; i++) {
123 epoll_event_dump(ev);
124 kn = knote_lookup(filt, ev->data.fd);
126 memcpy(dst, &kn->kev, sizeof(*dst));
127 #if defined(HAVE_EPOLLRDHUP)
128 if (ev->events & EPOLLRDHUP || ev->events & EPOLLHUP)
129 dst->flags |= EV_EOF;
131 if (ev->events & EPOLLHUP)
132 dst->flags |= EV_EOF;
134 if (ev->events & EPOLLERR)
135 dst->fflags = 1; /* FIXME: Return the actual socket error */
137 if (kn->flags & KNFL_PASSIVE_SOCKET) {
138 /* On return, data contains the length of the
139 socket backlog. This is not available under Linux.
143 /* On return, data contains the number of bytes of protocol
144 data available to read.
146 if (ioctl(dst->ident,
147 (dst->filter == EVFILT_READ) ? SIOCINQ : SIOCOUTQ,
149 /* race condition with socket close, so ignore this error */
150 dbg_puts("ioctl(2) of socket failed");
155 if (kn->kev.flags & EV_DISPATCH) {
156 socket_knote_delete(filt->kf_pfd, kn->kev.ident);
158 } else if (kn->kev.flags & EV_ONESHOT) {
159 socket_knote_delete(filt->kf_pfd, kn->kev.ident);
160 knote_free(filt, kn);
172 evfilt_socket_knote_create(struct filter *filt, struct knote *kn)
174 struct epoll_event ev;
176 if (knote_get_socket_type(kn) < 0)
179 /* Convert the kevent into an epoll_event */
180 if (kn->kev.filter == EVFILT_READ)
181 #if defined(HAVE_EPOLLRDHUP)
182 kn->data.events = EPOLLIN | EPOLLRDHUP;
184 kn->data.events = EPOLLIN;
187 kn->data.events = EPOLLOUT;
188 if (kn->kev.flags & EV_ONESHOT || kn->kev.flags & EV_DISPATCH)
189 kn->data.events |= EPOLLONESHOT;
190 if (kn->kev.flags & EV_CLEAR)
191 kn->data.events |= EPOLLET;
193 memset(&ev, 0, sizeof(ev));
194 ev.events = kn->data.events;
195 ev.data.fd = kn->kev.ident;
197 return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev);
201 evfilt_socket_knote_modify(struct filter *filt, struct knote *kn,
202 const struct kevent *kev)
204 return (-1); /* STUB */
208 evfilt_socket_knote_delete(struct filter *filt, struct knote *kn)
210 if (kn->kev.flags & EV_DISABLE)
213 return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
217 evfilt_socket_knote_enable(struct filter *filt, struct knote *kn)
219 struct epoll_event ev;
221 memset(&ev, 0, sizeof(ev));
222 ev.events = kn->data.events;
223 ev.data.fd = kn->kev.ident;
225 return epoll_update(EPOLL_CTL_ADD, filt, kn, &ev);
229 evfilt_socket_knote_disable(struct filter *filt, struct knote *kn)
231 return epoll_update(EPOLL_CTL_DEL, filt, kn, NULL);
235 const struct filter evfilt_read = {
238 evfilt_socket_destroy,
239 evfilt_socket_copyout,
240 evfilt_socket_knote_create,
241 evfilt_socket_knote_modify,
242 evfilt_socket_knote_delete,
243 evfilt_socket_knote_enable,
244 evfilt_socket_knote_disable,
247 const struct filter evfilt_write = {
250 evfilt_socket_destroy,
251 evfilt_socket_copyout,
252 evfilt_socket_knote_create,
253 evfilt_socket_knote_modify,
254 evfilt_socket_knote_delete,
255 evfilt_socket_knote_enable,
256 evfilt_socket_knote_disable,