ioloop.c revision 3809334f938c69df473f154978204e9044840c0b
89a126810703c666309310d0f3189e9834d70b5bTimo Sirainen/* Copyright (c) 2002-2016 Dovecot authors, see the included COPYING file */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen#include "array.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "time-util.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-private.h"
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#include "ioloop-private.h"
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include <unistd.h>
89b548af722113acb5d63dfffb44423cb60f91e4Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen#define timer_is_larger(tvp, uvp) \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((tvp)->tv_sec > (uvp)->tv_sec || \
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ((tvp)->tv_sec == (uvp)->tv_sec && \
66ae183b6e895216037bd921367670f4b0665911Timo Sirainen (tvp)->tv_usec > (uvp)->tv_usec))
e86d0d34fe365da4c7ca4312d575bfcbf3a01c0eTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainentime_t ioloop_time = 0;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainenstruct timeval ioloop_timeval;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct ioloop *current_ioloop = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenuint64_t ioloop_global_wait_usecs = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic ARRAY(io_switch_callback_t *) io_switch_callbacks = ARRAY_INIT;
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainen
31ddc75584c5cde53d2e78a737587f2e7fdcb0d2Timo Sirainenstatic void io_loop_initialize_handler(struct ioloop *ioloop)
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen{
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen unsigned int initial_fd_count;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen initial_fd_count = ioloop->max_fd_count > 0 &&
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->max_fd_count < IOLOOP_INITIAL_FD_COUNT ?
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->max_fd_count : IOLOOP_INITIAL_FD_COUNT;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_handler_init(ioloop, initial_fd_count);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic struct io_file *
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainenio_add_file(int fd, enum io_condition condition,
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen const char *source_filename,
8fa41238067c854435884c459963fde6f8c6436bTimo Sirainen unsigned int source_linenum,
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen io_callback_t *callback, void *context)
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen{
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen struct io_file *io;
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen
d6badc27cd6e8d3398877b6766cb0aaeef3a7800Timo Sirainen i_assert(callback != NULL);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert((condition & IO_NOTIFY) == 0);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen io = i_new(struct io_file, 1);
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen io->io.condition = condition;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen io->io.callback = callback;
41e1c7380edda701719d8ce1fb4d465d2ec4c84dTimo Sirainen io->io.context = context;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen io->io.ioloop = current_ioloop;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io->io.source_filename = source_filename;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io->io.source_linenum = source_linenum;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io->refcount = 1;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen io->fd = fd;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (io->io.ioloop->cur_ctx != NULL) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io->io.ctx = io->io.ioloop->cur_ctx;
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_loop_context_ref(io->io.ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen if (io->io.ioloop->handler_context == NULL)
d5cebe7f98e63d4e2822863ef2faa4971e8b3a5dTimo Sirainen io_loop_initialize_handler(io->io.ioloop);
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen if (fd != -1)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io_loop_handle_add(io);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen else {
ba00293b85c7fb4e7a2d100991c716e17b9daaaeTimo Sirainen /* we're adding an istream whose only way to get notified
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen is to call i_stream_set_input_pending() */
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen }
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen if (io->io.ioloop->io_files != NULL) {
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io->io.ioloop->io_files->prev = io;
46c31f64b9f0949f00b7819f45b22f2d64b2ea27Timo Sirainen io->next = io->io.ioloop->io_files;
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io->io.ioloop->io_files = io;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return io;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#undef io_add
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstruct io *io_add(int fd, enum io_condition condition,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen const char *source_filename,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen unsigned int source_linenum,
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen io_callback_t *callback, void *context)
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen{
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen struct io_file *io;
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen
20a802016205bbcafc90f164f769ea801f88d014Timo Sirainen i_assert(fd >= 0);
7797aa2479e99aeb71057b7a2584b2cb72e4d3f8Timo Sirainen io = io_add_file(fd, condition, source_filename, source_linenum, callback, context);
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen return &io->io;
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen}
bbf796c17f02538058d7559bfe96d677e5b55015Timo Sirainen
8e7da21696c9f8a6d5e601243fb6172ec85d47b2Timo Sirainen#undef io_add_istream
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstruct io *io_add_istream(struct istream *input, const char *source_filename,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen unsigned int source_linenum,
024815ea2ffdda9ea79919f18e865663977f73eaTimo Sirainen io_callback_t *callback, void *context)
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen{
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen struct io_file *io;
ffd9a1898a18fadfc5dce399162c25d50548f905Timo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen io = io_add_file(i_stream_get_fd(input), IO_READ, source_filename,
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen source_linenum, callback, context);
1175f27441385a7011629f295f42708f9a3a4ffcTimo Sirainen io->istream = input;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen i_stream_ref(io->istream);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen i_stream_set_io(io->istream, &io->io);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen return &io->io;
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenstatic void io_file_unlink(struct io_file *io)
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen{
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen if (io->prev != NULL)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen io->prev->next = io->next;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen else
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen io->io.ioloop->io_files = io->next;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (io->next != NULL)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen io->next->prev = io->prev;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen /* if we got here from an I/O handler callback, make sure we
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen don't try to handle this one next. */
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen if (io->io.ioloop->next_io_file == io)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen io->io.ioloop->next_io_file = io->next;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen}
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainenstatic void io_remove_full(struct io **_io, bool closed)
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen{
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen struct io *io = *_io;
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen i_assert(io->callback != NULL);
c5454841b5067a22827556ca9bc7935d190f57baTimo Sirainen
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen *_io = NULL;
5a07b37a9df398b5189c14872a600384208ab74bTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* make sure the callback doesn't get called anymore.
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen kqueue code relies on this. */
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen io->callback = NULL;
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (io->pending) {
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen i_assert(io->ioloop->io_pending_count > 0);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen io->ioloop->io_pending_count--;
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen }
7d7b5c98f086ffa8ac9c90f21db17748ca607202Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (io->ctx != NULL)
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen io_loop_context_unref(&io->ctx);
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen
da985034a708db2f61394b30d117050ae6829ee5Timo Sirainen if ((io->condition & IO_NOTIFY) != 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen io_loop_notify_remove(io);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen else {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen struct io_file *io_file = (struct io_file *)io;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen struct istream *istream = io_file->istream;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen if (istream != NULL) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* remove io before it's freed */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_stream_unset_io(istream, io);
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
de12ff295bb3d0873b4dced5840612cbacd635efTimo Sirainen io_file_unlink(io_file);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen if (io_file->fd != -1)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen io_loop_handle_remove(io_file, closed);
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen else
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen i_free(io);
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen /* remove io from the ioloop before unreferencing the istream,
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen because a destroyed istream may automatically close the
5626ae5e3316eced244adb6485c0927f1c7fdc41Timo Sirainen fd. */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen if (istream != NULL)
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen i_stream_unref(&istream);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainenvoid io_remove(struct io **io)
6a19e109ee8c5a6f688da83a86a7f6abeb71abddTimo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen io_remove_full(io, FALSE);
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainenvoid io_remove_closed(struct io **io)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_assert(((*io)->condition & IO_NOTIFY) == 0);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen io_remove_full(io, TRUE);
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen}
c27f03fa8fd2ef4acd1db814fae7d90e0eb9d3aeTimo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenvoid io_set_pending(struct io *io)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen i_assert((io->condition & IO_NOTIFY) == 0);
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen if (!io->pending) {
287ba82a8da3eaa473b5735d4eeac2fb4c5d8117Timo Sirainen io->pending = TRUE;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen io->ioloop->io_pending_count++;
f23298fea47eecbeded985ee2537a34c4c4ef56bTimo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen}
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainenstatic void timeout_update_next(struct timeout *timeout, struct timeval *tv_now)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen{
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (tv_now == NULL) {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen if (gettimeofday(&timeout->next_run, NULL) < 0)
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen i_fatal("gettimeofday(): %m");
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen } else {
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen timeout->next_run.tv_sec = tv_now->tv_sec;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen timeout->next_run.tv_usec = tv_now->tv_usec;
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen }
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen /* we don't want microsecond accuracy or this function will be
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen called all the time - millisecond is more than enough */
519e0a461271843833a2b42626ad93f6e7ddc497Timo Sirainen timeout->next_run.tv_usec -= timeout->next_run.tv_usec % 1000;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->next_run.tv_sec += timeout->msecs/1000;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen timeout->next_run.tv_usec += (timeout->msecs%1000)*1000;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen if (timeout->next_run.tv_usec > 1000000) {
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen timeout->next_run.tv_sec++;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen timeout->next_run.tv_usec -= 1000000;
6a04c5112961c5f4fb2d2f25192b3dc424d62ad0Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstatic struct timeout *
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainentimeout_add_common(const char *source_filename, unsigned int source_linenum,
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen timeout_callback_t *callback, void *context)
6825360d446542046757b06064282301c4c6b27cTimo Sirainen{
6825360d446542046757b06064282301c4c6b27cTimo Sirainen struct timeout *timeout;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout = i_new(struct timeout, 1);
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->item.idx = UINT_MAX;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->source_filename = source_filename;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->source_linenum = source_linenum;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->ioloop = current_ioloop;
6825360d446542046757b06064282301c4c6b27cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->callback = callback;
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen timeout->context = context;
c8d093d149253fe8faec267c5057f45fe626f84cTimo Sirainen
6825360d446542046757b06064282301c4c6b27cTimo Sirainen if (timeout->ioloop->cur_ctx != NULL) {
6825360d446542046757b06064282301c4c6b27cTimo Sirainen timeout->ctx = timeout->ioloop->cur_ctx;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen io_loop_context_ref(timeout->ctx);
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen }
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen return timeout;
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen}
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen#undef timeout_add
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainenstruct timeout *timeout_add(unsigned int msecs, const char *source_filename,
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen unsigned int source_linenum,
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen timeout_callback_t *callback, void *context)
bb10ebcf076c959c752f583746d83805d7686df8Timo Sirainen{
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen struct timeout *timeout;
16c89b1260c9d07c01c83a9219424d3727069b2eTimo Sirainen
2a34e2be33f8a17d21384a5527ed9f75f4d270e0Timo Sirainen timeout = timeout_add_common(source_filename, source_linenum, callback, context);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen timeout->msecs = msecs;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (msecs > 0) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen /* start this timeout in the next run cycle */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen array_append(&timeout->ioloop->timeouts_new, &timeout, 1);
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen } else {
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen /* trigger zero timeouts as soon as possible */
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen timeout_update_next(timeout, timeout->ioloop->running ?
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen NULL : &ioloop_timeval);
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen }
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return timeout;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen}
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen#undef timeout_add_short
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenstruct timeout *
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainentimeout_add_short(unsigned int msecs, const char *source_filename,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen unsigned int source_linenum,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen timeout_callback_t *callback, void *context)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen return timeout_add(msecs, source_filename, source_linenum, callback, context);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen#undef timeout_add_absolute
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenstruct timeout *
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainentimeout_add_absolute(const struct timeval *time,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen const char *source_filename,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen unsigned int source_linenum,
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen timeout_callback_t *callback, void *context)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen struct timeout *timeout;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen timeout = timeout_add_common(source_filename, source_linenum,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen callback, context);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen timeout->one_shot = TRUE;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen timeout->next_run = *time;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
3697080532ccd9f51fac108be6079b616c7a2ddfTimo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen return timeout;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainenstatic struct timeout *
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainentimeout_copy(const struct timeout *old_to)
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen{
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen struct timeout *new_to;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen new_to = timeout_add_common
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen (old_to->source_filename, old_to->source_linenum,
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen old_to->callback, old_to->context);
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen new_to->one_shot = old_to->one_shot;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_to->msecs = old_to->msecs;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen new_to->next_run = old_to->next_run;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (old_to->item.idx != UINT_MAX)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen priorityq_add(new_to->ioloop->timeouts, &new_to->item);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (!new_to->one_shot) {
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen i_assert(new_to->msecs > 0);
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen array_append(&new_to->ioloop->timeouts_new, &new_to, 1);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen return new_to;
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void timeout_free(struct timeout *timeout)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
d22390f33eedbd2413debabc0662dde5241b1aa6Timo Sirainen if (timeout->ctx != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_context_unref(&timeout->ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_free(timeout);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid timeout_remove(struct timeout **_timeout)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct timeout *timeout = *_timeout;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen struct ioloop *ioloop = timeout->ioloop;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen *_timeout = NULL;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (timeout->item.idx != UINT_MAX)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen else if (!timeout->one_shot && timeout->msecs > 0) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct timeout *const *to_idx;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen array_foreach(&ioloop->timeouts_new, to_idx) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (*to_idx == timeout) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen array_delete(&ioloop->timeouts_new,
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen array_foreach_idx(&ioloop->timeouts_new, to_idx), 1);
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen break;
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen }
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen }
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen }
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen timeout_free(timeout);
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen}
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainenstatic void ATTR_NULL(2)
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainentimeout_reset_timeval(struct timeout *timeout, struct timeval *tv_now)
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen{
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen if (timeout->item.idx == UINT_MAX)
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen return;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen timeout_update_next(timeout, tv_now);
95a284736b8b11319a3f575ba249ba2eb7dbac1bTimo Sirainen if (timeout->msecs <= 1) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen /* if we came here from io_loop_handle_timeouts(),
2d49f150b4bce6f2f59a84e268e4777901c3e42cTimo Sirainen next_run must be larger than tv_now or we could go to
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen infinite loop. +1000 to get 1 ms further, another +1000 to
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen account for timeout_update_next()'s truncation. */
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen timeout->next_run.tv_usec += 2000;
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen if (timeout->next_run.tv_usec >= 1000000) {
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen timeout->next_run.tv_sec++;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen timeout->next_run.tv_usec -= 1000000;
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen }
0b49cfeae91a4020a404714b11c99e8e955fb631Timo Sirainen }
af1e2b2ab5d1c5ca5afe482ef8c8161c17acc190Timo Sirainen i_assert(tv_now == NULL ||
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen timeout->next_run.tv_sec > tv_now->tv_sec ||
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen (timeout->next_run.tv_sec == tv_now->tv_sec &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen timeout->next_run.tv_usec > tv_now->tv_usec));
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen}
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenvoid timeout_reset(struct timeout *timeout)
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen{
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen i_assert(!timeout->one_shot);
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen timeout_reset_timeval(timeout, NULL);
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen}
f239eb76f77afcbc0bfc97c9b52b4407d1bc3fe6Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainenstatic int timeout_get_wait_time(struct timeout *timeout, struct timeval *tv_r,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct timeval *tv_now)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
a53cb86b4d733d9c48ee4d285bed477c80825804Timo Sirainen int ret;
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (tv_now->tv_sec == 0) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (gettimeofday(tv_now, NULL) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("gettimeofday(): %m");
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen }
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen tv_r->tv_sec = tv_now->tv_sec;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen tv_r->tv_usec = tv_now->tv_usec;
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen i_assert(tv_r->tv_sec > 0);
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen i_assert(timeout->next_run.tv_sec > 0);
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen tv_r->tv_sec = timeout->next_run.tv_sec - tv_r->tv_sec;
99e8698f598d2b83da7c581584a538c0713fd11dTimo Sirainen tv_r->tv_usec = timeout->next_run.tv_usec - tv_r->tv_usec;
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen if (tv_r->tv_usec < 0) {
0c27b881989bc2b391281650ee89a8cc4d89f5e7Timo Sirainen tv_r->tv_sec--;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tv_r->tv_usec += 1000000;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen }
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (tv_r->tv_sec < 0 || (tv_r->tv_sec == 0 && tv_r->tv_usec < 1000)) {
ee246b46953e4b94b2f22e093373674fa9155500Timo Sirainen tv_r->tv_sec = 0;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen tv_r->tv_usec = 0;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return 0;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen }
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if (tv_r->tv_sec > INT_MAX/1000-1)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tv_r->tv_sec = INT_MAX/1000-1;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* round wait times up to next millisecond */
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen ret = tv_r->tv_sec * 1000 + (tv_r->tv_usec + 999) / 1000;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen i_assert(ret > 0 && tv_r->tv_sec >= 0 && tv_r->tv_usec >= 0);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return ret;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen}
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainenint io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen{
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen struct timeval tv_now;
c53e8ee216904ffe6de4f6518d9f9f5107b7610eTimo Sirainen struct priorityq_item *item;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen struct timeout *timeout;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen int msecs;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen item = priorityq_peek(ioloop->timeouts);
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen timeout = (struct timeout *)item;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* we need to see if there are pending IO waiting,
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen if there is, we set msecs = 0 to ensure they are
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen processed without delay */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (timeout == NULL && ioloop->io_pending_count == 0) {
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen /* no timeouts. use INT_MAX msecs for timeval and
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return -1 for poll/epoll infinity. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tv_r->tv_sec = INT_MAX / 1000;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen tv_r->tv_usec = 0;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen ioloop->next_max_time = (1ULL << (TIME_T_MAX_BITS-1)) - 1;
1fd0d511885c30028aba388588151acf4ee85e75Timo Sirainen return -1;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
c2feb7d13482d0f60691cd71d06d42a80df99397Timo Sirainen if (ioloop->io_pending_count > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (gettimeofday(&tv_now, NULL) < 0)
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen i_fatal("gettimeofday(): %m");
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen msecs = 0;
da5d50534cfca45d0aaaf0bdac17b287b4588809Timo Sirainen tv_r->tv_sec = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tv_r->tv_usec = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen tv_now.tv_sec = 0;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen msecs = timeout_get_wait_time(timeout, tv_r, &tv_now);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->next_max_time = (tv_now.tv_sec + msecs/1000) + 1;
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen
e670e1783fe4541dc3fc6109a181d45b0a9c2635Timo Sirainen /* update ioloop_timeval - this is meant for io_loop_handle_timeouts()'s
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen ioloop_wait_usecs calculation. normally after this we go to the
e670e1783fe4541dc3fc6109a181d45b0a9c2635Timo Sirainen ioloop and after that we update ioloop_timeval immediately again. */
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen ioloop_timeval = tv_now;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen ioloop_time = tv_now.tv_sec;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return msecs;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainenstatic int timeout_cmp(const void *p1, const void *p2)
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen{
90c5979b3c530707744beab6413f9d1e446335d1Timo Sirainen const struct timeout *to1 = p1, *to2 = p2;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen return timeval_cmp(&to1->next_run, &to2->next_run);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void io_loop_default_time_moved(time_t old_time, time_t new_time)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen if (old_time > new_time) {
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_warning("Time moved backwards by %ld seconds.",
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen (long)(old_time - new_time));
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainenstatic void io_loop_timeouts_start_new(struct ioloop *ioloop)
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen{
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen struct timeout *const *to_idx;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen if (array_count(&ioloop->timeouts_new) == 0)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen return;
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen io_loop_time_refresh();
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen array_foreach(&ioloop->timeouts_new, to_idx) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen struct timeout *timeout= *to_idx;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(timeout->next_run.tv_sec == 0 &&
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen timeout->next_run.tv_usec == 0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen i_assert(!timeout->one_shot);
eb77c0a041648af50abc027811f6b7951c3a80cdTimo Sirainen i_assert(timeout->msecs > 0);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen timeout_update_next(timeout, &ioloop_timeval);
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen priorityq_add(ioloop->timeouts, &timeout->item);
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen }
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen array_clear(&ioloop->timeouts_new);
51b979b6414b940f04677a7e2d064be119345954Timo Sirainen}
6143fece58262865ce89b5012b73ef08f2ad6abcTimo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void io_loop_timeouts_update(struct ioloop *ioloop, long diff_secs)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen struct priorityq_item *const *items;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen unsigned int i, count;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen count = priorityq_count(ioloop->timeouts);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen items = priorityq_items(ioloop->timeouts);
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen for (i = 0; i < count; i++) {
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen struct timeout *to = (struct timeout *)items[i];
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen to->next_run.tv_sec += diff_secs;
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen }
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen}
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainenstatic void io_loops_timeouts_update(long diff_secs)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen{
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen struct ioloop *ioloop;
e4b09b008ab544eb8994beecbfffefa21d855e43Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen for (ioloop = current_ioloop; ioloop != NULL; ioloop = ioloop->prev)
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen io_loop_timeouts_update(ioloop, diff_secs);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen}
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainenstatic void ioloop_add_wait_time(struct ioloop *ioloop)
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen{
4b231ca0bbe3b536acbd350101e183441ce0247aTimo Sirainen long long diff =
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen timeval_diff_usecs(&ioloop_timeval, &ioloop->wait_started);
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen ioloop->ioloop_wait_usecs += diff;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen ioloop_global_wait_usecs += diff;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen}
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainenstatic void io_loop_handle_timeouts_real(struct ioloop *ioloop)
14c474d9f4591c397ed0b5206af6537c7b52c924Timo Sirainen{
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen struct priorityq_item *item;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen struct timeval tv, tv_call;
d30da25fb6be1f1c667d93767c9194000194b618Timo Sirainen data_stack_frame_t t_id;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("gettimeofday(): %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* Don't bother comparing usecs. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* time moved backwards */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loops_timeouts_update(-(long)(ioloop_time -
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop_timeval.tv_sec));
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->time_moved_callback(ioloop_time,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop_timeval.tv_sec);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* the callback may have slept, so check the time again. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_fatal("gettimeofday(): %m");
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen } else {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (unlikely(ioloop_timeval.tv_sec >
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->next_max_time)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loops_timeouts_update(ioloop_timeval.tv_sec -
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->next_max_time);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* time moved forwards */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->time_moved_callback(ioloop->next_max_time,
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop_timeval.tv_sec);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop_add_wait_time(ioloop);
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen }
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen ioloop_time = ioloop_timeval.tv_sec;
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen tv_call = ioloop_timeval;
c61d52810496376a2ea60b8f4e27bbcaa8754f3fTimo Sirainen
2469ed8e17534f6cb5f41493df8c7e6f3b2c9b61Timo Sirainen while ((item = priorityq_peek(ioloop->timeouts)) != NULL) {
c61d52810496376a2ea60b8f4e27bbcaa8754f3fTimo Sirainen struct timeout *timeout = (struct timeout *)item;
f4e0148e539c6dd4e12b8305ab0dd5e63c46ba67Timo Sirainen
f4e0148e539c6dd4e12b8305ab0dd5e63c46ba67Timo Sirainen /* use tv_call to make sure we don't get to infinite loop in
f4e0148e539c6dd4e12b8305ab0dd5e63c46ba67Timo Sirainen case callbacks update ioloop_timeval. */
2bd96c58be42146cb84076331604cadb2994fce5Timo Sirainen if (timeout_get_wait_time(timeout, &tv, &tv_call) > 0)
2bd96c58be42146cb84076331604cadb2994fce5Timo Sirainen break;
2bd96c58be42146cb84076331604cadb2994fce5Timo Sirainen
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen if (timeout->one_shot) {
27db4ce5fe399c981e09dcf9e885a1546afd34f4Timo Sirainen /* remove timeout from queue */
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen } else {
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen /* update timeout's next_run and reposition it in the queue */
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen timeout_reset_timeval(timeout, &tv_call);
5cc772dc8b507be0bc1996b5717943ba13432e08Timo Sirainen }
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen if (timeout->ctx != NULL)
2a6af811ea3de3cf9e2f15e446674dd21b0705f3Timo Sirainen io_loop_context_activate(timeout->ctx);
b0be0bead3d6963149f7f2a9504b8ab5aced9af5Timo Sirainen t_id = t_push_named("ioloop timeout handler %p",
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen (void *)timeout->callback);
ccffbed92cb02c24fd717808a84138240bf1885bTimo Sirainen timeout->callback(timeout->context);
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen if (!t_pop(&t_id)) {
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen i_panic("Leaked a t_pop() call in timeout handler %p",
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen (void *)timeout->callback);
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen }
ae14dfd895881f9d1c6899b0c09f1a8b51447d61Timo Sirainen if (ioloop->cur_ctx != NULL)
a045c3aba2610c6ed0bf1c346df1c6d8f7b9fbfdTimo Sirainen io_loop_context_deactivate(ioloop->cur_ctx);
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen }
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen}
d9fdacd5fb3e07997e5c389739d2054f0c8441d8Timo Sirainen
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainenvoid io_loop_handle_timeouts(struct ioloop *ioloop)
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen{
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen T_BEGIN {
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen io_loop_handle_timeouts_real(ioloop);
31189eeac1ccaaf1201c60427f8c1087b0f5dfceTimo Sirainen } T_END;
902222fb0928d1701f20a384b73f327b1d9a15ddTimo Sirainen}
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainen
0d0451206a91e9f96e522075dce28a89adc2325dTimo Sirainenvoid io_loop_call_io(struct io *io)
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen{
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen struct ioloop *ioloop = io->ioloop;
e3689d0f073341e844638f34e1e4d0b7bb053cc8Timo Sirainen data_stack_frame_t t_id;
87712707722ef7d73acb065546e61afa4455cd9eTimo Sirainen
8d131435ba4648c8821160ec38d508c97177c715Timo Sirainen if (io->pending) {
bc1d1497d715cc5c820ff518f070f78c39ef6cdcTimo Sirainen i_assert(ioloop->io_pending_count > 0);
bc1d1497d715cc5c820ff518f070f78c39ef6cdcTimo Sirainen ioloop->io_pending_count--;
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen io->pending = FALSE;
5ec0ca7ff13595daf0d096c17100afb352e6294aTimo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (io->ctx != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_context_activate(io->ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen t_id = t_push_named("ioloop handler %p",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void *)io->callback);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io->callback(io->context);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (!t_pop(&t_id)) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_panic("Leaked a t_pop() call in I/O handler %p",
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen (void *)io->callback);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen }
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ioloop->cur_ctx != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_context_deactivate(ioloop->cur_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenvoid io_loop_run(struct ioloop *ioloop)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ioloop->handler_context == NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_initialize_handler(ioloop);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ioloop->cur_ctx != NULL)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_context_unref(&ioloop->cur_ctx);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen /* recursive io_loop_run() isn't allowed for the same ioloop.
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen it can break backends. */
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen i_assert(!ioloop->iolooping);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->iolooping = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->running = TRUE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (ioloop->running)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_handler_run(ioloop);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->iolooping = FALSE;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen}
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainenstatic void io_loop_call_pending(struct ioloop *ioloop)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen{
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen struct io_file *io;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen while (ioloop->io_pending_count > 0) {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io = ioloop->io_files;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen do {
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen ioloop->next_io_file = io->next;
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (io->io.pending)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen io_loop_call_io(&io->io);
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen if (ioloop->io_pending_count == 0)
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen break;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen io = ioloop->next_io_file;
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen } while (io != NULL);
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen }
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen}
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainenvoid io_loop_handler_run(struct ioloop *ioloop)
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen{
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen io_loop_timeouts_start_new(ioloop);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen ioloop->wait_started = ioloop_timeval;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen io_loop_handler_run_internal(ioloop);
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen io_loop_call_pending(ioloop);
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen}
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainenvoid io_loop_stop(struct ioloop *ioloop)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen{
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen ioloop->running = FALSE;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen}
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainenvoid io_loop_set_running(struct ioloop *ioloop)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen{
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen ioloop->running = TRUE;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen}
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainenvoid io_loop_set_max_fd_count(struct ioloop *ioloop, unsigned int max_fds)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen{
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen ioloop->max_fd_count = max_fds;
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen}
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainenbool io_loop_is_running(struct ioloop *ioloop)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen{
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen return ioloop->running;
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen}
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainenvoid io_loop_time_refresh(void)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen{
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen i_fatal("gettimeofday(): %m");
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen ioloop_time = ioloop_timeval.tv_sec;
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen}
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainenstruct ioloop *io_loop_create(void)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen{
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen struct ioloop *ioloop;
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen /* initialize time */
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen if (gettimeofday(&ioloop_timeval, NULL) < 0)
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen i_fatal("gettimeofday(): %m");
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen ioloop_time = ioloop_timeval.tv_sec;
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen
44ff75ca53188056ff5a3e50428e3f2078800b3cTimo Sirainen ioloop = i_new(struct ioloop, 1);
2b498cb82aaad8a11adb5a27a29c55b9c334a1ecTimo Sirainen ioloop->timeouts = priorityq_init(timeout_cmp, 32);
i_array_init(&ioloop->timeouts_new, 8);
ioloop->time_moved_callback = current_ioloop != NULL ?
current_ioloop->time_moved_callback :
io_loop_default_time_moved;
ioloop->prev = current_ioloop;
io_loop_set_current(ioloop);
return ioloop;
}
void io_loop_destroy(struct ioloop **_ioloop)
{
struct ioloop *ioloop = *_ioloop;
struct timeout *const *to_idx;
struct priorityq_item *item;
*_ioloop = NULL;
/* ->prev won't work unless loops are destroyed in create order */
i_assert(ioloop == current_ioloop);
io_loop_set_current(current_ioloop->prev);
if (ioloop->notify_handler_context != NULL)
io_loop_notify_handler_deinit(ioloop);
while (ioloop->io_files != NULL) {
struct io_file *io = ioloop->io_files;
struct io *_io = &io->io;
i_warning("I/O leak: %p (%s:%u, fd %d)",
(void *)io->io.callback,
io->io.source_filename,
io->io.source_linenum, io->fd);
io_remove(&_io);
}
i_assert(ioloop->io_pending_count == 0);
array_foreach(&ioloop->timeouts_new, to_idx) {
struct timeout *to = *to_idx;
i_warning("Timeout leak: %p (%s:%u)", (void *)to->callback,
to->source_filename,
to->source_linenum);
timeout_free(to);
}
array_free(&ioloop->timeouts_new);
while ((item = priorityq_pop(ioloop->timeouts)) != NULL) {
struct timeout *to = (struct timeout *)item;
i_warning("Timeout leak: %p (%s:%u)", (void *)to->callback,
to->source_filename,
to->source_linenum);
timeout_free(to);
}
priorityq_deinit(&ioloop->timeouts);
if (ioloop->handler_context != NULL)
io_loop_handler_deinit(ioloop);
if (ioloop->cur_ctx != NULL)
io_loop_context_deactivate(ioloop->cur_ctx);
i_free(ioloop);
}
void io_loop_set_time_moved_callback(struct ioloop *ioloop,
io_loop_time_moved_callback_t *callback)
{
ioloop->time_moved_callback = callback;
}
static void io_switch_callbacks_free(void)
{
array_free(&io_switch_callbacks);
}
void io_loop_set_current(struct ioloop *ioloop)
{
io_switch_callback_t *const *callbackp;
struct ioloop *prev_ioloop = current_ioloop;
current_ioloop = ioloop;
if (array_is_created(&io_switch_callbacks)) {
array_foreach(&io_switch_callbacks, callbackp)
(*callbackp)(prev_ioloop);
}
}
void io_loop_add_switch_callback(io_switch_callback_t *callback)
{
if (!array_is_created(&io_switch_callbacks)) {
i_array_init(&io_switch_callbacks, 4);
lib_atexit(io_switch_callbacks_free);
}
array_append(&io_switch_callbacks, &callback, 1);
}
void io_loop_remove_switch_callback(io_switch_callback_t *callback)
{
io_switch_callback_t *const *callbackp;
unsigned int idx;
array_foreach(&io_switch_callbacks, callbackp) {
if (*callbackp == callback) {
idx = array_foreach_idx(&io_switch_callbacks, callbackp);
array_delete(&io_switch_callbacks, idx, 1);
return;
}
}
i_unreached();
}
struct ioloop_context *io_loop_context_new(struct ioloop *ioloop)
{
struct ioloop_context *ctx;
ctx = i_new(struct ioloop_context, 1);
ctx->refcount = 2;
ctx->ioloop = ioloop;
i_array_init(&ctx->callbacks, 4);
if (ioloop->cur_ctx != NULL)
io_loop_context_unref(&ioloop->cur_ctx);
ioloop->cur_ctx = ctx;
return ctx;
}
void io_loop_context_ref(struct ioloop_context *ctx)
{
i_assert(ctx->refcount > 0);
ctx->refcount++;
}
void io_loop_context_unref(struct ioloop_context **_ctx)
{
struct ioloop_context *ctx = *_ctx;
*_ctx = NULL;
i_assert(ctx->refcount > 0);
if (--ctx->refcount > 0)
return;
/* cur_ctx itself keeps a reference */
i_assert(ctx->ioloop->cur_ctx != ctx);
array_free(&ctx->callbacks);
i_free(ctx);
}
#undef io_loop_context_add_callbacks
void io_loop_context_add_callbacks(struct ioloop_context *ctx,
io_callback_t *activate,
io_callback_t *deactivate, void *context)
{
struct ioloop_context_callback cb;
memset(&cb, 0, sizeof(cb));
cb.activate = activate;
cb.deactivate = deactivate;
cb.context = context;
array_append(&ctx->callbacks, &cb, 1);
}
#undef io_loop_context_remove_callbacks
void io_loop_context_remove_callbacks(struct ioloop_context *ctx,
io_callback_t *activate,
io_callback_t *deactivate, void *context)
{
struct ioloop_context_callback *cb;
array_foreach_modifiable(&ctx->callbacks, cb) {
if (cb->context == context &&
cb->activate == activate && cb->deactivate == deactivate) {
/* simply mark it as deleted, since we could get
here from activate/deactivate loop */
cb->activate = NULL;
cb->deactivate = NULL;
cb->context = NULL;
return;
}
}
i_panic("io_loop_context_remove_callbacks() context not found");
}
static void
io_loop_context_remove_deleted_callbacks(struct ioloop_context *ctx)
{
const struct ioloop_context_callback *cbs;
unsigned int i, count;
cbs = array_get(&ctx->callbacks, &count);
for (i = 0; i < count; ) {
if (cbs[i].activate != NULL)
i++;
else {
array_delete(&ctx->callbacks, i, 1);
cbs = array_get(&ctx->callbacks, &count);
}
}
}
void io_loop_context_activate(struct ioloop_context *ctx)
{
struct ioloop_context_callback *cb;
i_assert(ctx->ioloop->cur_ctx == NULL);
ctx->ioloop->cur_ctx = ctx;
io_loop_context_ref(ctx);
array_foreach_modifiable(&ctx->callbacks, cb) {
i_assert(!cb->activated);
if (cb->activate != NULL)
cb->activate(cb->context);
cb->activated = TRUE;
}
}
void io_loop_context_deactivate(struct ioloop_context *ctx)
{
struct ioloop_context_callback *cb;
i_assert(ctx->ioloop->cur_ctx != NULL);
array_foreach_modifiable(&ctx->callbacks, cb) {
if (!cb->activated) {
/* we just added this callback. don't deactivate it
before it gets first activated. */
} else {
if (cb->deactivate != NULL)
cb->deactivate(cb->context);
cb->activated = FALSE;
}
}
ctx->ioloop->cur_ctx = NULL;
io_loop_context_remove_deleted_callbacks(ctx);
io_loop_context_unref(&ctx);
}
struct ioloop_context *io_loop_get_current_context(struct ioloop *ioloop)
{
return ioloop->cur_ctx;
}
struct io *io_loop_move_io(struct io **_io)
{
struct io *old_io = *_io;
struct io_file *old_io_file, *new_io_file;
i_assert((old_io->condition & IO_NOTIFY) == 0);
if (old_io->ioloop == current_ioloop)
return old_io;
old_io_file = (struct io_file *)old_io;
new_io_file = io_add_file(old_io_file->fd, old_io->condition,
old_io->source_filename,
old_io->source_linenum,
old_io->callback, old_io->context);
if (old_io_file->istream != NULL) {
/* reference before io_remove() */
new_io_file->istream = old_io_file->istream;
i_stream_ref(new_io_file->istream);
}
if (old_io->pending)
io_set_pending(&new_io_file->io);
io_remove(_io);
if (new_io_file->istream != NULL) {
/* update istream io after it was removed with io_remove() */
i_stream_set_io(new_io_file->istream, &new_io_file->io);
}
return &new_io_file->io;
}
struct timeout *io_loop_move_timeout(struct timeout **_timeout)
{
struct timeout *new_to, *old_to = *_timeout;
if (old_to->ioloop == current_ioloop)
return old_to;
new_to = timeout_copy(old_to);
timeout_remove(_timeout);
return new_to;
}
bool io_loop_have_ios(struct ioloop *ioloop)
{
return ioloop->io_files != NULL;
}
bool io_loop_have_immediate_timeouts(struct ioloop *ioloop)
{
struct timeval tv;
return io_loop_get_wait_time(ioloop, &tv) == 0;
}
uint64_t io_loop_get_wait_usecs(struct ioloop *ioloop)
{
return ioloop->ioloop_wait_usecs;
}
enum io_condition io_loop_find_fd_conditions(struct ioloop *ioloop, int fd)
{
enum io_condition conditions = 0;
struct io_file *io;
i_assert(fd >= 0);
for (io = ioloop->io_files; io != NULL; io = io->next) {
if (io->fd == fd)
conditions |= io->io.condition;
}
return conditions;
}