ioloop.c revision ae800c8a965688ab17415397dbc759a429e78199
a8c5a86d183db25a57bf193c06b41e092ec2e151Timo Sirainen/* Copyright (c) 2002-2011 Dovecot authors, see the included COPYING file */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "lib.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "array.h"
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen#include "time-util.h"
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen#include "ioloop-internal.h"
0536ccb51d41e3078c3a9fa33e509fb4b2420f95Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include <unistd.h>
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen#define timer_is_larger(tvp, uvp) \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen ((tvp)->tv_sec > (uvp)->tv_sec || \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen ((tvp)->tv_sec == (uvp)->tv_sec && \
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen (tvp)->tv_usec > (uvp)->tv_usec))
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainentime_t ioloop_time = 0;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstruct timeval ioloop_timeval;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstruct ioloop *current_ioloop = NULL;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainenstatic void io_loop_initialize_handler(struct ioloop *ioloop)
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen{
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen unsigned int initial_fd_count;
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen
8cb72c59d5ea4e9e5f638d7ec840bb853f5a188eTimo Sirainen initial_fd_count = ioloop->max_fd_count > 0 &&
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen ioloop->max_fd_count < IOLOOP_INITIAL_FD_COUNT ?
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen ioloop->max_fd_count : IOLOOP_INITIAL_FD_COUNT;
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen io_loop_handler_init(ioloop, initial_fd_count);
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen}
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen#undef io_add
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainenstruct io *io_add(int fd, enum io_condition condition,
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen io_callback_t *callback, void *context)
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen{
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen struct io_file *io;
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen i_assert(fd >= 0);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_assert(callback != NULL);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen i_assert((condition & IO_NOTIFY) == 0);
cd56a23e21f1df3f79648cf07e2f4385e2fadebbTimo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen io = i_new(struct io_file, 1);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io->io.condition = condition;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen io->io.callback = callback;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io->io.context = context;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io->io.ioloop = current_ioloop;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io->refcount = 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io->fd = fd;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (io->io.ioloop->cur_ctx != NULL) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen io->io.ctx = io->io.ioloop->cur_ctx;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen io_loop_context_ref(io->io.ctx);
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (io->io.ioloop->handler_context == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_loop_initialize_handler(io->io.ioloop);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_loop_handle_add(io);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (io->io.ioloop->io_files != NULL) {
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen io->io.ioloop->io_files->prev = io;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen io->next = io->io.ioloop->io_files;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen }
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen io->io.ioloop->io_files = io;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen return &io->io;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen}
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic void io_file_unlink(struct io_file *io)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen{
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (io->prev != NULL)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen io->prev->next = io->next;
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen else
5ac0b0bf32898c63da086ae169674ecac151a31eTimo Sirainen io->io.ioloop->io_files = io->next;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen if (io->next != NULL)
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen io->next->prev = io->prev;
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen /* if we got here from an I/O handler callback, make sure we
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen don't try to handle this one next. */
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen if (io->io.ioloop->next_io_file == io)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen io->io.ioloop->next_io_file = io->next;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen}
df831edaa3b3aa22e03bc5fd416a0553c5600a69Phil Carmody
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainenstatic void io_remove_full(struct io **_io, bool closed)
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen{
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen struct io *io = *_io;
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen
1a0ece3e873e3864269ed7eaed957dc10c56d25fTimo Sirainen i_assert(io->callback != NULL);
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen
c28f6aa0b70af4811c9ace9114fe827c2f503455Timo Sirainen *_io = NULL;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* make sure the callback doesn't get called anymore.
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen kqueue code relies on this. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io->callback = NULL;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (io->ctx != NULL)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_loop_context_unref(&io->ctx);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen if ((io->condition & IO_NOTIFY) != 0)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen io_loop_notify_remove(io);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen else {
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen struct io_file *io_file = (struct io_file *)io;
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen io_file_unlink(io_file);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen io_loop_handle_remove(io_file, closed);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen }
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenvoid io_remove(struct io **io)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen io_remove_full(io, FALSE);
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen}
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainenvoid io_remove_closed(struct io **io)
862ec874f9373e3e499e237d3b9f71fdf1413feeTimo Sirainen{
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_assert(((*io)->condition & IO_NOTIFY) == 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
e2ce8d4a6ac5d82a906178148453e7613fab9ba0Timo Sirainen io_remove_full(io, TRUE);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainenstatic void timeout_update_next(struct timeout *timeout, struct timeval *tv_now)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen{
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (tv_now == NULL) {
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen if (gettimeofday(&timeout->next_run, NULL) < 0)
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen i_fatal("gettimeofday(): %m");
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen } else {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen timeout->next_run.tv_sec = tv_now->tv_sec;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen timeout->next_run.tv_usec = tv_now->tv_usec;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen /* we don't want microsecond accuracy or this function will be
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen called all the time - millisecond is more than enough */
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen timeout->next_run.tv_usec -= timeout->next_run.tv_usec % 1000;
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen
0a49b316fc729e5d57268ffa63c7122ac73f994cTimo Sirainen timeout->next_run.tv_sec += timeout->msecs/1000;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen timeout->next_run.tv_usec += (timeout->msecs%1000)*1000;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (timeout->next_run.tv_usec > 1000000) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen timeout->next_run.tv_sec++;
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen timeout->next_run.tv_usec -= 1000000;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen#undef timeout_add
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstruct timeout *timeout_add(unsigned int msecs, timeout_callback_t *callback,
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen void *context)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen struct timeout *timeout;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen timeout = i_new(struct timeout, 1);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen timeout->msecs = msecs;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen timeout->ioloop = current_ioloop;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen timeout->callback = callback;
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen timeout->context = context;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (timeout->ioloop->cur_ctx != NULL) {
a2738cdb6d2733fb3e186331d68009421a19ea00Timo Sirainen timeout->ctx = timeout->ioloop->cur_ctx;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen io_loop_context_ref(timeout->ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen timeout_update_next(timeout, timeout->ioloop->running ?
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen NULL : &ioloop_timeval);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return timeout;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainenstatic void timeout_free(struct timeout *timeout)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen{
7af4788b402346c94496095dd819f95ce03fe431Timo Sirainen if (timeout->ctx != NULL)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen io_loop_context_unref(&timeout->ctx);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen i_free(timeout);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen}
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainenvoid timeout_remove(struct timeout **_timeout)
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen{
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen struct timeout *timeout = *_timeout;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen *_timeout = NULL;
d66ef20c30fee728899ee168c75fcc5ff8fbdac1Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen timeout_free(timeout);
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen}
c24ef531ca58abad996482f5c2e8992be9ae8981Timo Sirainen
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainenstatic void
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainentimeout_reset_timeval(struct timeout *timeout, struct timeval *tv_now)
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen{
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen timeout_update_next(timeout, tv_now);
0a0cd45a633112a2ae6aad801c1e6afe53ab95deTimo Sirainen if (timeout->msecs == 0) {
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen /* if we came here from io_loop_handle_timeouts(),
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen next_run must be larger than tv_now or we could go to
2524ef7b34965a1b1895d6140fd8296bf57c78d2Timo Sirainen infinite loop. +1000 to get 1 ms further, another +1000 to
0892446b45c195461bb7be6599f02d97e1e2c9b2Timo Sirainen account for timeout_update_next()'s truncation. */
e4c81823af1fc43ca3f2ce9eb4af7fc8f57b13a5Timo Sirainen timeout->next_run.tv_usec += 2000;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen if (timeout->next_run.tv_usec >= 1000000) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen timeout->next_run.tv_sec++;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen timeout->next_run.tv_usec -= 1000000;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(tv_now == NULL ||
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen timeout->next_run.tv_sec > tv_now->tv_sec ||
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen (timeout->next_run.tv_sec == tv_now->tv_sec &&
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen timeout->next_run.tv_usec > tv_now->tv_usec));
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainenvoid timeout_reset(struct timeout *timeout)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen timeout_reset_timeval(timeout, timeout->ioloop->running ? NULL :
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen &ioloop_timeval);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen}
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainenstatic int timeout_get_wait_time(struct timeout *timeout, struct timeval *tv_r,
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen struct timeval *tv_now)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen{
66dc739bb67d678770e1b7a7bc75f4f6f9523d2aTimo Sirainen int ret;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (tv_now->tv_sec == 0) {
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (gettimeofday(tv_now, NULL) < 0)
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_fatal("gettimeofday(): %m");
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen tv_r->tv_sec = tv_now->tv_sec;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen tv_r->tv_usec = tv_now->tv_usec;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(tv_r->tv_sec > 0);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen i_assert(timeout->next_run.tv_sec > 0);
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen tv_r->tv_sec = timeout->next_run.tv_sec - tv_r->tv_sec;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen tv_r->tv_usec = timeout->next_run.tv_usec - tv_r->tv_usec;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen if (tv_r->tv_usec < 0) {
c6b6ac7819931dfa92c0182ffaa7db07ac6ab0daTimo Sirainen tv_r->tv_sec--;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen tv_r->tv_usec += 1000000;
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen }
61e6367a259e2473f33df42fda8ceeb3b8b48416Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen if (tv_r->tv_sec < 0 || (tv_r->tv_sec == 0 && tv_r->tv_usec < 1000)) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen tv_r->tv_sec = 0;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen tv_r->tv_usec = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen if (tv_r->tv_sec > INT_MAX/1000-1)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen tv_r->tv_sec = INT_MAX/1000-1;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* round wait times up to next millisecond */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ret = tv_r->tv_sec * 1000 + (tv_r->tv_usec + 999) / 1000;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(ret > 0 && tv_r->tv_sec >= 0 && tv_r->tv_usec >= 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return ret;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenint io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
20344c0e814139e3c365fbb9287478f91512089eTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct timeval tv_now;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct priorityq_item *item;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen struct timeout *timeout;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen int msecs;
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen item = priorityq_peek(ioloop->timeouts);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen timeout = (struct timeout *)item;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (timeout == NULL) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen /* no timeouts. use INT_MAX msecs for timeval and
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return -1 for poll/epoll infinity. */
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen tv_r->tv_sec = INT_MAX / 1000;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen tv_r->tv_usec = 0;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen ioloop->next_max_time = (1ULL << (TIME_T_MAX_BITS-1)) - 1;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return -1;
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen tv_now.tv_sec = 0;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen msecs = timeout_get_wait_time(timeout, tv_r, &tv_now);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen ioloop->next_max_time = (tv_now.tv_sec + msecs/1000) + 1;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen return msecs;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int timeout_cmp(const void *p1, const void *p2)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const struct timeout *to1 = p1, *to2 = p2;
e3fc1874694a8ddba9552ec23f9952f74f33d1d5Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen return timeval_cmp(&to1->next_run, &to2->next_run);
601f5f14c6cde28f0e0c6ca7c5d735315d3d48dfTimo Sirainen}
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void io_loop_default_time_moved(time_t old_time, time_t new_time)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (old_time > new_time) {
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen i_warning("Time moved backwards by %ld seconds.",
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen (long)(old_time - new_time));
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen }
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainenstatic void io_loop_timeouts_update(struct ioloop *ioloop, long diff_secs)
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen{
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen struct priorityq_item *const *items;
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen unsigned int i, count;
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen count = priorityq_count(ioloop->timeouts);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen items = priorityq_items(ioloop->timeouts);
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen for (i = 0; i < count; i++) {
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen struct timeout *to = (struct timeout *)items[i];
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen to->next_run.tv_sec += diff_secs;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainenstatic void io_loops_timeouts_update(long diff_secs)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen{
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen struct ioloop *ioloop;
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen for (ioloop = current_ioloop; ioloop != NULL; ioloop = ioloop->prev)
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen io_loop_timeouts_update(ioloop, diff_secs);
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen}
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainenstatic void io_loop_handle_timeouts_real(struct ioloop *ioloop)
4334b9b032298defd4d3906f5357698ff016ead0Timo Sirainen{
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct priorityq_item *item;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen struct timeval tv, tv_call;
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen unsigned int t_id;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen i_fatal("gettimeofday(): %m");
c9bf63e9094761767a63ac6b189bcf60bcffdc44Timo Sirainen
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen /* Don't bother comparing usecs. */
548e394330621952db0f03dd667b70184c4a37b6Timo Sirainen if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) {
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen /* time moved backwards */
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen io_loops_timeouts_update(-(long)(ioloop_time -
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen ioloop_timeval.tv_sec));
01f4ee4a0243f3fe9af763e1a540cd5cff0d63f5Timo Sirainen ioloop->time_moved_callback(ioloop_time,
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen ioloop_timeval.tv_sec);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* the callback may have slept, so check the time again. */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen i_fatal("gettimeofday(): %m");
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen } else if (unlikely(ioloop_timeval.tv_sec >
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen ioloop->next_max_time)) {
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen io_loops_timeouts_update(ioloop_timeval.tv_sec -
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen ioloop->next_max_time);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen /* time moved forwards */
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen ioloop->time_moved_callback(ioloop->next_max_time,
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen ioloop_timeval.tv_sec);
4b9f99761df5014c659cd87fddaf6854af428cfcTimo Sirainen }
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen ioloop_time = ioloop_timeval.tv_sec;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen tv_call = ioloop_timeval;
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen
7e1f68ad71d3485f1882142837b01f7a98ca8467Timo Sirainen while ((item = priorityq_peek(ioloop->timeouts)) != NULL) {
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen struct timeout *timeout = (struct timeout *)item;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen /* use tv_call to make sure we don't get to infinite loop in
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen case callbacks update ioloop_timeval. */
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen if (timeout_get_wait_time(timeout, &tv, &tv_call) > 0)
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen break;
a3c197999dfe2b0c8ea38cb77cfa5e95026005c0Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen /* update timeout's next_run and reposition it in the queue */
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen timeout_reset_timeval(timeout, &tv_call);
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen if (timeout->ctx != NULL)
923115fd382904fa13bb09bf307bf2835b52df60Timo Sirainen io_loop_context_activate(timeout->ctx);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen t_id = t_push();
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen timeout->callback(timeout->context);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (t_pop() != t_id) {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen i_panic("Leaked a t_pop() call in timeout handler %p",
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen (void *)timeout->callback);
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (ioloop->cur_ctx != NULL)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen io_loop_context_activate(ioloop->cur_ctx);
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainenvoid io_loop_handle_timeouts(struct ioloop *ioloop)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen T_BEGIN {
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen io_loop_handle_timeouts_real(ioloop);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen } T_END;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainenvoid io_loop_call_io(struct io *io)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen{
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen struct ioloop *ioloop = io->ioloop;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen unsigned int t_id;
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (io->ctx != NULL)
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen io_loop_context_activate(io->ctx);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen t_id = t_push();
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen io->callback(io->context);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (t_pop() != t_id) {
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen i_panic("Leaked a t_pop() call in I/O handler %p",
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen (void *)io->callback);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen }
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen if (ioloop->cur_ctx != NULL)
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen io_loop_context_deactivate(ioloop->cur_ctx);
e0c3d5460d1cc0c440cb7723c8c2eef8d0afe9b9Timo Sirainen}
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid io_loop_run(struct ioloop *ioloop)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen{
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (ioloop->handler_context == NULL)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen io_loop_initialize_handler(ioloop);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen if (ioloop->cur_ctx != NULL)
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen io_loop_context_unref(&ioloop->cur_ctx);
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen ioloop->running = TRUE;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen while (ioloop->running)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_loop_handler_run(ioloop);
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen}
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid io_loop_stop(struct ioloop *ioloop)
7a77b948806106b46a33f3e6a3869657f49877fdTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ioloop->running = FALSE;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainenvoid io_loop_set_running(struct ioloop *ioloop)
b7651d283ca261015ef3c445f1f27f340f0864e2Timo Sirainen{
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen ioloop->running = TRUE;
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen}
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainenvoid io_loop_set_max_fd_count(struct ioloop *ioloop, unsigned int max_fds)
7b42d6cbee8186195d8c5e66078043a0fa1f25c1Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen ioloop->max_fd_count = max_fds;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainenbool io_loop_is_running(struct ioloop *ioloop)
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen{
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return ioloop->running;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen}
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainenstruct ioloop *io_loop_create(void)
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen{
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen struct ioloop *ioloop;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen /* initialize time */
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen i_fatal("gettimeofday(): %m");
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen ioloop_time = ioloop_timeval.tv_sec;
89c8d5f336e44cca091a1f588d51ba26e5145ad2Timo Sirainen
f20e7fbdc9bdbe8fecb9c661c9b8175f3bb78c69Timo Sirainen ioloop = i_new(struct ioloop, 1);
c0b1543512bc3e0a3a9f526056a3678a07ce32f5Timo Sirainen ioloop->timeouts = priorityq_init(timeout_cmp, 32);
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen ioloop->time_moved_callback = current_ioloop != NULL ?
51e1a1c280ccb461a15827f7987d09cb9708b6e3Timo Sirainen current_ioloop->time_moved_callback :
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen io_loop_default_time_moved;
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen
a0b6b441fc679e562e79be0fb2819ffc24ab5b74Timo Sirainen ioloop->prev = current_ioloop;
1036ad17ac837a451f6b045cac504d3efa2edb8eTimo Sirainen current_ioloop = ioloop;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen return ioloop;
89e195dfb5c4b0efd9b9f459771a4467674e5b1fTimo Sirainen}
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainenvoid io_loop_destroy(struct ioloop **_ioloop)
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen{
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen struct ioloop *ioloop = *_ioloop;
6f08b98ac63c25b747120d0c8f8e319b4e26ab0fTimo Sirainen struct priorityq_item *item;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen *_ioloop = NULL;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (ioloop->notify_handler_context != NULL)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen io_loop_notify_handler_deinit(ioloop);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen while (ioloop->io_files != NULL) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen struct io_file *io = ioloop->io_files;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen struct io *_io = &io->io;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i_warning("I/O leak: %p (%d)", (void *)io->io.callback, io->fd);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen io_remove(&_io);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen while ((item = priorityq_pop(ioloop->timeouts)) != NULL) {
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen struct timeout *to = (struct timeout *)item;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen i_warning("Timeout leak: %p", (void *)to->callback);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen timeout_free(to);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen }
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen priorityq_deinit(&ioloop->timeouts);
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ioloop->handler_context != NULL)
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen io_loop_handler_deinit(ioloop);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* ->prev won't work unless loops are destroyed in create order */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen i_assert(ioloop == current_ioloop);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen current_ioloop = current_ioloop->prev;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(ioloop);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenvoid io_loop_set_time_moved_callback(struct ioloop *ioloop,
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen io_loop_time_moved_callback_t *callback)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen ioloop->time_moved_callback = callback;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenvoid io_loop_set_current(struct ioloop *ioloop)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen current_ioloop = ioloop;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainenstruct ioloop_context *io_loop_context_new(struct ioloop *ioloop)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen{
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen struct ioloop_context *ctx;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen ctx = i_new(struct ioloop_context, 1);
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen ctx->refcount = 2;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen ctx->ioloop = ioloop;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen i_array_init(&ctx->callbacks, 4);
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen if (ioloop->cur_ctx != NULL)
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen io_loop_context_unref(&ioloop->cur_ctx);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen ioloop->cur_ctx = ctx;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return ctx;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenvoid io_loop_context_ref(struct ioloop_context *ctx)
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen{
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen i_assert(ctx->refcount > 0);
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen ctx->refcount++;
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen}
f5982bb5b0a704e88fa2b44b0b74e365d13103b9Timo Sirainen
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainenvoid io_loop_context_unref(struct ioloop_context **_ctx)
3785910c303507db5f629684e6dde2cc7f83668eTimo Sirainen{
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen struct ioloop_context *ctx = *_ctx;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen *_ctx = NULL;
4106a25399703eb6cbb166dcbd5bb932cb2f7ad2Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(ctx->refcount > 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (--ctx->refcount > 0)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* cur_ctx itself keeps a reference */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(ctx->ioloop->cur_ctx != ctx);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen array_free(&ctx->callbacks);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_free(ctx);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainenvoid io_loop_context_add_callbacks(struct ioloop_context *ctx,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_callback_t *activate,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_callback_t *deactivate, void *context)
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct ioloop_context_callback cb;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen memset(&cb, 0, sizeof(cb));
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen cb.activate = activate;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen cb.deactivate = deactivate;
37ab3cde96bfa4bc5304c0c348fc420aec79572dTimo Sirainen cb.context = context;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
f4bbeadda12fbd7c219063db68f3e78646d83c2cTimo Sirainen array_append(&ctx->callbacks, &cb, 1);
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen}
0b47e9f5e0181053b4d9ca7b426b0e5c185e820eTimo Sirainen
abe8754852e70763e92f74caabbcc13d0917714cTimo Sirainenvoid io_loop_context_remove_callbacks(struct ioloop_context *ctx,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen io_callback_t *activate,
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen io_callback_t *deactivate, void *context)
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen{
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen struct ioloop_context_callback *cb;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen array_foreach_modifiable(&ctx->callbacks, cb) {
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen if (cb->context == context &&
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen cb->activate == activate && cb->deactivate == deactivate) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen /* simply mark it as deleted, since we could get
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen here from activate/deactivate loop */
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen cb->activate = NULL;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen cb->deactivate = NULL;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen cb->context = NULL;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen return;
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen }
c09f9f95db314e7482c95e502e1c56ed6c555797Timo Sirainen i_panic("io_loop_context_remove_callbacks() context not found");
90b8f131849540fa374aede95edd86d47d35c09dTimo Sirainen}
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenio_loop_context_remove_deleted_callbacks(struct ioloop_context *ctx)
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen{
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen const struct ioloop_context_callback *cbs;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen unsigned int i, count;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen cbs = array_get(&ctx->callbacks, &count);
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen for (i = 0; i < count; ) {
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen if (cbs[i].activate != NULL)
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen i++;
904f9d5654b9c39edcdf32883e5e88771faf4d69Timo Sirainen else {
252db51b6c0a605163326b3ea5d09e9936ca3b29Timo Sirainen array_delete(&ctx->callbacks, i, 1);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen cbs = array_get(&ctx->callbacks, &count);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen}
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainenvoid io_loop_context_activate(struct ioloop_context *ctx)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen{
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen const struct ioloop_context_callback *cb;
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen
7662010b03ffe5f2a6ecf4b4eb220d1c65efea76Timo Sirainen ctx->ioloop->cur_ctx = ctx;
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen io_loop_context_ref(ctx);
fe363b433b8038a69b55169da9dca27892ad7d18Timo Sirainen array_foreach(&ctx->callbacks, cb) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (cb->activate != NULL)
97e62b2b36dda0acb3215667042f5c80cdee8155Timo Sirainen cb->activate(cb->context);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen}
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainenvoid io_loop_context_deactivate(struct ioloop_context *ctx)
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen{
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen const struct ioloop_context_callback *cb;
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen array_foreach(&ctx->callbacks, cb) {
7d5d50dd9a8c2539d7025a69e39d34fca56daeafTimo Sirainen if (cb->deactivate != NULL)
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen cb->deactivate(cb->context);
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen ctx->ioloop->cur_ctx = NULL;
dd2df6a67f10792ce31a3666197c0b6885893a3aTimo Sirainen io_loop_context_remove_deleted_callbacks(ctx);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen io_loop_context_unref(&ctx);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen}
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainenstruct io *io_loop_move_io(struct io **_io)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen{
14175321ddb88619015866978c05a27786ca4814Timo Sirainen struct io *new_io, *old_io = *_io;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen struct io_file *old_io_file;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen i_assert((old_io->condition & IO_NOTIFY) == 0);
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen if (old_io->ioloop == current_ioloop)
14175321ddb88619015866978c05a27786ca4814Timo Sirainen return old_io;
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainen old_io_file = (struct io_file *)old_io;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen new_io = io_add(old_io_file->fd, old_io->condition,
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen old_io->callback, old_io->context);
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen io_remove(_io);
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen return new_io;
439dd06aec3301e65d650f6dc1d4a1a00b356b4fTimo Sirainen}
14175321ddb88619015866978c05a27786ca4814Timo Sirainen
14175321ddb88619015866978c05a27786ca4814Timo Sirainenstruct timeout *io_loop_move_timeout(struct timeout **_timeout)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen{
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen struct timeout *new_to, *old_to = *_timeout;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen if (old_to->ioloop == current_ioloop)
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen return old_to;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen new_to = timeout_add(old_to->msecs, old_to->callback, old_to->context);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen timeout_remove(_timeout);
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen return new_to;
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen}
c7acd38cd4ef76a0f4652f9ca659ea5e64458b52Timo Sirainen