]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
udev: list up all dependencies of an event when the first time it is examined
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 5 May 2025 17:25:32 +0000 (02:25 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 9 May 2025 15:26:32 +0000 (00:26 +0900)
No functional change, just refactoring.

src/udev/udev-manager.c

index b18d52181ff1ace018c27d9413a2352a522ba705..504fdf2abfc48efdf6b932a65fdcb54d971fdbeb 100644 (file)
@@ -57,7 +57,6 @@ typedef struct Event {
 
         sd_device_action_t action;
         uint64_t seqnum;
-        uint64_t blocker_seqnum;
         const char *id;
         const char *devpath;
         const char *devpath_old;
@@ -71,6 +70,10 @@ typedef struct Event {
         sd_event_source *timeout_warning_event;
         sd_event_source *timeout_event;
 
+        bool dependencies_built;
+        Set *blocker_events;
+        Set *blocking_events;
+
         LIST_FIELDS(Event, event);
 } Event;
 
@@ -90,6 +93,21 @@ typedef struct Worker {
         Event *event;
 } Worker;
 
+static void event_clear_dependencies(Event *event) {
+        assert(event);
+
+        Event *e;
+        while ((e = set_steal_first(event->blocker_events)))
+                assert_se(set_remove(e->blocking_events, event) == event);
+        event->blocker_events = set_free(event->blocker_events);
+
+        while ((e = set_steal_first(event->blocking_events)))
+                assert_se(set_remove(e->blocker_events, event) == event);
+        event->blocking_events = set_free(event->blocking_events);
+
+        event->dependencies_built = false;
+}
+
 static Event* event_free(Event *event) {
         if (!event)
                 return NULL;
@@ -103,6 +121,8 @@ static Event* event_free(Event *event) {
         if (event->worker)
                 event->worker->event = NULL;
 
+        event_clear_dependencies(event);
+
         sd_device_unref(event->dev);
 
         sd_event_source_unref(event->retry_event_source);
@@ -584,85 +604,65 @@ bool devpath_conflict(const char *a, const char *b) {
         return *a == '/' || *b == '/' || *a == *b;
 }
 
-static int event_is_blocked(Event *event) {
-        Event *loop_event = NULL;
+static int event_build_dependencies(Event *event) {
         int r;
 
-        /* lookup event for identical, parent, child device */
-
         assert(event);
-        assert(event->manager);
-        assert(event->blocker_seqnum <= event->seqnum);
-
-        if (event->retry_again_next_usec > 0) {
-                usec_t now_usec;
-
-                r = sd_event_now(event->manager->event, CLOCK_BOOTTIME, &now_usec);
-                if (r < 0)
-                        return r;
-
-                if (event->retry_again_next_usec > now_usec)
-                        return true;
-        }
 
-        if (event->blocker_seqnum == event->seqnum)
-                /* we have checked previously and no blocker found */
-                return false;
+        /* lookup event for identical, parent, child device */
 
-        LIST_FOREACH(event, e, event->manager->events) {
-                loop_event = e;
+        if (event->dependencies_built)
+                return 0;
 
-                /* we already found a later event, earlier cannot block us, no need to check again */
-                if (loop_event->seqnum < event->blocker_seqnum)
+        LIST_FOREACH_BACKWARDS(event, e, event->event_prev) {
+                if (!streq_ptr(event->id, e->id) &&
+                    !devpath_conflict(event->devpath, e->devpath) &&
+                    !devpath_conflict(event->devpath, e->devpath_old) &&
+                    !devpath_conflict(event->devpath_old, e->devpath) &&
+                    !(event->devnode && streq_ptr(event->devnode, e->devnode)))
                         continue;
 
-                /* event we checked earlier still exists, no need to check again */
-                if (loop_event->seqnum == event->blocker_seqnum)
-                        return true;
+                r = set_ensure_put(&event->blocker_events, NULL, e);
+                if (r < 0)
+                        return r;
 
-                /* found ourself, no later event can block us */
-                if (loop_event->seqnum >= event->seqnum)
-                        goto no_blocker;
+                r = set_ensure_put(&e->blocking_events, NULL, event);
+                if (r < 0) {
+                        assert_se(set_remove(event->blocker_events, e) == e);
+                        return r;
+                }
 
-                /* found event we have not checked */
-                break;
+                log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
+                                 event->seqnum, e->seqnum);
         }
 
-        assert(loop_event);
-        assert(loop_event->seqnum > event->blocker_seqnum &&
-               loop_event->seqnum < event->seqnum);
+        event->dependencies_built = true;
+        return 0;
+}
 
-        /* check if queue contains events we depend on */
-        LIST_FOREACH(event, e, loop_event) {
-                loop_event = e;
+static int event_is_blocked(Event *event) {
+        int r;
 
-                /* found ourself, no later event can block us */
-                if (loop_event->seqnum >= event->seqnum)
-                        goto no_blocker;
+        assert(event);
+        assert(event->manager);
 
-                if (streq_ptr(loop_event->id, event->id))
-                        break;
+        if (event->retry_again_next_usec > 0) {
+                assert(event->dependencies_built);
 
-                if (devpath_conflict(event->devpath, loop_event->devpath) ||
-                    devpath_conflict(event->devpath, loop_event->devpath_old) ||
-                    devpath_conflict(event->devpath_old, loop_event->devpath))
-                        break;
+                usec_t now_usec;
+                r = sd_event_now(event->manager->event, CLOCK_BOOTTIME, &now_usec);
+                if (r < 0)
+                        return r;
 
-                if (event->devnode && streq_ptr(event->devnode, loop_event->devnode))
-                        break;
+                if (event->retry_again_next_usec > now_usec)
+                        return true;
         }
 
-        assert(loop_event);
-
-        log_device_debug(event->dev, "SEQNUM=%" PRIu64 " blocked by SEQNUM=%" PRIu64,
-                         event->seqnum, loop_event->seqnum);
-
-        event->blocker_seqnum = loop_event->seqnum;
-        return true;
+        r = event_build_dependencies(event);
+        if (r < 0)
+                return r;
 
-no_blocker:
-        event->blocker_seqnum = event->seqnum;
-        return false;
+        return !set_isempty(event->blocker_events);
 }
 
 static bool manager_can_process_event(Manager *manager) {