bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2004-2018 Dovecot authors, see the included COPYING file */
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#include "lib.h"
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen#include "array.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen#include "ioloop-private.h"
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen#include "ioloop-iolist.h"
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#ifdef IOLOOP_EPOLL
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#include <sys/epoll.h>
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#include <unistd.h>
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainenstruct ioloop_handler_context {
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen int epfd;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen unsigned int deleted_count;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct io_list *) fd_index;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct epoll_event) events;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen};
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dac0b2e5e0f38c6d95ef1a842d891480db580236Timo Sirainenvoid io_loop_handler_init(struct ioloop *ioloop, unsigned int initial_fd_count)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen{
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainen struct ioloop_handler_context *ctx;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dac0b2e5e0f38c6d95ef1a842d891480db580236Timo Sirainen i_array_init(&ctx->events, initial_fd_count);
dac0b2e5e0f38c6d95ef1a842d891480db580236Timo Sirainen i_array_init(&ctx->fd_index, initial_fd_count);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dac0b2e5e0f38c6d95ef1a842d891480db580236Timo Sirainen ctx->epfd = epoll_create(initial_fd_count);
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen if (ctx->epfd < 0) {
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen if (errno != EMFILE)
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen i_fatal("epoll_create(): %m");
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen else {
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen i_fatal("epoll_create(): %m (you may need to increase "
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen "/proc/sys/fs/epoll/max_user_instances)");
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen }
717a444a466280a84a468220f647fdcb9f3b546fTimo Sirainen }
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen fd_close_on_exec(ctx->epfd, TRUE);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen}
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenvoid io_loop_handler_deinit(struct ioloop *ioloop)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen{
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainen struct ioloop_handler_context *ctx = ioloop->handler_context;
720692523ece4a549f7c589508d5693ee310f6b3Timo Sirainen struct io_list **list;
720692523ece4a549f7c589508d5693ee310f6b3Timo Sirainen unsigned int i, count;
720692523ece4a549f7c589508d5693ee310f6b3Timo Sirainen
4b8459c6c24b79d4ed5974ab6e3289a3f2b701c0Timo Sirainen list = array_get_modifiable(&ctx->fd_index, &count);
720692523ece4a549f7c589508d5693ee310f6b3Timo Sirainen for (i = 0; i < count; i++)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen i_free(list[i]);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen if (close(ctx->epfd) < 0)
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen i_error("close(epoll) failed: %m");
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen array_free(&ioloop->handler_context->fd_index);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen array_free(&ioloop->handler_context->events);
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen i_free(ioloop->handler_context);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen}
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen#define IO_EPOLL_ERROR (EPOLLERR | EPOLLHUP)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen#define IO_EPOLL_INPUT (EPOLLIN | EPOLLPRI | IO_EPOLL_ERROR)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen#define IO_EPOLL_OUTPUT (EPOLLOUT | IO_EPOLL_ERROR)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainenstatic int epoll_event_mask(struct io_list *list)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen{
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen int events = 0, i;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen struct io_file *io;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen for (i = 0; i < IOLOOP_IOLIST_IOS_PER_FD; i++) {
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen io = list->ios[i];
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen if (io == NULL)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen continue;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
49b6e2d72cfaa5c244c798ddbae5b61489b0f728Timo Sirainen if ((io->io.condition & IO_READ) != 0)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen events |= IO_EPOLL_INPUT;
49b6e2d72cfaa5c244c798ddbae5b61489b0f728Timo Sirainen if ((io->io.condition & IO_WRITE) != 0)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen events |= IO_EPOLL_OUTPUT;
49b6e2d72cfaa5c244c798ddbae5b61489b0f728Timo Sirainen if ((io->io.condition & IO_ERROR) != 0)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen events |= IO_EPOLL_ERROR;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen }
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen return events;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen}
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainenvoid io_loop_handle_add(struct io_file *io)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen{
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen struct io_list **list;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen struct epoll_event event;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen int op;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool first;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
139143f1b798472438b813343a48601f1c564060Sergey Kitov list = array_idx_get_space(&ctx->fd_index, io->fd);
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen if (*list == NULL)
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen *list = i_new(struct io_list, 1);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen first = ioloop_iolist_add(*list, io);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&event);
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen event.data.ptr = *list;
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen event.events = epoll_event_mask(*list);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen op = first ? EPOLL_CTL_ADD : EPOLL_CTL_MOD;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
debb28d107fa06d26fd194fdac523cfb32809199Timo Sirainen if (errno == EPERM && op == EPOLL_CTL_ADD) {
7420207c4eae66bd7edc2bdebaee7d2cb0b6c341Timo Sirainen i_panic("epoll_ctl(add, %d) failed: %m "
4d4cd9cde9e01d4ad9354e6e30ac2f90d13042b2Timo Sirainen "(fd doesn't support epoll%s)", io->fd,
4d4cd9cde9e01d4ad9354e6e30ac2f90d13042b2Timo Sirainen io->fd != STDIN_FILENO ? "" :
4d4cd9cde9e01d4ad9354e6e30ac2f90d13042b2Timo Sirainen " - instead of '<file', try 'cat file|'");
debb28d107fa06d26fd194fdac523cfb32809199Timo Sirainen }
debb28d107fa06d26fd194fdac523cfb32809199Timo Sirainen i_panic("epoll_ctl(%s, %d) failed: %m",
debb28d107fa06d26fd194fdac523cfb32809199Timo Sirainen op == EPOLL_CTL_ADD ? "add" : "mod", io->fd);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen }
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (first) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen /* allow epoll_wait() to return the maximum number of events
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen by keeping space allocated for each file descriptor */
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (ctx->deleted_count > 0)
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen ctx->deleted_count--;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen else
31a574fda352ef4f71dbff9c30e15e4744e132c0Timo Sirainen array_append_zero(&ctx->events);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen }
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen}
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainenvoid io_loop_handle_remove(struct io_file *io, bool closed)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen{
193f5296d2a6b847970c222d8a261b89aae46331Timo Sirainen struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
08f24237ccc177f5b3a09b24d8a725fa47e1ee32Timo Sirainen struct io_list **list;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen struct epoll_event event;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen int op;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool last;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen list = array_idx_modifiable(&ctx->fd_index, io->fd);
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen last = ioloop_iolist_del(*list, io);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen if (!closed) {
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&event);
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen event.data.ptr = *list;
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen event.events = epoll_event_mask(*list);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen op = last ? EPOLL_CTL_DEL : EPOLL_CTL_MOD;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen if (epoll_ctl(ctx->epfd, op, io->fd, &event) < 0) {
f2767c736d72e6aa9a2aae5d0a9b89abae9e29e9Timo Sirainen const char *errstr = t_strdup_printf(
f2767c736d72e6aa9a2aae5d0a9b89abae9e29e9Timo Sirainen "epoll_ctl(%s, %d) failed: %m",
debb28d107fa06d26fd194fdac523cfb32809199Timo Sirainen op == EPOLL_CTL_DEL ? "del" : "mod", io->fd);
f2767c736d72e6aa9a2aae5d0a9b89abae9e29e9Timo Sirainen if (errno == EBADF)
f2767c736d72e6aa9a2aae5d0a9b89abae9e29e9Timo Sirainen i_panic("%s", errstr);
f2767c736d72e6aa9a2aae5d0a9b89abae9e29e9Timo Sirainen else
f2767c736d72e6aa9a2aae5d0a9b89abae9e29e9Timo Sirainen i_error("%s", errstr);
745f2c7424d88e368eff0a3a7650b352a9d1f0ddTimo Sirainen }
f05b9dd37f830576ca7d32ec7071bf87906df3d2Timo Sirainen }
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen if (last) {
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen /* since we're not freeing memory in any case, just increase
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen deleted counter so next handle_add() can just decrease it
19557f192d37cd54a1a090a8a26d9d47265e4413Aki Tuomi instead of appending to the events array */
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen ctx->deleted_count++;
35565557e05721a761132cec2ba1d93acacb6c14Timo Sirainen }
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen i_free(io);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen}
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
f922ecaf766c60c10f642f3ac2d5f7748ff642b0Timo Sirainenvoid io_loop_handler_run_internal(struct ioloop *ioloop)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen{
797de45dcf6e24642ab347d5033beb92034b779dTimo Sirainen struct ioloop_handler_context *ctx = ioloop->handler_context;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen struct epoll_event *events;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen const struct epoll_event *event;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen struct io_list *list;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen struct io_file *io;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen struct timeval tv;
b9a13c136b7c5803a8271878fcbbf5328f6e7f2aTimo Sirainen unsigned int events_count;
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen int msecs, ret, i, j;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen bool call;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
80cfaba9e253545cbcd08f84939b27cdbb4a50d0Aki Tuomi i_assert(ctx != NULL);
80cfaba9e253545cbcd08f84939b27cdbb4a50d0Aki Tuomi
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen /* get the time left for next timeout task */
6795f542ed816a3c977085d4f74df1d62a37b690Timo Sirainen msecs = io_loop_get_wait_time(ioloop, &tv);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen events = array_get_modifiable(&ctx->events, &events_count);
b116c06e4d3609f07f1d9582a932ad3ea9ce7e15Stephan Bosch if (ioloop->io_files != NULL && events_count > ctx->deleted_count) {
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen ret = epoll_wait(ctx->epfd, events, events_count, msecs);
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen if (ret < 0 && errno != EINTR)
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen i_fatal("epoll_wait(): %m");
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen } else {
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen /* no I/Os, but we should have some timeouts.
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen just wait for them. */
c8920d5f3df9663668ccd6412218eb28008f4e9aTimo Sirainen if (msecs < 0)
c8920d5f3df9663668ccd6412218eb28008f4e9aTimo Sirainen i_panic("BUG: No IOs or timeouts set. Not waiting for infinity.");
f0a386b29f2c9163e8fff6a8e26077b59708c980Timo Sirainen usleep(msecs*1000);
637f9883a385abb03fd1211e79cc68df696cc387Timo Sirainen ret = 0;
eff0f02f2c8320c1bd4df72a281a92051d78b2b1Timo Sirainen }
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen /* execute timeout handlers */
20a3870db4f78717574ee94bca1512994391b2abTimo Sirainen io_loop_handle_timeouts(ioloop);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen if (!ioloop->running)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen return;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen for (i = 0; i < ret; i++) {
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen /* io_loop_handle_add() may cause events array reallocation,
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen so we have use array_idx() */
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen event = array_idx(&ctx->events, i);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen list = event->data.ptr;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) {
dba5754de32284b3149ddd5c9bb1701b05707752Timo Sirainen io = list->ios[j];
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen if (io == NULL)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen continue;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen call = FALSE;
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen if ((event->events & (EPOLLHUP | EPOLLERR)) != 0)
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen call = TRUE;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen else if ((io->io.condition & IO_READ) != 0)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen call = (event->events & EPOLLIN) != 0;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen else if ((io->io.condition & IO_WRITE) != 0)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen call = (event->events & EPOLLOUT) != 0;
dcc76bb1e1bb287e3e71e6a39a7ca207fab0eaa8Timo Sirainen else if ((io->io.condition & IO_ERROR) != 0)
8d59f06c9422fa49b538e23ffb06eddb23c6add2Timo Sirainen call = (event->events & IO_EPOLL_ERROR) != 0;
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
b9a13c136b7c5803a8271878fcbbf5328f6e7f2aTimo Sirainen if (call)
b9a13c136b7c5803a8271878fcbbf5328f6e7f2aTimo Sirainen io_loop_call_io(&io->io);
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen }
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen }
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen}
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen
c014f12e8268bf37ca2997e632ad7c22b8d04a84Timo Sirainen#endif /* IOLOOP_EPOLL */