dovecot-2.2: lib: Try fixing ec6e672a6e32 (ioloop timeout fixing)
dovecot at dovecot.org
dovecot at dovecot.org
Thu Aug 27 15:35:46 UTC 2015
details: http://hg.dovecot.org/dovecot-2.2/rev/5423ae859f15
changeset: 19025:5423ae859f15
user: Timo Sirainen <tss at iki.fi>
date: Thu Aug 27 17:34:52 2015 +0200
description:
lib: Try fixing ec6e672a6e32 (ioloop timeout fixing)
Previous code was broken at least when moving a timeout between ioloops.
This is now tested and works.
diffstat:
src/lib/Makefile.am | 1 +
src/lib/ioloop-private.h | 2 +
src/lib/ioloop.c | 68 +++++++++++++++++++++++++++++++++++++++++++++--
src/lib/test-ioloop.c | 18 +++++++++++-
src/lib/test-lib.c | 1 +
src/lib/test-lib.h | 1 +
6 files changed, 85 insertions(+), 6 deletions(-)
diffs (239 lines):
diff -r 84b45106e143 -r 5423ae859f15 src/lib/Makefile.am
--- a/src/lib/Makefile.am Thu Aug 27 15:46:23 2015 +0200
+++ b/src/lib/Makefile.am Thu Aug 27 17:34:52 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 \
diff -r 84b45106e143 -r 5423ae859f15 src/lib/ioloop-private.h
--- a/src/lib/ioloop-private.h Thu Aug 27 15:46:23 2015 +0200
+++ b/src/lib/ioloop-private.h Thu Aug 27 17:34:52 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;
diff -r 84b45106e143 -r 5423ae859f15 src/lib/ioloop.c
--- a/src/lib/ioloop.c Thu Aug 27 15:46:23 2015 +0200
+++ b/src/lib/ioloop.c Thu Aug 27 17:34:52 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;
}
@@ -267,7 +274,13 @@
new_to->one_shot = old_to->one_shot;
new_to->msecs = old_to->msecs;
new_to->next_run = old_to->next_run;
- priorityq_add(new_to->ioloop->timeouts, &new_to->item);
+
+ if (old_to->item.idx != UINT_MAX)
+ priorityq_add(new_to->ioloop->timeouts, &new_to->item);
+ else if (!new_to->one_shot) {
+ i_assert(new_to->msecs > 0);
+ array_append(&new_to->ioloop->timeouts_new, &new_to, 1);
+ }
return new_to;
}
@@ -282,16 +295,30 @@
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 if (!timeout->one_shot && timeout->msecs > 0) {
+ 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);
}
static void ATTR_NULL(2)
timeout_reset_timeval(struct timeout *timeout, struct timeval *tv_now)
{
+ if (timeout->item.idx == UINT_MAX)
+ return;
+
timeout_update_next(timeout, tv_now);
if (timeout->msecs <= 1) {
/* if we came here from io_loop_handle_timeouts(),
@@ -393,6 +420,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 +593,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 +636,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 +650,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 +673,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;
diff -r 84b45106e143 -r 5423ae859f15 src/lib/test-ioloop.c
--- a/src/lib/test-ioloop.c Thu Aug 27 15:46:23 2015 +0200
+++ b/src/lib/test-ioloop.c Thu Aug 27 17:34:52 2015 +0200
@@ -15,22 +15,36 @@
static void test_ioloop_timeout(void)
{
- struct ioloop *ioloop;
- struct timeout *to;
+ struct ioloop *ioloop, *ioloop2;
+ struct timeout *to, *to2;
struct timeval tv_start, tv_callback;
test_begin("ioloop timeout");
ioloop = io_loop_create();
+
+ /* add a timeout by moving it from another ioloop */
+ ioloop2 = io_loop_create();
+ to2 = timeout_add(1000, timeout_callback, &tv_callback);
+ io_loop_set_current(ioloop);
+ to2 = io_loop_move_timeout(&to2);
+ io_loop_set_current(ioloop2);
+ io_loop_destroy(&ioloop2);
+
sleep(1);
+
+ /* add & remove immediately */
to = timeout_add(1000, timeout_callback, &tv_callback);
timeout_remove(&to);
+
+ /* add the timeout we're actually testing below */
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);
+ timeout_remove(&to2);
io_loop_destroy(&ioloop);
test_end();
diff -r 84b45106e143 -r 5423ae859f15 src/lib/test-lib.c
--- a/src/lib/test-lib.c Thu Aug 27 15:46:23 2015 +0200
+++ b/src/lib/test-lib.c Thu Aug 27 17:34:52 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,
diff -r 84b45106e143 -r 5423ae859f15 src/lib/test-lib.h
--- a/src/lib/test-lib.h Thu Aug 27 15:46:23 2015 +0200
+++ b/src/lib/test-lib.h Thu Aug 27 17:34:52 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);
More information about the dovecot-cvs
mailing list