ioloop.c revision cc80e458f2e3f13106299794376e9be4d3e8ef80
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (c) 2002-2014 Dovecot authors, see the included COPYING file */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic ARRAY(io_switch_callback_t *) io_switch_callbacks = ARRAY_INIT;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic void io_loop_initialize_handler(struct ioloop *ioloop)
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen initial_fd_count = ioloop->max_fd_count > 0 &&
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen ioloop->max_fd_count < IOLOOP_INITIAL_FD_COUNT ?
f5a7396b31762a1f876517e13ce9065820139f7cTimo Sirainen ioloop->max_fd_count : IOLOOP_INITIAL_FD_COUNT;
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen io_loop_handler_init(ioloop, initial_fd_count);
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenstatic struct io_file *
132487b9a47c2eb6fc80cfa2b0aaf82c6dc3af56Timo Sirainenio_add_file(int fd, enum io_condition condition,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* we're adding an istream whose only way to get notified
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen is to call i_stream_set_input_pending() */
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainenstruct io *io_add(int fd, enum io_condition condition,
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen io = io_add_file(fd, condition, source_linenum, callback, context);
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainenstruct io *io_add_istream(struct istream *input, unsigned int source_linenum,
4ece61edd7c266a4b8f3b290a7f0a3cb3d13ca0fTimo Sirainen io = io_add_file(i_stream_get_fd(input), IO_READ, source_linenum,
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* if we got here from an I/O handler callback, make sure we
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen don't try to handle this one next. */
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainenstatic void io_remove_full(struct io **_io, bool closed)
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen /* make sure the callback doesn't get called anymore.
c93ff0433cc3d348116f75a64f9988fedb86fd18Timo Sirainen kqueue code relies on this. */
755aea84bbe2b15ed7fe991f6462a93333ff571fTimo Sirainen struct io_file *io_file = (struct io_file *)io;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen i_assert(((*io)->condition & IO_NOTIFY) == 0);
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainenstatic void timeout_update_next(struct timeout *timeout, struct timeval *tv_now)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen if (gettimeofday(&timeout->next_run, NULL) < 0)
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen /* we don't want microsecond accuracy or this function will be
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen called all the time - millisecond is more than enough */
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen timeout->next_run.tv_usec -= timeout->next_run.tv_usec % 1000;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen timeout->next_run.tv_sec += timeout->msecs/1000;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainen timeout->next_run.tv_usec += (timeout->msecs%1000)*1000;
6b399f555c9c5c722d4cd5eab8faa02b2a4731d3Timo Sirainenstruct timeout *timeout_add(unsigned int msecs, unsigned int source_linenum,
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainen timeout_update_next(timeout, timeout->ioloop->running ?
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainentimeout_add_short(unsigned int msecs, unsigned int source_linenum,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen return timeout_add(msecs, source_linenum, callback, context);
499fec3443374cc89fb8c83b8027c1614097d7a3Timo Sirainenstatic void timeout_free(struct timeout *timeout)
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainentimeout_reset_timeval(struct timeout *timeout, struct timeval *tv_now)
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen /* if we came here from io_loop_handle_timeouts(),
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen next_run must be larger than tv_now or we could go to
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen infinite loop. +1000 to get 1 ms further, another +1000 to
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen account for timeout_update_next()'s truncation. */
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen (timeout->next_run.tv_sec == tv_now->tv_sec &&
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen timeout->next_run.tv_usec > tv_now->tv_usec));
047e3bbb00e68a0d43355e11a67b2e912e06de19Timo Sirainen priorityq_remove(timeout->ioloop->timeouts, &timeout->item);
c4bb0320ab43ea35fa6df88fc745fdad906cee44Timo Sirainen priorityq_add(timeout->ioloop->timeouts, &timeout->item);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainenstatic int timeout_get_wait_time(struct timeout *timeout, struct timeval *tv_r,
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen tv_r->tv_sec = timeout->next_run.tv_sec - tv_r->tv_sec;
eca30f1fe8556c46abc75c94d03f59b2e89d4162Timo Sirainen tv_r->tv_usec = timeout->next_run.tv_usec - tv_r->tv_usec;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (tv_r->tv_sec < 0 || (tv_r->tv_sec == 0 && tv_r->tv_usec < 1000)) {
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen /* round wait times up to next millisecond */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ret = tv_r->tv_sec * 1000 + (tv_r->tv_usec + 999) / 1000;
942302b0247403645394d848b3c620ead262a2a5Timo Sirainen i_assert(ret > 0 && tv_r->tv_sec >= 0 && tv_r->tv_usec >= 0);
18ccd19c244f49665fe03cda785efa066d2c38dfTimo Sirainenint io_loop_get_wait_time(struct ioloop *ioloop, struct timeval *tv_r)
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen /* no timeouts. use INT_MAX msecs for timeval and
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen return -1 for poll/epoll infinity. */
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ioloop->next_max_time = (1ULL << (TIME_T_MAX_BITS-1)) - 1;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen msecs = timeout_get_wait_time(timeout, tv_r, &tv_now);
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainen ioloop->next_max_time = (tv_now.tv_sec + msecs/1000) + 1;
17ad2164c747cedbf81dae1893063e71a3df0356Timo Sirainenstatic int timeout_cmp(const void *p1, const void *p2)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen return timeval_cmp(&to1->next_run, &to2->next_run);
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainenstatic void io_loop_default_time_moved(time_t old_time, time_t new_time)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen i_warning("Time moved backwards by %ld seconds.",
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainenstatic void io_loop_timeouts_update(struct ioloop *ioloop, long diff_secs)
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen unsigned int i, count;
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen for (i = 0; i < count; i++) {
421d30619384e72a27e2a5d13ff6525aff4d17feTimo Sirainen struct timeout *to = (struct timeout *)items[i];
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainenstatic void io_loops_timeouts_update(long diff_secs)
206ed2f6fa3a6fb291498627b2da626581c07a18Timo Sirainen for (ioloop = current_ioloop; ioloop != NULL; ioloop = ioloop->prev)
51327f2489a4e0e615eb9f7d921473cf8512bb79Timo Sirainenstatic void io_loop_handle_timeouts_real(struct ioloop *ioloop)
d859478e8b106de6cea54f26861bd4232c92f62cTimo Sirainen unsigned int t_id;
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen /* Don't bother comparing usecs. */
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) {
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen /* time moved backwards */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen io_loops_timeouts_update(-(long)(ioloop_time -
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen /* the callback may have slept, so check the time again. */
77d8223da3da23b731257596abefa77e4485b77dTimo Sirainen io_loops_timeouts_update(ioloop_timeval.tv_sec -
9438ecaf1caee1bb33c8d7f638742875ac42c4e5Timo Sirainen /* time moved forwards */
9438ecaf1caee1bb33c8d7f638742875ac42c4e5Timo Sirainen ioloop->time_moved_callback(ioloop->next_max_time,
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen while ((item = priorityq_peek(ioloop->timeouts)) != NULL) {
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen struct timeout *timeout = (struct timeout *)item;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* use tv_call to make sure we don't get to infinite loop in
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen case callbacks update ioloop_timeval. */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen if (timeout_get_wait_time(timeout, &tv, &tv_call) > 0)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* update timeout's next_run and reposition it in the queue */
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen t_id = t_push_named("ioloop timeout handler %p",
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_panic("Leaked a t_pop() call in timeout handler %p",
86bde2c1838d1ce967fa2b394bb952004a4adcb7Timo Sirainenvoid io_loop_handle_timeouts(struct ioloop *ioloop)
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen unsigned int t_id;
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen i_panic("Leaked a t_pop() call in I/O handler %p",
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen /* recursive io_loop_run() isn't allowed for the same ioloop.
8d587838c414c48a331f0b54cd7ffd97e5024abdTimo Sirainen it can break backends. */
3852872e6954b7132e637294132005e86b8ebd4aTimo Sirainenstatic void io_loop_call_pending(struct ioloop *ioloop)
4cf5f0934a25f1fd58f2780108f9d6498c455a1fTimo Sirainenvoid io_loop_handler_run(struct ioloop *ioloop)
563273bdac80393af63b9520cbf4d24cc0efd028Timo Sirainenvoid io_loop_set_running(struct ioloop *ioloop)
1d2b188f0eedc3cab6e27ceac5425a037f38042eTimo Sirainenvoid io_loop_set_max_fd_count(struct ioloop *ioloop, unsigned int max_fds)
62041dfb7d6ac6e9c633a557075999cdfcff7bd5Timo Sirainen /* initialize time */
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ioloop->timeouts = priorityq_init(timeout_cmp, 32);
24e5e4526d8f5cbc056ab97fd0d154d0936d7a5eTimo Sirainen ioloop->time_moved_callback = current_ioloop != NULL ?
c115c742f730e312d6b6ab5064595cd0d8b4e26eTimo Sirainen /* ->prev won't work unless loops are destroyed in create order */
static void io_switch_callbacks_free(void)
unsigned int idx;
i_unreached();
return ctx;
here from activate/deactivate loop */
unsigned int i, count;
for (i = 0; i < count; ) {
return old_io;
return old_to;
return new_to;