dovecot-2.2: ioloop: Delay actual start of a new normal timeout ...

dovecot at dovecot.org dovecot at dovecot.org
Thu Aug 27 08:41:28 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/ec6e672a6e32
changeset: 19019:ec6e672a6e32
user:      Stephan Bosch <stephan at rename-it.nl>
date:      Thu Aug 27 10:39:26 2015 +0200
description:
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.

diffstat:

 src/lib/Makefile.am      |   1 +
 src/lib/ioloop-private.h |   2 +
 src/lib/ioloop.c         |  57 +++++++++++++++++++++++++++++++++++++++++++++--
 src/lib/test-ioloop.c    |  42 +++++++++++++++++++++++++++++++++++
 src/lib/test-lib.c       |   1 +
 src/lib/test-lib.h       |   1 +
 6 files changed, 101 insertions(+), 3 deletions(-)

diffs (219 lines):

diff -r f363a7665a14 -r ec6e672a6e32 src/lib/Makefile.am
--- 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 \
diff -r f363a7665a14 -r ec6e672a6e32 src/lib/ioloop-private.h
--- 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;
diff -r f363a7665a14 -r ec6e672a6e32 src/lib/ioloop.c
--- 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;
 
diff -r f363a7665a14 -r ec6e672a6e32 src/lib/test-ioloop.c
--- /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();
+}
diff -r f363a7665a14 -r ec6e672a6e32 src/lib/test-lib.c
--- 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,
diff -r f363a7665a14 -r ec6e672a6e32 src/lib/test-lib.h
--- 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);


More information about the dovecot-cvs mailing list