sd_device_action_t action;
uint64_t seqnum;
- uint64_t blocker_seqnum;
const char *id;
const char *devpath;
const char *devpath_old;
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;
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;
if (event->worker)
event->worker->event = NULL;
+ event_clear_dependencies(event);
+
sd_device_unref(event->dev);
sd_event_source_unref(event->retry_event_source);
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) {