}
static int event_run(Event *event) {
- static bool log_children_max_reached = true;
- Manager *manager;
- Worker *worker;
+ Manager *manager = ASSERT_PTR(ASSERT_PTR(event)->manager);
int r;
- assert(event);
- assert(event->manager);
-
log_device_uevent(event->dev, "Device ready for processing");
(void) event_source_disable(event->retry_event_source);
- manager = event->manager;
+ Worker *worker;
HASHMAP_FOREACH(worker, manager->workers) {
if (worker->state != WORKER_IDLE)
continue;
continue;
}
worker_attach_event(worker, event);
- return 1; /* event is now processing. */
- }
-
- if (hashmap_size(manager->workers) >= manager->config.children_max) {
- /* Avoid spamming the debug logs if the limit is already reached and
- * many events still need to be processed */
- if (log_children_max_reached && manager->config.children_max > 1) {
- log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
- log_children_max_reached = false;
- }
- return 0; /* no free worker */
+ return 0;
}
- /* Re-enable the debug message for the next batch of events */
- log_children_max_reached = true;
-
/* 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;
- return 1; /* event is now processing. */
+ return 0;
}
bool devpath_conflict(const char *a, const char *b) {
return false;
}
+static bool manager_can_process_event(Manager *manager) {
+ static bool children_max_reached_logged = false;
+
+ assert(manager);
+
+ /* Check if there is a free room for processing an event. */
+
+ if (hashmap_size(manager->workers) < manager->config.children_max)
+ goto yes_we_can; /* new worker can be spawned */
+
+ Worker *worker;
+ HASHMAP_FOREACH(worker, manager->workers)
+ if (worker->state == WORKER_IDLE)
+ goto yes_we_can; /* found an idle worker */
+
+ /* Avoid spamming the debug logs if the limit is already reached and
+ * many events still need to be processed */
+ if (!children_max_reached_logged) {
+ log_debug("Maximum number (%u) of children reached.", hashmap_size(manager->workers));
+ children_max_reached_logged = true;
+ }
+
+ return false;
+
+yes_we_can:
+ /* Re-enable the debug message for the next batch of events */
+ children_max_reached_logged = false;
+ return true;
+}
+
static int event_queue_start(Manager *manager) {
int r;
manager_reload(manager, /* force = */ false);
+ /* manager_reload() may kill idle workers, hence we may not be possible to start processing an event.
+ * Let's check that and return earlier if we cannot. */
+ if (!manager_can_process_event(manager))
+ return 0;
+
LIST_FOREACH(event, event, manager->events) {
if (event->state != EVENT_QUEUED)
continue;
strna(device_action_to_string(event->action)));
r = event_run(event);
- if (r <= 0) /* 0 means there are no idle workers. Let's escape from the loop. */
+ if (r < 0)
return r;
+
+ /* A worker is activated now. Let's check if we can process more events. */
+ if (!manager_can_process_event(manager))
+ break;
}
return 0;