[PATCH libinput 2/2] timer: always restart the timer loop when we called one of them

Peter Hutterer peter.hutterer at who-t.net
Mon Jul 17 03:57:04 UTC 2017


If a timer_func causes the removal or addition of a different timer, our tmp
pointer from the list_for_each_safe may not be valid anymore.

This was triggered by having the debounce code trigger a middle button state
change, which caused that timer to be cancelled.

Signed-off-by: Peter Hutterer <peter.hutterer at who-t.net>
---
 src/timer.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)

diff --git a/src/timer.c b/src/timer.c
index 5d9fc512..6acc7673 100644
--- a/src/timer.c
+++ b/src/timer.c
@@ -128,7 +128,7 @@ static void
 libinput_timer_handler(void *data)
 {
 	struct libinput *libinput = data;
-	struct libinput_timer *timer, *tmp;
+	struct libinput_timer *timer;
 	uint64_t now;
 	uint64_t discard;
 	int r;
@@ -144,7 +144,9 @@ libinput_timer_handler(void *data)
 	if (now == 0)
 		return;
 
-	list_for_each_safe(timer, tmp, &libinput->timer.list, link) {
+restart:
+	list_for_each(timer, &libinput->timer.list, link) {
+		printf("handling timer %s\n", timer->timer_name);
 		if (timer->expire == 0)
 			continue;
 
@@ -153,6 +155,16 @@ libinput_timer_handler(void *data)
 			   as timer_func may re-arm it */
 			libinput_timer_cancel(timer);
 			timer->timer_func(now, timer->timer_func_data);
+
+			/*
+			 * Restart the loop. We can't use
+			 * list_for_each_safe() here because that only
+			 * allows removing one (our) timer per timer_func.
+			 * But the timer func may trigger another unrelated
+			 * timer to be cancelled and removed, causing a
+			 * segfault.
+			 */
+			goto restart;
 		}
 	}
 }
-- 
2.13.0



More information about the wayland-devel mailing list