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.
25
#include <sys/devpoll.h>
26
#include "iv_private.h"
27
#include "iv_fd_private.h"
29
#define UPLOAD_BATCH 1024
31
static int iv_fd_avl_compare(struct iv_avl_node *_a, struct iv_avl_node *_b)
33
struct iv_fd_ *a = iv_container_of(_a, struct iv_fd_, u.avl_node);
34
struct iv_fd_ *b = iv_container_of(_b, struct iv_fd_, u.avl_node);
45
static int iv_fd_dev_poll_init(struct iv_state *st)
50
poll_fd = open("/dev/poll", O_RDWR | O_CLOEXEC);
54
poll_fd = open("/dev/poll", O_RDWR);
58
iv_fd_set_cloexec(poll_fd);
61
INIT_IV_AVL_TREE(&st->u.dev_poll.fds, iv_fd_avl_compare);
62
st->u.dev_poll.poll_fd = poll_fd;
63
INIT_IV_LIST_HEAD(&st->u.dev_poll.notify);
68
static void xwrite(int fd, const void *buf, size_t count)
74
ret = write(fd, buf, count);
75
} while (ret < 0 && errno == EINTR);
78
iv_fatal("iv_fd_dev_poll_flush_pending: got error "
79
"%d[%s]", errno, strerror(errno));
87
static int bits_to_poll_mask(int bits)
100
static void iv_fd_dev_poll_flush_pending(struct iv_state *st)
103
struct pollfd pfd[UPLOAD_BATCH];
106
poll_fd = st->u.dev_poll.poll_fd;
109
while (!iv_list_empty(&st->u.dev_poll.notify)) {
110
struct iv_list_head *ilh;
113
if (num > UPLOAD_BATCH - 2) {
114
xwrite(poll_fd, pfd, num * sizeof(pfd[0]));
118
ilh = st->u.dev_poll.notify.next;
119
iv_list_del_init(ilh);
121
fd = iv_list_entry(ilh, struct iv_fd_, list_notify);
123
if (fd->registered_bands & ~fd->wanted_bands) {
124
pfd[num].fd = fd->fd;
125
pfd[num].events = POLLREMOVE;
129
if (fd->wanted_bands) {
130
pfd[num].fd = fd->fd;
131
pfd[num].events = bits_to_poll_mask(fd->wanted_bands);
135
fd->registered_bands = fd->wanted_bands;
139
xwrite(poll_fd, pfd, num * sizeof(pfd[0]));
142
static struct iv_fd_ *iv_fd_avl_find(struct iv_avl_tree *root, int fd)
144
struct iv_avl_node *an;
150
p = iv_container_of(an, struct iv_fd_, u.avl_node);
164
iv_fd_dev_poll_poll(struct iv_state *st,
165
struct iv_list_head *active, struct timespec *to)
167
struct pollfd batch[st->numfds ? : 1];
172
iv_fd_dev_poll_flush_pending(st);
175
dvp.dp_nfds = ARRAY_SIZE(batch);
176
dvp.dp_timeout = 1000 * to->tv_sec + ((to->tv_nsec + 999999) / 1000000);
178
ret = ioctl(st->u.dev_poll.poll_fd, DP_POLL, &dvp);
183
iv_fatal("iv_fd_dev_poll_poll: got error %d[%s]",
184
errno, strerror(errno));
187
for (i = 0; i < ret; i++) {
191
fd = iv_fd_avl_find(&st->u.dev_poll.fds, batch[i].fd);
193
iv_fatal("iv_fd_dev_poll_poll: got event for "
194
"unknown fd %d", batch[i].fd);
197
revents = batch[i].revents;
199
if (revents & (POLLIN | POLLERR | POLLHUP))
200
iv_fd_make_ready(active, fd, MASKIN);
202
if (revents & (POLLOUT | POLLERR | POLLHUP))
203
iv_fd_make_ready(active, fd, MASKOUT);
205
if (revents & (POLLERR | POLLHUP))
206
iv_fd_make_ready(active, fd, MASKERR);
210
static void iv_fd_dev_poll_register_fd(struct iv_state *st, struct iv_fd_ *fd)
214
ret = iv_avl_tree_insert(&st->u.dev_poll.fds, &fd->u.avl_node);
216
iv_fatal("iv_fd_dev_poll_register_fd: got error %d[%s]",
221
static void iv_fd_dev_poll_unregister_fd(struct iv_state *st, struct iv_fd_ *fd)
223
iv_avl_tree_delete(&st->u.dev_poll.fds, &fd->u.avl_node);
225
if (!iv_list_empty(&fd->list_notify))
226
iv_fd_dev_poll_flush_pending(st);
229
static void iv_fd_dev_poll_notify_fd(struct iv_state *st, struct iv_fd_ *fd)
231
iv_list_del_init(&fd->list_notify);
232
if (fd->registered_bands != fd->wanted_bands)
233
iv_list_add_tail(&fd->list_notify, &st->u.dev_poll.notify);
236
static int iv_fd_dev_poll_notify_fd_sync(struct iv_state *st, struct iv_fd_ *fd)
242
pfd.events = bits_to_poll_mask(fd->wanted_bands);
245
ret = write(st->u.dev_poll.poll_fd, &pfd, sizeof(pfd));
246
} while (ret < 0 && errno == EINTR);
248
if (ret == sizeof(pfd)) {
249
fd->registered_bands = fd->wanted_bands;
256
static void iv_fd_dev_poll_deinit(struct iv_state *st)
258
close(st->u.dev_poll.poll_fd);
262
struct iv_fd_poll_method iv_fd_poll_method_dev_poll = {
264
.init = iv_fd_dev_poll_init,
265
.poll = iv_fd_dev_poll_poll,
266
.register_fd = iv_fd_dev_poll_register_fd,
267
.unregister_fd = iv_fd_dev_poll_unregister_fd,
268
.notify_fd = iv_fd_dev_poll_notify_fd,
269
.notify_fd_sync = iv_fd_dev_poll_notify_fd_sync,
270
.deinit = iv_fd_dev_poll_deinit,