ioloop.c revision 90da11b31d498cd653ec7232b334b6057198ab46
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen/* Copyright (c) 2002-2003 Timo Sirainen */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#include "lib.h"
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#include "ioloop-internal.h"
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#undef timercmp
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen#define timercmp(tvp, uvp) \
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen ((tvp)->tv_sec > (uvp)->tv_sec || \
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen ((tvp)->tv_sec == (uvp)->tv_sec && \
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen (tvp)->tv_usec > (uvp)->tv_usec))
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainentime_t ioloop_time = 0;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovilastruct timeval ioloop_timeval;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovilastruct timezone ioloop_timezone;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovilastatic struct ioloop *current_ioloop = NULL;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovilastruct io *io_add(int fd, enum io_condition condition,
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila io_callback_t *callback, void *context)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila{
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila struct io *io;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila i_assert(fd >= 0);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila i_assert(callback != NULL);
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila if ((condition & IO_NOTIFY_MASK) != 0) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return io_loop_notify_add(current_ioloop, fd, condition,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen callback, context);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io = p_new(current_ioloop->pool, struct io, 1);
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen io->fd = fd;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io->condition = condition;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io->callback = callback;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io->context = context;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen io_loop_handle_add(current_ioloop, io);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* have to append it, or io_destroy() breaks */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io->next = current_ioloop->ios;
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen current_ioloop->ios = io;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (io->next != NULL)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io->next->prev = io;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return io;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenvoid io_remove(struct io *io)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if ((io->condition & IO_NOTIFY_MASK) != 0) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io_loop_notify_remove(current_ioloop, io);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* notify the real I/O handler */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io_loop_handle_remove(current_ioloop, io);
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen
a46abae27d4b00f77e5932ed8f7595c054fe0280Timo Sirainen if (current_ioloop->next_io == io)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen current_ioloop->next_io = io->next;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (io->prev == NULL)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen current_ioloop->ios = io->next;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila else
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila io->prev->next = io->next;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila if (io->next != NULL)
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila io->next->prev = io->prev;
4ef1f9f3293965734e6e3c38c191ceb2246a721fTeemu Huovila
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen p_free(current_ioloop->pool, io);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenstatic void timeout_list_insert(struct ioloop *ioloop, struct timeout *timeout)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct timeout **t;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct timeval *next_run;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen next_run = &timeout->next_run;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen for (t = &ioloop->timeouts; *t != NULL; t = &(*t)->next) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (timercmp(&(*t)->next_run, next_run))
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen break;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next = *t;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen *t = timeout;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenstatic void timeout_update_next(struct timeout *timeout, struct timeval *tv_now)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (tv_now == NULL) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (gettimeofday(&timeout->next_run, NULL) < 0)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen i_fatal("gettimeofday(): %m");
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen } else {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_sec = tv_now->tv_sec;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_usec = tv_now->tv_usec;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* we don't want microsecond accuracy or this function will be
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen called all the time - millisecond is more than enough */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_usec -= timeout->next_run.tv_usec % 1000;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_sec += timeout->msecs/1000;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_usec += (timeout->msecs%1000)*1000;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (timeout->next_run.tv_usec > 1000000) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_sec++;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->next_run.tv_usec -= 1000000;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenstruct timeout *timeout_add(unsigned int msecs, timeout_callback_t *callback,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen void *context)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct timeout *timeout;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout = p_new(current_ioloop->pool, struct timeout, 1);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->msecs = msecs;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->callback = callback;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->context = context;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout_update_next(timeout, current_ioloop->running ?
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen NULL : &ioloop_timeval);
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila timeout_list_insert(current_ioloop, timeout);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return timeout;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila}
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenvoid timeout_remove(struct timeout *timeout)
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen i_assert(timeout != NULL);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->destroyed = TRUE;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen}
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenvoid timeout_destroy(struct ioloop *ioloop, struct timeout **timeout_p)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen{
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila struct timeout *timeout = *timeout_p;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen *timeout_p = timeout->next;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen p_free(ioloop->pool, timeout);
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila}
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenint io_loop_get_wait_time(struct timeout *timeout, struct timeval *tv,
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct timeval *tv_now)
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (timeout == NULL) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* no timeouts. give it INT_MAX msecs. */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen tv->tv_sec = INT_MAX / 1000;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen tv->tv_usec = 0;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return INT_MAX;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (tv_now == NULL) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (gettimeofday(tv, NULL) < 0)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen i_fatal("gettimeofday(): %m");
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen } else {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen tv->tv_sec = tv_now->tv_sec;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila tv->tv_usec = tv_now->tv_usec;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen tv->tv_sec = timeout->next_run.tv_sec - tv->tv_sec;
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen tv->tv_usec = timeout->next_run.tv_usec - tv->tv_usec;
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen if (tv->tv_usec < 0) {
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen tv->tv_sec--;
2730605833442b5ddcb261f90b8375fc98201e35Timo Sirainen tv->tv_usec += 1000000;
2bb1ef0b669901fb91ff961e7fb074439ef769abTimo Sirainen }
2bb1ef0b669901fb91ff961e7fb074439ef769abTimo Sirainen
2bb1ef0b669901fb91ff961e7fb074439ef769abTimo Sirainen if (tv->tv_sec > 0 || (tv->tv_sec == 0 && tv->tv_usec > 0))
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return tv->tv_sec*1000 + tv->tv_usec/1000;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen /* no need to calculate the times again with this timeout */
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen tv->tv_sec = tv->tv_usec = 0;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout->run_now = TRUE;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila return 0;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila}
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainenvoid io_loop_handle_timeouts(struct ioloop *ioloop)
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila{
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct timeout *t, **t_p;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen struct timeval tv;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen unsigned int t_id;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila i_fatal("gettimeofday(): %m");
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila ioloop_time = ioloop_timeval.tv_sec;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (ioloop->timeouts == NULL || !ioloop->timeouts->run_now)
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen return;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila t_p = &ioloop->timeouts;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila for (t = ioloop->timeouts; t != NULL; t = *t_p) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (t->destroyed) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen timeout_destroy(ioloop, t_p);
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen continue;
3dc5a231160859c9627157dc53a94d5e4494fe9fTeemu Huovila }
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen t_p = &t->next;
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen if (!t->run_now) {
c865b0e9c65fd77f7b2ab6f8616d3def5501ecb3Timo Sirainen io_loop_get_wait_time(t, &tv, &ioloop_timeval);
if (!t->run_now)
break;
}
t->run_now = FALSE;
timeout_update_next(t, &ioloop_timeval);
t_id = t_push();
t->callback(t->context);
if (t_pop() != t_id)
i_panic("Leaked a t_pop() call!");
}
}
void io_loop_run(struct ioloop *ioloop)
{
ioloop->running = TRUE;
while (ioloop->running)
io_loop_handler_run(ioloop);
}
void io_loop_stop(struct ioloop *ioloop)
{
ioloop->running = FALSE;
}
void io_loop_set_running(struct ioloop *ioloop)
{
ioloop->running = TRUE;
}
int io_loop_is_running(struct ioloop *ioloop)
{
return ioloop->running;
}
struct ioloop *io_loop_create(pool_t pool)
{
struct ioloop *ioloop;
/* initialize time */
if (gettimeofday(&ioloop_timeval, &ioloop_timezone) < 0)
i_fatal("gettimeofday(): %m");
ioloop_time = ioloop_timeval.tv_sec;
ioloop = p_new(pool, struct ioloop, 1);
pool_ref(pool);
ioloop->pool = pool;
io_loop_handler_init(ioloop);
ioloop->prev = current_ioloop;
current_ioloop = ioloop;
return ioloop;
}
void io_loop_destroy(struct ioloop *ioloop)
{
pool_t pool;
while (ioloop->ios != NULL) {
struct io *io = ioloop->ios;
i_warning("I/O leak: %p (%d)", (void *)io->callback, io->fd);
io_remove(io);
}
while (ioloop->timeouts != NULL) {
struct timeout *to = ioloop->timeouts;
if (!to->destroyed) {
i_warning("Timeout leak: %p", (void *)to->callback);
timeout_remove(to);
}
timeout_destroy(ioloop, &ioloop->timeouts);
}
io_loop_handler_deinit(ioloop);
/* ->prev won't work unless loops are destroyed in create order */
i_assert(ioloop == current_ioloop);
current_ioloop = current_ioloop->prev;
pool = ioloop->pool;
p_free(pool, ioloop);
pool_unref(pool);
}