2
* ivykis, an event handling library
3
* Copyright (C) 2002, 2003, 2009 Lennert Buytenhek
4
* Dedicated to Marija Kulikova.
6
* This library is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU Lesser General Public License version
8
* 2.1 as published by the Free Software Foundation.
10
* This library is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU Lesser General Public License version 2.1 for more details.
15
* You should have received a copy of the GNU Lesser General Public
16
* License version 2.1 along with this library; if not, write to the
17
* Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
18
* Boston, MA 02110-1301, USA.
26
#include <sys/types.h>
27
#include <sys/event.h>
30
#include "iv_private.h"
32
#define UPLOAD_QUEUE_SIZE (1024)
37
struct kevent *upload_queue;
42
#define kqueue_fd __tls_deref(kqueue_fd)
43
#define upload_queue __tls_deref(upload_queue)
44
#define upload_entries __tls_deref(upload_entries)
47
static int iv_kqueue_init(int maxfd)
55
flags = fcntl(kqueue_fd, F_GETFD);
56
if (!(flags & FD_CLOEXEC)) {
58
fcntl(kqueue_fd, F_SETFD, flags);
61
upload_queue = malloc(UPLOAD_QUEUE_SIZE * sizeof(*upload_queue));
62
if (upload_queue == NULL) {
67
fprintf(stderr, "warning: using kqueue(2), POLLERR delivery broken\n");
74
static void iv_kqueue_poll(int numfds, struct list_head *active, int msec)
77
struct kevent batch[numfds ? : 1];
82
* Valgrind 3.5.0 as supplied with FreeBSD 8.1-RELEASE ports
83
* doesn't understand that kevent(2) fills in kevent udata on
84
* return, and labels our subsequent use of it as "Conditional
85
* jump or move depends on uninitialised value(s)". Zero the
86
* udata fields here as an ugly workaround.
88
for (i = 0; i < (numfds ? : 1); i++)
91
to.tv_sec = msec / 1000;
92
to.tv_nsec = 1000000 * (msec % 1000);
94
ret = kevent(kqueue_fd, upload_queue, upload_entries,
95
batch, numfds ? : 1, &to);
100
fprintf(stderr, "iv_kqueue_poll: got error %d[%s]",
101
errno, strerror(errno));
107
for (i = 0; i < ret; i++) {
111
if (batch[i].filter == EVFILT_READ) {
112
iv_fd_make_ready(active, fd, MASKIN);
113
} else if (batch[i].filter == EVFILT_WRITE) {
114
iv_fd_make_ready(active, fd, MASKOUT);
116
fprintf(stderr, "iv_kqueue_poll: got message from "
117
"filter %d", batch[i].filter);
123
static void flush_upload_queue(void)
125
struct timespec to = { 0, 0 };
129
ret = kevent(kqueue_fd, upload_queue,
130
upload_entries, NULL, 0, &to);
131
} while (ret < 0 && errno == EINTR);
134
fprintf(stderr, "flush_upload_queue: got error %d[%s]",
135
errno, strerror(errno));
142
static void iv_kqueue_unregister_fd(struct iv_fd_ *fd)
144
flush_upload_queue();
147
static void queue(u_int ident, short filter, u_short flags,
148
u_int fflags, int data, void *udata)
150
if (upload_entries == UPLOAD_QUEUE_SIZE)
151
flush_upload_queue();
153
EV_SET(&upload_queue[upload_entries], ident, filter, flags,
154
fflags, data, udata);
158
static void iv_kqueue_notify_fd(struct iv_fd_ *fd, int wanted)
160
if ((fd->registered_bands & MASKIN) && !(wanted & MASKIN)) {
161
queue(fd->fd, EVFILT_READ, EV_DELETE, 0, 0, (void *)fd);
162
fd->registered_bands &= ~MASKIN;
163
} else if ((wanted & MASKIN) && !(fd->registered_bands & MASKIN)) {
164
queue(fd->fd, EVFILT_READ, EV_ADD | EV_ENABLE,
166
fd->registered_bands |= MASKIN;
169
if ((fd->registered_bands & MASKOUT) && !(wanted & MASKOUT)) {
170
queue(fd->fd, EVFILT_WRITE, EV_DELETE, 0, 0, (void *)fd);
171
fd->registered_bands &= ~MASKOUT;
172
} else if ((wanted & MASKOUT) && !(fd->registered_bands & MASKOUT)) {
173
queue(fd->fd, EVFILT_WRITE, EV_ADD | EV_ENABLE,
175
fd->registered_bands |= MASKOUT;
177
if (wanted & MASKERR) {
178
/* NOTE: kqueue doesn't support POLLERR-like interface, but
179
* we need to set it here, as otherwise we run into a failed
180
* assertion later on in the ivykis core.
183
fd->registered_bands |= MASKERR;
187
static void iv_kqueue_deinit(void)
193
static int iv_kqueue_pollable(int fd)
195
struct timespec to = { 0, 0 };
199
EV_SET(&kev, fd, EVFILT_READ, EV_ADD, 0, 0, &fd);
202
ret = kevent(kqueue_fd, &kev, 1,
204
} while (ret < 0 && errno == EINTR);
206
if (ret < 0 && errno == ENODEV)
209
EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, &fd);
212
ret = kevent(kqueue_fd, &kev, 1,
214
} while (ret < 0 && errno == EINTR);
217
fprintf(stderr, "iv_kqueue_pollable: got error %d[%s]",
218
errno, strerror(errno));
225
struct iv_poll_method iv_method_kqueue = {
227
.init = iv_kqueue_init,
228
.poll = iv_kqueue_poll,
229
.unregister_fd = iv_kqueue_unregister_fd,
230
.notify_fd = iv_kqueue_notify_fd,
231
.pollable = iv_kqueue_pollable,
232
.deinit = iv_kqueue_deinit,