ioloop.c revision a3e4bc66fc6501374fdaa3ebb5a9e676756d0726
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch/*
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ioloop.c : I/O loop
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Copyright (c) 2002 Timo Sirainen
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch Permission is hereby granted, free of charge, to any person obtaining
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch a copy of this software and associated documentation files (the
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch "Software"), to deal in the Software without restriction, including
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch without limitation the rights to use, copy, modify, merge, publish,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch distribute, sublicense, and/or sell copies of the Software, and to
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch permit persons to whom the Software is furnished to do so, subject to
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch the following conditions:
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch The above copyright notice and this permission notice shall be
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch included in all copies or substantial portions of the Software.
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch*/
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch/* FIXME: inserting io is slow if there's lots of them. I should add a linked
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch list of priorities pointing to first item in the list with the priority. */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch#include "lib.h"
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch#include "ioloop-internal.h"
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch#undef timercmp
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch#define timercmp(tvp, uvp) \
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ((tvp)->tv_sec > (uvp)->tv_sec || \
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ((tvp)->tv_sec == (uvp)->tv_sec && \
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch (tvp)->tv_usec > (uvp)->tv_usec))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschtime_t ioloop_time = 0;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstruct timeval ioloop_timeval;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstruct timezone ioloop_timezone;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic struct ioloop *current_ioloop = NULL;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic void update_highest_fd(struct ioloop *ioloop)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct io *io;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch int max_highest_fd;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch max_highest_fd = ioloop->highest_fd-1;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ioloop->highest_fd = -1;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (io = ioloop->ios; io != NULL; io = io->next) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (!io->destroyed && io->fd > ioloop->highest_fd) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ioloop->highest_fd = io->fd;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (ioloop->highest_fd == max_highest_fd)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch break;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic void io_list_insert(struct ioloop *ioloop, struct io *io)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct io *prev, *next;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch prev = NULL;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (next = ioloop->ios; next != NULL; next = next->next) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (next->priority >= io->priority)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch break;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch prev = next;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (prev == NULL)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ioloop->ios = io;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch else {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->prev = prev;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch prev->next = io;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (next != NULL) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->next = next;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch next->prev = io;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstruct io *io_add(int fd, int condition, io_callback_t callback, void *data)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch return io_add_priority(fd, IO_PRIORITY_DEFAULT,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch condition, callback, data);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstruct io *io_add_priority(int fd, int priority, int condition,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io_callback_t callback, void *context)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct io *io;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch i_assert(fd >= 0);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch i_assert(callback != NULL);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io = p_new(current_ioloop->pool, struct io, 1);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->fd = fd;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->priority = priority;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->condition = condition;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->callback = callback;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->context = context;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (io->fd > current_ioloop->highest_fd)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch current_ioloop->highest_fd = io->fd;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io_loop_handle_add(current_ioloop, io->fd, io->condition);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io_list_insert(current_ioloop, io);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch return io;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschvoid io_remove(struct io *io)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch i_assert(io != NULL);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch i_assert(io->fd >= 0);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch i_assert(io->fd <= current_ioloop->highest_fd);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* notify the real I/O handler */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io_loop_handle_remove(current_ioloop, io->fd, io->condition);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* check if we removed the highest fd */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (io->fd == current_ioloop->highest_fd)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch update_highest_fd(current_ioloop);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->destroyed = TRUE;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->fd = -1;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschvoid io_destroy(struct ioloop *ioloop, struct io *io)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* remove from list */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (io->prev == NULL)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch ioloop->ios = io->next;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch else
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->prev->next = io->next;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (io->next != NULL)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch io->next->prev = io->prev;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch p_free(ioloop->pool, io);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstatic void timeout_list_insert(struct ioloop *ioloop, struct timeout *timeout)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct timeout **t;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct timeval *next_run;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch next_run = &timeout->next_run;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (t = &ioloop->timeouts; *t != NULL; t = &(*t)->next) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (timercmp(&(*t)->next_run, next_run))
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch break;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next = *t;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch *t = timeout;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschinline static void
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschtimeout_update_next(struct timeout *timeout, struct timeval *tv_now)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (tv_now == NULL)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch gettimeofday(&timeout->next_run, NULL);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch else {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_sec = tv_now->tv_sec;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_usec = tv_now->tv_usec;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch /* we don't want microsecond accuracy or this function will be
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch called all the time - millisecond is more than enough */
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_usec /= 1000;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_usec *= 1000;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_sec += timeout->msecs/1000;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_usec += (timeout->msecs%1000)*1000;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (timeout->next_run.tv_usec > 1000000) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_sec++;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->next_run.tv_usec -= 1000000;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschstruct timeout *timeout_add(int msecs, timeout_callback_t callback,
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch void *context)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct timeout *timeout;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout = p_new(current_ioloop->pool, struct timeout, 1);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->msecs = msecs;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->callback = callback;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->context = context;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout_update_next(timeout, current_ioloop->running ?
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch NULL : &ioloop_timeval);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout_list_insert(current_ioloop, timeout);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch return timeout;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschvoid timeout_remove(struct timeout *timeout)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch i_assert(timeout != NULL);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch timeout->destroyed = TRUE;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschvoid timeout_destroy(struct ioloop *ioloop, struct timeout *timeout)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch{
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch struct timeout **t;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch for (t = &ioloop->timeouts; *t != NULL; t = &(*t)->next) {
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch if (*t == timeout)
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch break;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch }
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch *t = timeout->next;
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch p_free(ioloop->pool, timeout);
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch}
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Bosch
1bd20e2a575473f3d05499f05f1d72da59b34fd6Stephan Boschint io_loop_get_wait_time(struct timeout *timeout, struct timeval *tv,
struct timeval *tv_now)
{
if (timeout == NULL)
return INT_MAX;
if (tv_now == NULL)
gettimeofday(tv, NULL);
else {
tv->tv_sec = tv_now->tv_sec;
tv->tv_usec = tv_now->tv_usec;
}
tv->tv_sec = timeout->next_run.tv_sec - tv->tv_sec;
tv->tv_usec = timeout->next_run.tv_usec - tv->tv_usec;
if (tv->tv_usec < 0) {
tv->tv_sec--;
tv->tv_usec += 1000000;
}
if (tv->tv_sec > 0 || (tv->tv_sec == 0 && tv->tv_usec > 0))
return tv->tv_sec*1000 + tv->tv_usec/1000;
/* no need to calculate the times again with this timeout */
tv->tv_sec = tv->tv_usec = 0;
timeout->run_now = TRUE;
return 0;
}
void io_loop_handle_timeouts(struct ioloop *ioloop)
{
struct timeout *t, *next;
struct timeval tv;
unsigned int t_id;
gettimeofday(&ioloop_timeval, &ioloop_timezone);
ioloop_time = ioloop_timeval.tv_sec;
if (ioloop->timeouts == NULL || !ioloop->timeouts->run_now)
return;
for (t = ioloop->timeouts; t != NULL; t = next) {
next = t->next;
if (t->destroyed) {
timeout_destroy(ioloop, t);
continue;
}
if (!t->run_now) {
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, t);
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 */
gettimeofday(&ioloop_timeval, &ioloop_timezone);
ioloop_time = ioloop_timeval.tv_sec;
ioloop = p_new(pool, struct ioloop, 1);
pool_ref(pool);
ioloop->pool = pool;
ioloop->highest_fd = -1;
io_loop_handler_init(ioloop);
ioloop->prev = current_ioloop;
current_ioloop = ioloop;
return ioloop;
}
void io_loop_destroy(struct ioloop *ioloop)
{
while (ioloop->ios != NULL) {
struct io *io = ioloop->ios;
if (!io->destroyed) {
i_warning("I/O leak: %p (%d)",
(void *) io->callback, io->fd);
io_remove(io);
}
io_destroy(ioloop, 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, to);
}
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_unref(ioloop->pool);
}