6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher * BSD kqueue() based ioloop handler.
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher * Copyright (c) 2005 Vaclav Haisman <v.haisman@sh.cvut.cz>
ad805face83ba7d67b1cf2067a1982c7e63d1060Jakub Hrozek/* kevent.udata's type just has to be different in NetBSD than in
a7797068c4deb6ce2bdbcda27c45ff1bbb4a8e78Jakub Hrozek FreeBSD and OpenBSD.. */
7a14e8f66c0e932fe2954d792614a3b61d444bd1Jakub Hrozek EV_SET(a, b, c, d, e, f, g)
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekvoid io_loop_handler_init(struct ioloop *ioloop, unsigned int initial_fd_count)
9a839b29816c8906d4a6b074cf76df790cac9209Jakub Hrozek ioloop->handler_context = ctx = i_new(struct ioloop_handler_context, 1);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_fatal("kqueue() in io_loop_handler_init() failed: %m");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_array_init(&ctx->events, initial_fd_count);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid io_loop_handler_deinit(struct ioloop *ioloop)
261cdde02b40aa8dabb3d69e43586a5a220647e9Jakub Hrozek i_error("close(kqueue) in io_loop_handler_deinit() failed: %m");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid io_loop_handle_add(struct io_file *io)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if ((io->io.condition & (IO_READ | IO_ERROR)) != 0) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MY_EV_SET(&ev, io->fd, EVFILT_READ, EV_ADD, 0, 0, io);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_panic("kevent(EV_ADD, READ, %d) failed: %m", io->fd);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher MY_EV_SET(&ev, io->fd, EVFILT_WRITE, EV_ADD, 0, 0, io);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_panic("kevent(EV_ADD, WRITE, %d) failed: %m", io->fd);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher /* allow kevent() to return the maximum number of events
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher by keeping space allocated for each handle */
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozekvoid io_loop_handle_remove(struct io_file *io, bool closed)
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek struct ioloop_handler_context *ctx = io->io.ioloop->handler_context;
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if ((io->io.condition & (IO_READ | IO_ERROR)) != 0 && !closed) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MY_EV_SET(&ev, io->fd, EVFILT_READ, EV_DELETE, 0, 0, NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("kevent(EV_DELETE, %d) failed: %m", io->fd);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if ((io->io.condition & IO_WRITE) != 0 && !closed) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher MY_EV_SET(&ev, io->fd, EVFILT_WRITE, EV_DELETE, 0, 0, NULL);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher if (kevent(ctx->kq, &ev, 1, NULL, 0, NULL) < 0)
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher i_error("kevent(EV_DELETE, %d) failed: %m", io->fd);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* since we're not freeing memory in any case, just increase
f10ebaa51ecdcbbd10f171d19fe8e680e5bc74aaJakub Hrozek deleted counter so next handle_add() can just decrease it
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher instead of appending to the events array */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallaghervoid io_loop_handler_run_internal(struct ioloop *ioloop)
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher struct ioloop_handler_context *ctx = ioloop->handler_context;
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher /* get the time left for next timeout task */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher msecs = io_loop_get_wait_time(ioloop, &tv);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher /* wait for events */
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher events = array_get_modifiable(&ctx->events, &events_count);
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher ret = kevent (ctx->kq, NULL, 0, events, events_count, &ts);
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_panic("kevent(events=%u, ts=%ld.%u) failed: %m",
1008001f34abb42df75f840db17f14a83f0c21d4Stephen Gallagher i_panic("BUG: No IOs or timeouts set. Not waiting for infinity.");
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* reference all IOs */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher for (i = 0; i < ret; i++) {
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* execute timeout handlers */
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek for (i = 0; i < ret; i++) {
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek /* io_loop_handle_add() may cause events array reallocation,
b47fd11a259c50e63cd674c7cba0da3f2549cae0Jakub Hrozek so we have use array_idx() */
6b0f9cd2ee601121cb7fe1d9ad8ebce782aa8f39Stephen Gallagher /* callback is NULL if io_remove() was already called */