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