void io_loop_handler_run_internal(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct epoll_event *events; const struct epoll_event *event; struct io_list *list; struct io_file *io; struct timeval tv; unsigned int events_count; int msecs, ret, i, j; bool call; /* get the time left for next timeout task */ msecs = io_loop_get_wait_time(ioloop, &tv); events = array_get_modifiable(&ctx->events, &events_count); if (ioloop->io_files != NULL && events_count > ctx->deleted_count) { ret = epoll_wait(ctx->epfd, events, events_count, msecs); if (ret < 0 && errno != EINTR) i_fatal("epoll_wait(): %m"); } else { /* no I/Os, but we should have some timeouts. just wait for them. */ i_assert(msecs >= 0); usleep(msecs*1000); ret = 0; } /* execute timeout handlers */ io_loop_handle_timeouts(ioloop); if (!ioloop->running) return; for (i = 0; i < ret; i++) { /* io_loop_handle_add() may cause events array reallocation, so we have use array_idx() */ event = array_idx(&ctx->events, i); list = event->data.ptr; for (j = 0; j < IOLOOP_IOLIST_IOS_PER_FD; j++) { io = list->ios[j]; if (io == NULL) continue; call = FALSE; if ((event->events & (EPOLLHUP | EPOLLERR)) != 0) call = TRUE; else if ((io->io.condition & IO_READ) != 0) call = (event->events & EPOLLIN) != 0; else if ((io->io.condition & IO_WRITE) != 0) call = (event->events & EPOLLOUT) != 0; else if ((io->io.condition & IO_ERROR) != 0) call = (event->events & IO_EPOLL_ERROR) != 0; if (call) io_loop_call_io(&io->io); } } }
void io_loop_handler_run_internal(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct kevent *events; const struct kevent *event; struct timeval tv; struct timespec ts; struct io_file *io; unsigned int events_count; int ret, i, msecs; /* get the time left for next timeout task */ msecs = io_loop_get_wait_time(ioloop, &tv); ts.tv_sec = tv.tv_sec; ts.tv_nsec = tv.tv_usec * 1000; /* wait for events */ events = array_get_modifiable(&ctx->events, &events_count); if (events_count > 0) { ret = kevent (ctx->kq, NULL, 0, events, events_count, &ts); if (ret < 0 && errno != EINTR) i_panic("kevent() failed: %m"); } else { if (msecs < 0) i_panic("BUG: No IOs or timeouts set. Not waiting for infinity."); usleep(msecs * 1000); ret = 0; } /* reference all IOs */ for (i = 0; i < ret; i++) { io = (void *)events[i].udata; i_assert(io->refcount > 0); io->refcount++; } /* execute timeout handlers */ io_loop_handle_timeouts(ioloop); for (i = 0; i < ret; i++) { /* io_loop_handle_add() may cause events array reallocation, so we have use array_idx() */ event = array_idx(&ctx->events, i); io = (void *)event->udata; /* callback is NULL if io_remove() was already called */ if (io->io.callback != NULL) io_loop_call_io(&io->io); i_assert(io->refcount > 0); if (--io->refcount == 0) i_free(io); } }
static void event_callback(struct ioloop_notify_handler_context *ctx) { struct io_notify *io; struct kevent events[64]; struct timespec ts; int i, ret; ts.tv_sec = 0; ts.tv_nsec = 0; ret = kevent(ctx->kq, NULL, 0, events, N_ELEMENTS(events), &ts); if (ret <= 0) { if (ret == 0 || errno == EINTR) return; i_fatal("kevent(notify) failed: %m"); } if (gettimeofday(&ioloop_timeval, NULL) < 0) i_fatal("gettimeofday() failed: %m"); ioloop_time = ioloop_timeval.tv_sec; for (i = 0; i < ret; i++) { io = (void *)events[i].udata; i_assert(io->refcount >= 1); io->refcount++; } for (i = 0; i < ret; i++) { io = (void *)events[i].udata; /* there can be multiple events for a single io. call the callback only once if that happens. */ if (io->refcount == 2 && io->io.callback != NULL) io_loop_call_io(&io->io); if (--io->refcount == 0) i_free(io); } }
void io_loop_handler_run(struct ioloop *ioloop) { struct ioloop_handler_context *ctx = ioloop->handler_context; struct timeval tv; struct io_file *io; int ret; /* get the time left for next timeout task */ io_loop_get_wait_time(ioloop, &tv); memcpy(&ctx->tmp_read_fds, &ctx->read_fds, sizeof(fd_set)); memcpy(&ctx->tmp_write_fds, &ctx->write_fds, sizeof(fd_set)); memcpy(&ctx->tmp_except_fds, &ctx->except_fds, sizeof(fd_set)); ret = select(ctx->highest_fd + 1, &ctx->tmp_read_fds, &ctx->tmp_write_fds, &ctx->tmp_except_fds, &tv); if (ret < 0 && errno != EINTR) i_warning("select() : %m"); /* execute timeout handlers */ io_loop_handle_timeouts(ioloop); if (ret <= 0 || !ioloop->running) { /* no I/O events */ return; } io = ioloop->io_files; for (; io != NULL && ret > 0; io = ioloop->next_io_file) { ioloop->next_io_file = io->next; if (io_check_condition(ctx, io->fd, io->io.condition)) { ret--; io_loop_call_io(&io->io); } } }