ioloop-epoll.c revision a912d084eb8024ce35462c9fd2d50b86b13d8d33
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/*
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * Linux epoll() based ioloop handler.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * This library is free software; you can redistribute it and/or modify
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * it under the terms of the GNU Lesser General Public License as published
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * by the Free Software Foundation; either version 2 of the License, or
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen * (at your option) any later version.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen/* @UNSAFE: whole file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "ioloop-internal.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#ifdef IOLOOP_EPOLL
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <sys/epoll.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#define INITIAL_EPOLL_EVENTS 128
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenenum {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen EPOLL_LIST_INPUT,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen EPOLL_LIST_OUTPUT,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen EPOLL_IOS_PER_FD
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct ioloop_handler_context {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int epfd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int events_size, events_pos;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct epoll_event *events;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int idx_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io_list **fd_index;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct io_list {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io *ios[EPOLL_IOS_PER_FD];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen};
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_handler_init(struct ioloop *ioloop)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct ioloop_handler_context *ctx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->handler_context = ctx =
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_new(ioloop->pool, struct ioloop_handler_context, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->events_pos = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->events_size = INITIAL_EPOLL_EVENTS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->events = p_new(ioloop->pool, struct epoll_event,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->events_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->idx_size = INITIAL_EPOLL_EVENTS;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->fd_index = p_new(ioloop->pool, struct io_list *, ctx->idx_size);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->epfd = epoll_create(INITIAL_EPOLL_EVENTS);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->epfd < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("epoll_create(): %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_handler_deinit(struct ioloop *ioloop)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct ioloop_handler_context *ctx = ioloop->handler_context;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen close(ctx->epfd);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen p_free(ioloop->pool, ioloop->handler_context->events);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen p_free(ioloop->pool, ioloop->handler_context->fd_index);
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen p_free(ioloop->pool, ioloop->handler_context);
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen}
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen#define IO_EPOLL_INPUT (EPOLLIN | EPOLLPRI | EPOLLERR | EPOLLHUP)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen#define IO_EPOLL_OUTPUT (EPOLLOUT | EPOLLERR | EPOLLHUP)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainenstatic int epoll_event_mask(struct io_list *list)
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int events = 0, i;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io *io;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen for (i = 0; i < EPOLL_IOS_PER_FD; i++) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io = list->ios[i];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (io == NULL)
8fcff4c5b52f24d9c681805fdf06b486f1d0fcbeTimo Sirainen continue;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (io->condition & IO_READ)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen events |= IO_EPOLL_INPUT;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen if (io->condition & IO_WRITE)
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen events |= IO_EPOLL_OUTPUT;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return events;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int iolist_add(struct io_list *list, struct io *io)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((io->condition & IO_READ) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(list->ios[EPOLL_LIST_INPUT] == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->ios[EPOLL_LIST_INPUT] = io;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return list->ios[EPOLL_LIST_OUTPUT] == NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((io->condition & IO_WRITE) != 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(list->ios[EPOLL_LIST_OUTPUT] == NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->ios[EPOLL_LIST_OUTPUT] = io;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return list->ios[EPOLL_LIST_INPUT] == NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen return TRUE;
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen}
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic int iolist_del(struct io_list *list, struct io *io)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->ios[EPOLL_LIST_INPUT] == io) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->ios[EPOLL_LIST_INPUT] = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return list->ios[EPOLL_LIST_OUTPUT] == NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list->ios[EPOLL_LIST_OUTPUT] == io) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list->ios[EPOLL_LIST_OUTPUT] = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return list->ios[EPOLL_LIST_INPUT] == NULL;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_unreached();
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_handle_add(struct ioloop *ioloop, struct io *io)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct ioloop_handler_context *ctx = ioloop->handler_context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io_list *list;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct epoll_event event;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret, first, op, fd = io->fd;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen list = ctx->fd_index[fd];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (list == NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if ((unsigned int) fd >= ctx->idx_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* grow the fd -> iolist array */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen unsigned int old_size = ctx->idx_size;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->idx_size = nearest_power((unsigned int) fd+1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(ctx->idx_size < (size_t)-1 / sizeof(int));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->fd_index = p_realloc(ioloop->pool, ctx->fd_index,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(int) * old_size,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen sizeof(int) * ctx->idx_size);
f5672f838a62a3ae6cdf41641abecdddf1340f83Timo Sirainen }
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->fd_index[fd] = list =
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen p_new(ioloop->pool, struct io_list, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen first = iolist_add(list, io);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen event.data.ptr = list;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen event.events = epoll_event_mask(list);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = epoll_ctl(ctx->epfd, op, fd, &event);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("epoll_ctl(): %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ctx->events_pos >= ctx->events_size) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->events_size = nearest_power(ctx->events_size + 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen p_free(ioloop->pool, ctx->events);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ctx->events = p_new(ioloop->pool, struct epoll_event,
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->events_size);
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
992a13add4eea0810e4db0f042a595dddf85536aTimo Sirainen ctx->events_pos++;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_handle_remove(struct ioloop *ioloop, struct io *io)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct ioloop_handler_context *ctx = ioloop->handler_context;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io_list *list = ctx->fd_index[io->fd];
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct epoll_event event;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen int ret, last, op;
641f0c0900ee6e7cf9667f4b40ed95cec7d0cdcaTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen last = iolist_del(list, io);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen event.data.ptr = list;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen event.events = epoll_event_mask(list);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ret = epoll_ctl(ctx->epfd, op, io->fd, &event);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ret < 0 && errno != EBADF)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("epoll_ctl(): %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
ctx->events_pos--;
}
void io_loop_handler_run(struct ioloop *ioloop)
{
struct ioloop_handler_context *ctx = ioloop->handler_context;
struct epoll_event *event;
struct io_list *list;
struct io *io;
struct timeval tv;
unsigned int t_id;
int msecs, ret, i, call;
/* get the time left for next timeout task */
msecs = io_loop_get_wait_time(ioloop->timeouts, &tv, NULL);
ret = epoll_wait(ctx->epfd, ctx->events, ctx->events_size, msecs);
if (ret < 0 && errno != EINTR)
i_fatal("epoll_wait(): %m");
/* execute timeout handlers */
io_loop_handle_timeouts(ioloop);
if (ret <= 0 || !ioloop->running) {
/* No events */
return;
}
event = ctx->events;
while (ret-- > 0) {
list = event->data.ptr;
for (i = 0; i < EPOLL_IOS_PER_FD; i++) {
io = list->ios[i];
if (io == NULL)
continue;
call = FALSE;
if ((event->events & (EPOLLHUP | EPOLLERR)) != 0) {
call = TRUE;
} else if ((io->condition & IO_READ) != 0) {
call = event->events & EPOLLIN;
} else if ((io->condition & IO_WRITE) != 0) {
call = event->events & EPOLLOUT;
}
if (call) {
t_id = t_push();
io->callback(io->context);
if (t_pop() != t_id) {
i_panic("Leaked a t_pop() call in "
"I/O handler %p",
(void *)io->callback);
}
}
}
event++;
}
}
#endif /* IOLOOP_EPOLL */