From: Daan De Meyer Date: Tue, 21 Apr 2026 08:44:44 +0000 (+0000) Subject: udev: don't assert on worker cap after killing a broken idle worker X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=181a9f65a7cf9059da0f2a44e2152d7636446b33;p=thirdparty%2Fsystemd.git udev: don't assert on worker cap after killing a broken idle worker manager_can_process_event() considers an event processable if either there is room below children_max to spawn, or an idle worker exists. When only the latter holds, event_run() picks the idle worker and tries device_monitor_send(). If that send fails, event_run() SIGKILLs the worker, marks it WORKER_KILLED and continues the loop. With no other idle worker available, it falls through to worker_spawn(), guarded by: assert(hashmap_size(manager->workers) < manager->config.children_max); The just-killed worker is still in manager->workers until its SIGCHLD is reaped by on_worker_exit(), so at the cap this assertion trips and udevd aborts: Assertion 'hashmap_size(manager->workers) < manager->config.children_max' failed at src/udev/udev-manager.c:635, function event_run(). Aborting. Instead of asserting, bail out when we are already at the worker limit. The event remains in EVENT_QUEUED; once the killed worker's SIGCHLD arrives and frees it from the hashmap, on_post() re-runs event_queue_start() and the event is retried. --- diff --git a/src/udev/udev-manager.c b/src/udev/udev-manager.c index 46c8a85d986..7c2530f17fe 100644 --- a/src/udev/udev-manager.c +++ b/src/udev/udev-manager.c @@ -631,8 +631,13 @@ static int event_run(Event *event) { return 0; } + /* No idle worker could accept the event. If we already reached the worker limit, e.g. because + * we just killed the only idle worker above, leave the event queued and wait for SIGCHLD of an + * exiting worker to free up a slot. on_post() will retry processing the queue. */ + if (hashmap_size(manager->workers) >= manager->config.children_max) + return 0; + /* start new worker and pass initial device */ - assert(hashmap_size(manager->workers) < manager->config.children_max); r = worker_spawn(manager, event); if (r < 0) return r;