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