ioloop-epoll.c revision 6795f542ed816a3c977085d4f74df1d62a37b690
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Linux epoll() based ioloop handler.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * Copyright (c) 2004 Andrey Panin <pazke@donpac.ru>
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher * This software is released under the MIT license.
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handler_init(struct ioloop *ioloop, unsigned int initial_fd_count)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_array_init(&ctx->events, initial_fd_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_array_init(&ctx->fd_index, initial_fd_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ctx->epfd = epoll_create(initial_fd_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher i_fatal("epoll_create(): %m (you may need to increase "
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "/proc/sys/fs/epoll/max_user_instances)");
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handler_deinit(struct ioloop *ioloop)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher unsigned int i, count;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = array_get_modifiable(&ctx->fd_index, &count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; i < count; i++)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher array_free(&ioloop->handler_context->fd_index);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher array_free(&ioloop->handler_context->events);
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 Gallagherstatic int epoll_event_mask(struct io_list *list)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handle_add(struct io_file *io)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = array_idx_modifiable(&ctx->fd_index, io->fd);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
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 /* allow epoll_wait() to return the maximum number of events
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher by keeping space allocated for each file descriptor */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallaghervoid io_loop_handle_remove(struct io_file *io, bool closed)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher list = array_idx_modifiable(&ctx->fd_index, io->fd);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
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 /* 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 Gallaghervoid io_loop_handler_run(struct ioloop *ioloop)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher struct ioloop_handler_context *ctx = ioloop->handler_context;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* get the time left for next timeout task */
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher msecs = io_loop_get_wait_time(ioloop, &tv);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher events = array_get_modifiable(&ctx->events, &events_count);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher ret = epoll_wait(ctx->epfd, events, events_count, msecs);
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher /* execute timeout handlers */
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 for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) {
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher if ((event->events & (EPOLLHUP | EPOLLERR)) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else if ((io->io.condition & IO_READ) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else if ((io->io.condition & IO_WRITE) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher else if ((io->io.condition & IO_ERROR) != 0)
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher call = (event->events & IO_EPOLL_ERROR) != 0;
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher "I/O handler %p",
e134a6af42102c8d865e82bf89e0b8c5a40fb5faStephen Gallagher#endif /* IOLOOP_EPOLL */