udev: raise priority of post event source above device monitor

The commit bca7d4ab23e90ec8859fbaeadaa5e0ae9e51b398 kept the priority of
the post event source at the default (NORMAL), which is lower than the
device monitor (EVENT_PRIORITY_DEVICE_MONITOR, NORMAL-1). Since a pending
device monitor is always dispatched first, on_post() only runs when the
monitor is not pending, hence the sd_event_source_get_pending() check
added in the previous commit could never be true. Moreover, during a
uevent flood on_post() is starved, and as it is the only caller of
event_queue_start(), idle workers no longer get events assigned.

Let's give the post event source a priority above the device monitor, but
below the worker event sources so that worker completions are observed
before the queue is started.

Also, similar to checking whether the device monitor event source is pending,
when synthesizing change uevents, new uevents may come soon. Do not remove
the queue file and do not kill idle workers in that case.

Follow-up for bca7d4ab23e90ec8859fbaeadaa5e0ae9e51b398.
Fixes #43865.

(cherry picked from commit a0d25767050d76cfbc1f32dcdde3a0c3da5a7423)
This commit is contained in:
Yu Watanabe
2026-10-16 17:24:50 +01:00
committed by Luca Boccassi
parent 6eb23d3526
commit c20ee1bfc2
2 changed files with 27 additions and 9 deletions
+17 -2
View File
@@ -1312,13 +1312,17 @@ static int on_post(sd_event_source *s, void *userdata) {
if (sd_event_source_get_pending(sd_device_monitor_get_event_source(manager->monitor)) != 0)
return 0;
/* We are currently synthesizing change uevents, hence new uevents may come soon. */
if (!set_isempty(manager->synthesize_change_child_event_sources))
return 0;
(void) manager_unlink_queue_file(manager);
(void) manager_reset_kill_workers_timer(manager);
if (!hashmap_isempty(manager->workers))
return 0; /* There still exist idle workers. */
if (manager->workers_cgroup && set_isempty(manager->synthesize_change_child_event_sources))
if (manager->workers_cgroup)
/* cleanup possible left-over processes in the workers cgroup */
if (cg_kill_kernel_sigkill(manager->workers_cgroup, /* ret_n_pids_killed= */ NULL) == -EOPNOTSUPP)
(void) cg_kill(manager->workers_cgroup, SIGKILL, CGROUP_IGNORE_SELF, /* killed_pids= */ NULL, /* log_kill= */ NULL, /* userdata= */ NULL);
@@ -1379,10 +1383,21 @@ static int manager_setup_event(Manager *manager) {
if (r < 0)
return log_error_errno(r, "Failed to create SIGHUP event source: %m");
r = sd_event_add_post(e, /* ret= */ NULL, on_post, manager);
_cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL;
r = sd_event_add_post(e, &s, on_post, manager);
if (r < 0)
return log_error_errno(r, "Failed to create post event source: %m");
r = sd_event_source_set_priority(s, EVENT_PRIORITY_POST);
if (r < 0)
return log_error_errno(r, "Failed to set priority to post event source: %m");
(void) sd_event_source_set_description(s, "post-event-source");
r = sd_event_source_set_floating(s, true);
if (r < 0)
return log_error_errno(r, "Failed to set floating to post event source: %m");
/* Eventually, we probably want to do more here on memory pressure, for example, kill idle workers immediately */
r = sd_event_add_memory_pressure(e, /* ret= */ NULL, /* callback= */ NULL, /* userdata= */ NULL);
if (r < 0)
+10 -7
View File
@@ -13,20 +13,23 @@
/* This should have a higher priority than the device monitor and inotify watch, to make device monitor and
* inotify event source stopped as soon as possible when the signal is received. Otherwise, we may continue
* receive events that needs to be serialized anyway. */
#define EVENT_PRIORITY_SIGTERM (SD_EVENT_PRIORITY_NORMAL - 6)
#define EVENT_PRIORITY_SIGTERM (SD_EVENT_PRIORITY_NORMAL - 7)
/* This must have a higher priority than the worker notification, to make IN_IGNORED event received earlier
* than notifications about requests of adding/removing inotify watches. */
#define EVENT_PRIORITY_INOTIFY_WATCH (SD_EVENT_PRIORITY_NORMAL - 5)
#define EVENT_PRIORITY_INOTIFY_WATCH (SD_EVENT_PRIORITY_NORMAL - 6)
/* This must have a higher priority than the worker exit event, to make notifications about completions of
* processing events received before exit. */
#define EVENT_PRIORITY_WORKER_NOTIFY (SD_EVENT_PRIORITY_NORMAL - 4)
#define EVENT_PRIORITY_WORKER_NOTIFY (SD_EVENT_PRIORITY_NORMAL - 5)
/* This should have a higher priority than timer events about killing long running worker processes or idle
* worker processes. */
#define EVENT_PRIORITY_WORKER_EXIT (SD_EVENT_PRIORITY_NORMAL - 3)
#define EVENT_PRIORITY_WORKER_EXIT (SD_EVENT_PRIORITY_NORMAL - 4)
/* As mentioned above, this should have a lower priority than the exit event source. */
#define EVENT_PRIORITY_WORKER_TIMER (SD_EVENT_PRIORITY_NORMAL - 2)
/* This must have a lower priority than the worker event source. Otherwise, flood of uevents delays worker
* sigchld events or notifications, and workers will not continue to process events. */
#define EVENT_PRIORITY_WORKER_TIMER (SD_EVENT_PRIORITY_NORMAL - 3)
/* This must have a higher priority than the device monitor to prevent uevent floods from starving
* event_queue_start(), but lower than worker event sources to observe worker completions first. */
#define EVENT_PRIORITY_POST (SD_EVENT_PRIORITY_NORMAL - 2)
/* This must have a lower priority than the worker event source and post event source. Otherwise, flood of
* uevents delays worker sigchld events or notifications, and workers will not continue to process events. */
#define EVENT_PRIORITY_DEVICE_MONITOR (SD_EVENT_PRIORITY_NORMAL - 1)
/* This should have a lower priority than most event sources, but let's process earlier than varlink and the
* legacy control socket. */