ioloop-epoll.c revision 6795f542ed816a3c977085d4f74df1d62a37b690
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher/*
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Linux epoll() based ioloop handler.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher *
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher *
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * This software is released under the MIT license.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "lib.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "array.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "fd-close-on-exec.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "ioloop-internal.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include "ioloop-iolist.h"
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#ifdef IOLOOP_EPOLL
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <sys/epoll.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#include <unistd.h>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstruct ioloop_handler_context {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int epfd;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher unsigned int deleted_count;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ARRAY_DEFINE(fd_index, struct io_list *);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ARRAY_DEFINE(events, struct epoll_event);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher};
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handler_init(struct ioloop *ioloop, unsigned int initial_fd_count)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_array_init(&ctx->events, initial_fd_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_array_init(&ctx->fd_index, initial_fd_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->epfd = epoll_create(initial_fd_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ctx->epfd < 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (errno != EMFILE)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_fatal("epoll_create(): %m");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_fatal("epoll_create(): %m (you may need to increase "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "/proc/sys/fs/epoll/max_user_instances)");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher fd_close_on_exec(ctx->epfd, TRUE);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handler_deinit(struct ioloop *ioloop)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct io_list **list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher unsigned int i, count;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = array_get_modifiable(&ctx->fd_index, &count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; i < count; i++)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_free(list[i]);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (close(ctx->epfd) < 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_error("close(epoll) failed: %m");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher array_free(&ioloop->handler_context->fd_index);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher array_free(&ioloop->handler_context->events);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_free(ioloop->handler_context);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define IO_EPOLL_ERROR (EPOLLERR | EPOLLHUP)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define IO_EPOLL_INPUT (EPOLLIN | EPOLLPRI | IO_EPOLL_ERROR)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#define IO_EPOLL_OUTPUT (EPOLLOUT | IO_EPOLL_ERROR)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagherstatic int epoll_event_mask(struct io_list *list)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int events = 0, i;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct io_file *io;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher io = list->ios[i];
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (io == NULL)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher continue;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (io->io.condition & IO_READ)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher events |= IO_EPOLL_INPUT;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (io->io.condition & IO_WRITE)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher events |= IO_EPOLL_OUTPUT;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (io->io.condition & IO_ERROR)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher events |= IO_EPOLL_ERROR;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return events;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handle_add(struct io_file *io)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct io_list **list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct epoll_event event;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int op;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool first;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = array_idx_modifiable(&ctx->fd_index, io->fd);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (*list == NULL)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher *list = i_new(struct io_list, 1);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher first = ioloop_iolist_add(*list, io);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher memset(&event, 0, sizeof(event));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher event.data.ptr = *list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher event.events = epoll_event_mask(*list);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_fatal("io_loop_handle_add: epoll_ctl(%d, %d): %m",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher op, io->fd);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (first) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* allow epoll_wait() to return the maximum number of events
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher by keeping space allocated for each file descriptor */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ctx->deleted_count > 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->deleted_count--;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher (void)array_append_space(&ctx->events);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handle_remove(struct io_file *io, bool closed)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct io_list **list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct epoll_event event;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int op;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool last;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = array_idx_modifiable(&ctx->fd_index, io->fd);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher last = ioloop_iolist_del(*list, io);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!closed) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher memset(&event, 0, sizeof(event));
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher event.data.ptr = *list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher event.events = epoll_event_mask(*list);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_error("io_loop_handle_remove: epoll_ctl(%d, %d): %m",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher op, io->fd);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (last) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* since we're not freeing memory in any case, just increase
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher deleted counter so next handle_add() can just decrease it
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher insteading of appending to the events array */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->deleted_count++;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_free(io);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handler_run(struct ioloop *ioloop)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher{
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct epoll_event *events;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher const struct epoll_event *event;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct io_list *list;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct io_file *io;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct timeval tv;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher unsigned int events_count, t_id;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher int msecs, ret, i, j;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher bool call;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* get the time left for next timeout task */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher msecs = io_loop_get_wait_time(ioloop, &tv);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher events = array_get_modifiable(&ctx->events, &events_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = epoll_wait(ctx->epfd, events, events_count, msecs);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (ret < 0 && errno != EINTR)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_fatal("epoll_wait(): %m");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* execute timeout handlers */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher io_loop_handle_timeouts(ioloop);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (!ioloop->running)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher return;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; i < ret; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* io_loop_handle_add() may cause events array reallocation,
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher so we have use array_idx() */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher event = array_idx(&ctx->events, i);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = event->data.ptr;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher io = list->ios[j];
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (io == NULL)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher continue;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher call = FALSE;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if ((event->events & (EPOLLHUP | EPOLLERR)) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher call = TRUE;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else if ((io->io.condition & IO_READ) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher call = (event->events & EPOLLIN) != 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else if ((io->io.condition & IO_WRITE) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher call = (event->events & EPOLLOUT) != 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else if ((io->io.condition & IO_ERROR) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher call = (event->events & IO_EPOLL_ERROR) != 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (call) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher t_id = t_push();
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher io->io.callback(io->io.context);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if (t_pop() != t_id) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_panic("Leaked a t_pop() call in "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "I/O handler %p",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher (void *)io->io.callback);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher }
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher}
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#endif /* IOLOOP_EPOLL */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher