446ea3
From 93de7820843c175f4c9661dbfcb312e8ee09fbd3 Mon Sep 17 00:00:00 2001
446ea3
From: Lennart Poettering <lennart@poettering.net>
446ea3
Date: Tue, 8 Jun 2021 00:07:51 -0700
446ea3
Subject: [PATCH] sd-event: change ordering of pending/ratelimited events
446ea3
446ea3
Instead of ordering non-pending before pending we should order
446ea3
"non-pending OR ratelimited" before "pending AND not-ratelimited".
446ea3
This fixes a bug where ratelimited events were ordered at the end of the
446ea3
priority queue and could be stuck there for an indeterminate amount of
446ea3
time.
446ea3
446ea3
(cherry picked from commit 81107b8419c39f726fd2805517a5b9faab204e59)
446ea3
446ea3
Related: #1984406
446ea3
---
446ea3
 src/libsystemd/sd-event/sd-event.c | 48 +++++++++++++-----------------
446ea3
 1 file changed, 20 insertions(+), 28 deletions(-)
446ea3
446ea3
diff --git a/src/libsystemd/sd-event/sd-event.c b/src/libsystemd/sd-event/sd-event.c
446ea3
index be912d94e3..3e77f4e810 100644
446ea3
--- a/src/libsystemd/sd-event/sd-event.c
446ea3
+++ b/src/libsystemd/sd-event/sd-event.c
446ea3
@@ -427,25 +427,6 @@ static usec_t time_event_source_next(const sd_event_source *s) {
446ea3
         return USEC_INFINITY;
446ea3
 }
446ea3
 
446ea3
-static int earliest_time_prioq_compare(const void *a, const void *b) {
446ea3
-        const sd_event_source *x = a, *y = b;
446ea3
-
446ea3
-        /* Enabled ones first */
446ea3
-        if (x->enabled != SD_EVENT_OFF && y->enabled == SD_EVENT_OFF)
446ea3
-                return -1;
446ea3
-        if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
446ea3
-                return 1;
446ea3
-
446ea3
-        /* Move the pending ones to the end */
446ea3
-        if (!x->pending && y->pending)
446ea3
-                return -1;
446ea3
-        if (x->pending && !y->pending)
446ea3
-                return 1;
446ea3
-
446ea3
-        /* Order by time */
446ea3
-        return CMP(time_event_source_next(x), time_event_source_next(y));
446ea3
-}
446ea3
-
446ea3
 static usec_t time_event_source_latest(const sd_event_source *s) {
446ea3
         assert(s);
446ea3
 
446ea3
@@ -464,7 +445,15 @@ static usec_t time_event_source_latest(const sd_event_source *s) {
446ea3
         return USEC_INFINITY;
446ea3
 }
446ea3
 
446ea3
-static int latest_time_prioq_compare(const void *a, const void *b) {
446ea3
+static bool event_source_timer_candidate(const sd_event_source *s) {
446ea3
+        assert(s);
446ea3
+
446ea3
+        /* Returns true for event sources that either are not pending yet (i.e. where it's worth to mark them pending)
446ea3
+         * or which are currently ratelimited (i.e. where it's worth leaving the ratelimited state) */
446ea3
+        return !s->pending || s->ratelimited;
446ea3
+}
446ea3
+
446ea3
+static int time_prioq_compare(const void *a, const void *b, usec_t (*time_func)(const sd_event_source *s)) {
446ea3
         const sd_event_source *x = a, *y = b;
446ea3
 
446ea3
         /* Enabled ones first */
446ea3
@@ -473,19 +462,22 @@ static int latest_time_prioq_compare(const void *a, const void *b) {
446ea3
         if (x->enabled == SD_EVENT_OFF && y->enabled != SD_EVENT_OFF)
446ea3
                 return 1;
446ea3
 
446ea3
-        /* Move the pending ones to the end */
446ea3
-        if (!x->pending && y->pending)
446ea3
+        /* Order "non-pending OR ratelimited" before "pending AND not-ratelimited" */
446ea3
+        if (event_source_timer_candidate(x) && !event_source_timer_candidate(y))
446ea3
                 return -1;
446ea3
-        if (x->pending && !y->pending)
446ea3
+        if (!event_source_timer_candidate(x) && event_source_timer_candidate(y))
446ea3
                 return 1;
446ea3
 
446ea3
         /* Order by time */
446ea3
-        if (time_event_source_latest(x) < time_event_source_latest(y))
446ea3
-                return -1;
446ea3
-        if (time_event_source_latest(x) > time_event_source_latest(y))
446ea3
-                return 1;
446ea3
+        return CMP(time_func(x), time_func(y));
446ea3
+}
446ea3
 
446ea3
-        return 0;
446ea3
+static int earliest_time_prioq_compare(const void *a, const void *b) {
446ea3
+        return time_prioq_compare(a, b, time_event_source_next);
446ea3
+}
446ea3
+
446ea3
+static int latest_time_prioq_compare(const void *a, const void *b) {
446ea3
+        return time_prioq_compare(a, b, time_event_source_latest);
446ea3
 }
446ea3
 
446ea3
 static int exit_prioq_compare(const void *a, const void *b) {