udev: do not wait for event queue being empty on exit
When the manager process is requested to terminate, if a worker process try to lock a block device and failed, then the worker returns a TRY_AGAIN notification and the event is requeued. Hence, the event queue may have pending events even after manager_exit() is called. In such situation, sd_event_exit() will never called, and udevd will stuck. This makes, after termination is requested, it only checks whether there are any events currently being processed.
This commit is contained in:
+22
-6
@@ -588,8 +588,9 @@ static int event_queue_start(Manager *manager) {
|
||||
int r;
|
||||
|
||||
assert(manager);
|
||||
assert(!manager->exit);
|
||||
|
||||
if (!manager->events || manager->exit || manager->stop_exec_queue)
|
||||
if (!manager->events || manager->stop_exec_queue)
|
||||
return 0;
|
||||
|
||||
r = event_source_disable(manager->kill_workers_event);
|
||||
@@ -921,9 +922,29 @@ static int manager_unlink_queue_file(Manager *manager) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_post_exit(Manager *manager) {
|
||||
assert(manager);
|
||||
assert(manager->exit);
|
||||
|
||||
LIST_FOREACH(event, event, manager->events)
|
||||
if (event->state == EVENT_RUNNING)
|
||||
return 0; /* There still exist events being processed. */
|
||||
|
||||
(void) manager_unlink_queue_file(manager);
|
||||
|
||||
if (!hashmap_isempty(manager->workers))
|
||||
return 0; /* There still exist running workers. */
|
||||
|
||||
udev_watch_dump();
|
||||
return sd_event_exit(manager->event, 0);
|
||||
}
|
||||
|
||||
static int on_post(sd_event_source *s, void *userdata) {
|
||||
Manager *manager = ASSERT_PTR(userdata);
|
||||
|
||||
if (manager->exit)
|
||||
return on_post_exit(manager);
|
||||
|
||||
if (manager->events) {
|
||||
/* Try to process pending events if idle workers exist. Why is this necessary?
|
||||
* When a worker finished an event and became idle, even if there was a pending event,
|
||||
@@ -940,11 +961,6 @@ static int on_post(sd_event_source *s, void *userdata) {
|
||||
if (!hashmap_isempty(manager->workers))
|
||||
return 0; /* There still exist idle workers. */
|
||||
|
||||
if (manager->exit) {
|
||||
udev_watch_dump();
|
||||
return sd_event_exit(manager->event, 0);
|
||||
}
|
||||
|
||||
if (manager->cgroup && set_isempty(manager->synthesize_change_child_event_sources))
|
||||
/* cleanup possible left-over processes in our cgroup */
|
||||
(void) cg_kill(manager->cgroup, SIGKILL, CGROUP_IGNORE_SELF, /* set=*/ NULL, /* kill_log= */ NULL, /* userdata= */ NULL);
|
||||
|
||||
Reference in New Issue
Block a user