changeset 4102:99b17f13cc1e HEAD

Timers weren't called always properly when they should have.
author Timo Sirainen <tss@iki.fi>
date Sat, 25 Mar 2006 12:10:41 +0200
parents 321469dcb8fb
children 25204e1faeb6
files src/lib/ioloop.c
diffstat 1 files changed, 36 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/ioloop.c	Sat Mar 25 11:25:09 2006 +0200
+++ b/src/lib/ioloop.c	Sat Mar 25 12:10:41 2006 +0200
@@ -3,8 +3,7 @@
 #include "lib.h"
 #include "ioloop-internal.h"
 
-#undef timercmp
-#define timercmp(tvp, uvp) \
+#define timer_is_larger(tvp, uvp) \
 	((tvp)->tv_sec > (uvp)->tv_sec || \
 	 ((tvp)->tv_sec == (uvp)->tv_sec && \
 	  (tvp)->tv_usec > (uvp)->tv_usec))
@@ -101,7 +100,7 @@
 
         next_run = &timeout->next_run;
 	for (t = &ioloop->timeouts; *t != NULL; t = &(*t)->next) {
-		if (timercmp(&(*t)->next_run, next_run))
+		if (timer_is_larger(&(*t)->next_run, next_run))
                         break;
 	}
 
@@ -201,7 +200,7 @@
 
 void io_loop_handle_timeouts(struct ioloop *ioloop)
 {
-	struct timeout *t, **t_p;
+	struct timeout *called_timeouts;
 	struct timeval tv;
         unsigned int t_id;
 
@@ -212,13 +211,14 @@
 	if (ioloop->timeouts == NULL || !ioloop->timeouts->run_now)
 		return;
 
-	t_p = &ioloop->timeouts;
-	for (t = ioloop->timeouts; t != NULL; t = *t_p) {
+	called_timeouts = NULL;
+	while (ioloop->timeouts != NULL) {
+		struct timeout *t = ioloop->timeouts;
+
 		if (t->destroyed) {
-                        timeout_destroy(ioloop, t_p);
+                        timeout_destroy(ioloop, &ioloop->timeouts);
 			continue;
 		}
-		t_p = &t->next;
 
 		if (!t->run_now) {
 			io_loop_get_wait_time(t, &tv, &ioloop_timeval);
@@ -227,6 +227,11 @@
 				break;
 		}
 
+		/* move timeout to called_timeouts list */
+		ioloop->timeouts = t->next;
+		t->next = called_timeouts;
+		called_timeouts = t;
+
                 t->run_now = FALSE;
                 timeout_update_next(t, &ioloop_timeval);
 
@@ -237,6 +242,29 @@
 				(void *)t->callback);
 		}
 	}
+
+	/* move timeouts back to list so they get re-sorted again by next_run
+	   time, or destroy them if timeout_remove() was called for them. */
+	while (called_timeouts != NULL) {
+		struct timeout *t = called_timeouts;
+
+		if (t->destroyed)
+			timeout_destroy(ioloop, &called_timeouts);
+		else {
+			called_timeouts = t->next;
+			timeout_list_insert(current_ioloop, t);
+		}
+	}
+#ifdef DEBUG
+	if (ioloop->timeouts != NULL) {
+		struct timeout *t;
+
+		for (t = ioloop->timeouts; t->next != NULL; t = t->next) {
+			if (timer_is_larger(&t->next_run, &t->next->next_run))
+				i_panic("broken timeout list");
+		}
+	}
+#endif
 }
 
 void io_loop_run(struct ioloop *ioloop)