Mercurial > dovecot > core-2.2
changeset 19019:ec6e672a6e32
ioloop: Delay actual start of a new normal timeout until the next io_loop_run() cycle.
This makes sure that timeouts will not expire before they get a chance to
run.
author | Stephan Bosch <stephan@rename-it.nl> |
---|---|
date | Thu, 27 Aug 2015 10:39:26 +0200 |
parents | f363a7665a14 |
children | 42d4da9ee7a9 |
files | src/lib/Makefile.am src/lib/ioloop-private.h src/lib/ioloop.c src/lib/test-ioloop.c src/lib/test-lib.c src/lib/test-lib.h |
diffstat | 6 files changed, 101 insertions(+), 3 deletions(-) [+] |
line wrap: on
line diff
--- a/src/lib/Makefile.am Wed Aug 26 17:00:55 2015 +0200 +++ b/src/lib/Makefile.am Thu Aug 27 10:39:26 2015 +0200 @@ -304,6 +304,7 @@ test-hash-format.c \ test-hash-method.c \ test-hex-binary.c \ + test-ioloop.c \ test-iso8601-date.c \ test-istream.c \ test-istream-base64-decoder.c \
--- a/src/lib/ioloop-private.h Wed Aug 26 17:00:55 2015 +0200 +++ b/src/lib/ioloop-private.h Thu Aug 27 10:39:26 2015 +0200 @@ -3,6 +3,7 @@ #include "priorityq.h" #include "ioloop.h" +#include "array-decl.h" #ifndef IOLOOP_INITIAL_FD_COUNT # define IOLOOP_INITIAL_FD_COUNT 128 @@ -16,6 +17,7 @@ struct io_file *io_files; struct io_file *next_io_file; struct priorityq *timeouts; + ARRAY(struct timeout *) timeouts_new; struct ioloop_handler_context *handler_context; struct ioloop_notify_handler_context *notify_handler_context;
--- a/src/lib/ioloop.c Wed Aug 26 17:00:55 2015 +0200 +++ b/src/lib/ioloop.c Thu Aug 27 10:39:26 2015 +0200 @@ -204,7 +204,8 @@ struct timeout *timeout; timeout = i_new(struct timeout, 1); - timeout->source_linenum = source_linenum; + timeout->item.idx = UINT_MAX; + timeout->source_linenum = source_linenum; timeout->ioloop = current_ioloop; timeout->callback = callback; @@ -227,9 +228,15 @@ timeout = timeout_add_common(source_linenum, callback, context); timeout->msecs = msecs; - timeout_update_next(timeout, timeout->ioloop->running ? + if (msecs > 0) { + /* start this timeout in the next run cycle */ + array_append(&timeout->ioloop->timeouts_new, &timeout, 1); + } else { + /* trigger zero timeouts as soon as possible */ + timeout_update_next(timeout, timeout->ioloop->running ? NULL : &ioloop_timeval); - priorityq_add(timeout->ioloop->timeouts, &timeout->item); + priorityq_add(timeout->ioloop->timeouts, &timeout->item); + } return timeout; } @@ -282,10 +289,21 @@ void timeout_remove(struct timeout **_timeout) { struct timeout *timeout = *_timeout; + struct ioloop *ioloop = timeout->ioloop; *_timeout = NULL; if (timeout->item.idx != UINT_MAX) priorityq_remove(timeout->ioloop->timeouts, &timeout->item); + else { + struct timeout *const *to_idx; + array_foreach(&ioloop->timeouts_new, to_idx) { + if (*to_idx == timeout) { + array_delete(&ioloop->timeouts_new, + array_foreach_idx(&ioloop->timeouts_new, to_idx), 1); + break; + } + } + } timeout_free(timeout); } @@ -393,6 +411,27 @@ } } +static void io_loop_timeouts_start_new(struct ioloop *ioloop) +{ + struct timeout *const *to_idx; + + if (array_count(&ioloop->timeouts_new) == 0) + return; + + io_loop_time_refresh(); + + array_foreach(&ioloop->timeouts_new, to_idx) { + struct timeout *timeout = *to_idx; + i_assert(timeout->next_run.tv_sec == 0 && + timeout->next_run.tv_usec == 0); + i_assert(!timeout->one_shot); + i_assert(timeout->msecs > 0); + timeout_update_next(timeout, &ioloop_timeval); + priorityq_add(ioloop->timeouts, &timeout->item); + } + array_clear(&ioloop->timeouts_new); +} + static void io_loop_timeouts_update(struct ioloop *ioloop, long diff_secs) { struct priorityq_item *const *items; @@ -545,6 +584,7 @@ void io_loop_handler_run(struct ioloop *ioloop) { + io_loop_timeouts_start_new(ioloop); io_loop_handler_run_internal(ioloop); io_loop_call_pending(ioloop); } @@ -587,6 +627,7 @@ ioloop = i_new(struct ioloop, 1); 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 : @@ -600,6 +641,7 @@ void io_loop_destroy(struct ioloop **_ioloop) { struct ioloop *ioloop = *_ioloop; + struct timeout *const *to_idx; struct priorityq_item *item; *_ioloop = NULL; @@ -622,6 +664,15 @@ } i_assert(ioloop->io_pending_count == 0); + array_foreach(&ioloop->timeouts_new, to_idx) { + struct timeout *to = *to_idx; + + i_warning("Timeout leak: %p (line %u)", (void *)to->callback, + to->source_linenum); + timeout_free(to); + } + array_free(&ioloop->timeouts_new); + while ((item = priorityq_pop(ioloop->timeouts)) != NULL) { struct timeout *to = (struct timeout *)item;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lib/test-ioloop.c Thu Aug 27 10:39:26 2015 +0200 @@ -0,0 +1,42 @@ +/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */ + +#include "test-lib.h" +#include "time-util.h" +#include "ioloop.h" + +#include <unistd.h> + +static void timeout_callback(struct timeval *tv) +{ + if (gettimeofday(tv, NULL) < 0) + i_fatal("gettimeofday() failed: %m"); + io_loop_stop(current_ioloop); +} + +static void test_ioloop_timeout(void) +{ + struct ioloop *ioloop; + struct timeout *to; + struct timeval tv_start, tv_callback; + + test_begin("ioloop timeout"); + + ioloop = io_loop_create(); + sleep(1); + to = timeout_add(1000, timeout_callback, &tv_callback); + timeout_remove(&to); + to = timeout_add(1000, timeout_callback, &tv_callback); + if (gettimeofday(&tv_start, NULL) < 0) + i_fatal("gettimeofday() failed: %m"); + io_loop_run(ioloop); + test_assert(timeval_diff_msecs(&tv_callback, &tv_start) >= 500); + timeout_remove(&to); + io_loop_destroy(&ioloop); + + test_end(); +} + +void test_ioloop(void) +{ + test_ioloop_timeout(); +}
--- a/src/lib/test-lib.c Wed Aug 26 17:00:55 2015 +0200 +++ b/src/lib/test-lib.c Thu Aug 27 10:39:26 2015 +0200 @@ -20,6 +20,7 @@ test_hash_format, test_hash_method, test_hex_binary, + test_ioloop, test_iso8601_date, test_istream, test_istream_base64_decoder,
--- a/src/lib/test-lib.h Wed Aug 26 17:00:55 2015 +0200 +++ b/src/lib/test-lib.h Thu Aug 27 10:39:26 2015 +0200 @@ -21,6 +21,7 @@ void test_hash_format(void); void test_hash_method(void); void test_hex_binary(void); +void test_ioloop(void); void test_iso8601_date(void); void test_istream(void); void test_istream_base64_decoder(void);