diff --git a/src/core/cgroup.c b/src/core/cgroup.c index 8db044befa..ad67ba0438 100644 --- a/src/core/cgroup.c +++ b/src/core/cgroup.c @@ -2319,7 +2319,7 @@ static int unit_watch_pids_in_path(Unit *u, const char *path) { pid_t pid; while ((r = cg_read_pid(f, &pid)) > 0) { - r = unit_watch_pid(u, pid); + r = unit_watch_pid(u, pid, false); if (r < 0 && ret >= 0) ret = r; } diff --git a/src/core/dbus-scope.c b/src/core/dbus-scope.c index bb807df2e9..8eb915e508 100644 --- a/src/core/dbus-scope.c +++ b/src/core/dbus-scope.c @@ -106,7 +106,7 @@ static int bus_scope_set_transient_property( return r; if (!UNIT_WRITE_FLAGS_NOOP(flags)) { - r = unit_watch_pid(UNIT(s), pid); + r = unit_watch_pid(UNIT(s), pid, false); if (r < 0 && r != -EEXIST) return r; } diff --git a/src/core/manager.c b/src/core/manager.c index 22d1fda2dc..33785d905f 100644 --- a/src/core/manager.c +++ b/src/core/manager.c @@ -2129,6 +2129,16 @@ void manager_clear_jobs(Manager *m) { job_finish_and_invalidate(j, JOB_CANCELED, false, false); } +void manager_unwatch_pid(Manager *m, pid_t pid) { + assert(m); + + /* First let's drop the unit keyed as "pid". */ + (void) hashmap_remove(m->watch_pids, PID_TO_PTR(pid)); + + /* Then, let's also drop the array keyed by -pid. */ + free(hashmap_remove(m->watch_pids, PID_TO_PTR(-pid))); +} + static int manager_dispatch_run_queue(sd_event_source *source, void *userdata) { Manager *m = userdata; Job *j; diff --git a/src/core/manager.h b/src/core/manager.h index bce8020cfd..c43c587a79 100644 --- a/src/core/manager.h +++ b/src/core/manager.h @@ -437,6 +437,8 @@ int manager_get_dump_string(Manager *m, char **ret); void manager_clear_jobs(Manager *m); +void manager_unwatch_pid(Manager *m, pid_t pid); + unsigned manager_dispatch_load_queue(Manager *m); int manager_default_environment(Manager *m); diff --git a/src/core/mount.c b/src/core/mount.c index a991bf8794..4fb4b0f81e 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -704,7 +704,7 @@ static int mount_coldplug(Unit *u) { pid_is_unwaited(m->control_pid) && MOUNT_STATE_WITH_PROCESS(new_state)) { - r = unit_watch_pid(UNIT(m), m->control_pid); + r = unit_watch_pid(UNIT(m), m->control_pid, false); if (r < 0) return r; @@ -810,9 +810,8 @@ static int mount_spawn(Mount *m, ExecCommand *c, pid_t *_pid) { if (r < 0) return r; - r = unit_watch_pid(UNIT(m), pid); + r = unit_watch_pid(UNIT(m), pid, true); if (r < 0) - /* FIXME: we need to do something here */ return r; *_pid = pid; diff --git a/src/core/service.c b/src/core/service.c index 4682e86f8e..883ca7bbfe 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -990,7 +990,7 @@ static int service_load_pid_file(Service *s, bool may_warn) { if (r < 0) return r; - r = unit_watch_pid(UNIT(s), pid); + r = unit_watch_pid(UNIT(s), pid, false); if (r < 0) /* FIXME: we need to do something here */ return log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" for service: %m", pid); @@ -1020,7 +1020,7 @@ static void service_search_main_pid(Service *s) { if (service_set_main_pid(s, pid) < 0) return; - r = unit_watch_pid(UNIT(s), pid); + r = unit_watch_pid(UNIT(s), pid, false); if (r < 0) /* FIXME: we need to do something here */ log_unit_warning_errno(UNIT(s), r, "Failed to watch PID "PID_FMT" from: %m", pid); @@ -1154,7 +1154,7 @@ static int service_coldplug(Unit *u) { SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) { - r = unit_watch_pid(UNIT(s), s->main_pid); + r = unit_watch_pid(UNIT(s), s->main_pid, false); if (r < 0) return r; } @@ -1166,7 +1166,7 @@ static int service_coldplug(Unit *u) { SERVICE_RELOAD, SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL)) { - r = unit_watch_pid(UNIT(s), s->control_pid); + r = unit_watch_pid(UNIT(s), s->control_pid, false); if (r < 0) return r; } @@ -1566,8 +1566,8 @@ static int service_spawn( s->exec_fd_event_source = TAKE_PTR(exec_fd_source); s->exec_fd_hot = false; - r = unit_watch_pid(UNIT(s), pid); - if (r < 0) /* FIXME: we need to do something here */ + r = unit_watch_pid(UNIT(s), pid, true); + if (r < 0) return r; *_pid = pid; @@ -3705,7 +3705,7 @@ static void service_notify_message( if (r > 0) { service_set_main_pid(s, new_main_pid); - r = unit_watch_pid(UNIT(s), new_main_pid); + r = unit_watch_pid(UNIT(s), new_main_pid, false); if (r < 0) log_unit_warning_errno(UNIT(s), r, "Failed to watch new main PID "PID_FMT" for service: %m", new_main_pid); @@ -3923,7 +3923,7 @@ static void service_bus_name_owner_change( log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, name, pid); service_set_main_pid(s, pid); - unit_watch_pid(UNIT(s), pid); + unit_watch_pid(UNIT(s), pid, false); } } } diff --git a/src/core/socket.c b/src/core/socket.c index fd550290be..1396842b26 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -1852,7 +1852,7 @@ static int socket_coldplug(Unit *u) { SOCKET_FINAL_SIGTERM, SOCKET_FINAL_SIGKILL)) { - r = unit_watch_pid(UNIT(s), s->control_pid); + r = unit_watch_pid(UNIT(s), s->control_pid, false); if (r < 0) return r; @@ -1938,9 +1938,8 @@ static int socket_spawn(Socket *s, ExecCommand *c, pid_t *_pid) { if (r < 0) return r; - r = unit_watch_pid(UNIT(s), pid); + r = unit_watch_pid(UNIT(s), pid, true); if (r < 0) - /* FIXME: we need to do something here */ return r; *_pid = pid; @@ -2009,7 +2008,7 @@ static int socket_chown(Socket *s, pid_t *_pid) { _exit(EXIT_SUCCESS); } - r = unit_watch_pid(UNIT(s), pid); + r = unit_watch_pid(UNIT(s), pid, true); if (r < 0) goto fail; diff --git a/src/core/swap.c b/src/core/swap.c index b836fdd304..28acef2373 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -550,7 +550,7 @@ static int swap_coldplug(Unit *u) { pid_is_unwaited(s->control_pid) && SWAP_STATE_WITH_PROCESS(new_state)) { - r = unit_watch_pid(UNIT(s), s->control_pid); + r = unit_watch_pid(UNIT(s), s->control_pid, false); if (r < 0) return r; @@ -657,9 +657,8 @@ static int swap_spawn(Swap *s, ExecCommand *c, pid_t *_pid) { if (r < 0) goto fail; - r = unit_watch_pid(UNIT(s), pid); + r = unit_watch_pid(UNIT(s), pid, true); if (r < 0) - /* FIXME: we need to do something here */ goto fail; *_pid = pid; diff --git a/src/core/unit.c b/src/core/unit.c index 445cf6695c..5620fd9017 100644 --- a/src/core/unit.c +++ b/src/core/unit.c @@ -2525,7 +2525,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlag unit_add_to_gc_queue(u); } -int unit_watch_pid(Unit *u, pid_t pid) { +int unit_watch_pid(Unit *u, pid_t pid, bool exclusive) { int r; assert(u); @@ -2533,6 +2533,12 @@ int unit_watch_pid(Unit *u, pid_t pid) { /* Watch a specific PID */ + /* Caller might be sure that this PID belongs to this unit only. Let's take this + * opportunity to remove any stalled references to this PID as they can be created + * easily (when watching a process which is not our direct child). */ + if (exclusive) + manager_unwatch_pid(u->manager, pid); + r = set_ensure_allocated(&u->pids, NULL); if (r < 0) return r; diff --git a/src/core/unit.h b/src/core/unit.h index 35b936771c..28878b5f4f 100644 --- a/src/core/unit.h +++ b/src/core/unit.h @@ -678,7 +678,7 @@ typedef enum UnitNotifyFlags { void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, UnitNotifyFlags flags); -int unit_watch_pid(Unit *u, pid_t pid); +int unit_watch_pid(Unit *u, pid_t pid, bool exclusive); void unit_unwatch_pid(Unit *u, pid_t pid); void unit_unwatch_all_pids(Unit *u); diff --git a/src/test/test-watch-pid.c b/src/test/test-watch-pid.c index 2c6ca0a1a2..04d7e1fbd8 100644 --- a/src/test/test-watch-pid.c +++ b/src/test/test-watch-pid.c @@ -42,25 +42,25 @@ int main(int argc, char *argv[]) { assert_se(hashmap_isempty(m->watch_pids)); assert_se(manager_get_unit_by_pid(m, 4711) == NULL); - assert_se(unit_watch_pid(a, 4711) >= 0); + assert_se(unit_watch_pid(a, 4711, false) >= 0); assert_se(manager_get_unit_by_pid(m, 4711) == a); - assert_se(unit_watch_pid(a, 4711) >= 0); + assert_se(unit_watch_pid(a, 4711, false) >= 0); assert_se(manager_get_unit_by_pid(m, 4711) == a); - assert_se(unit_watch_pid(b, 4711) >= 0); + assert_se(unit_watch_pid(b, 4711, false) >= 0); u = manager_get_unit_by_pid(m, 4711); assert_se(u == a || u == b); - assert_se(unit_watch_pid(b, 4711) >= 0); + assert_se(unit_watch_pid(b, 4711, false) >= 0); u = manager_get_unit_by_pid(m, 4711); assert_se(u == a || u == b); - assert_se(unit_watch_pid(c, 4711) >= 0); + assert_se(unit_watch_pid(c, 4711, false) >= 0); u = manager_get_unit_by_pid(m, 4711); assert_se(u == a || u == b || u == c); - assert_se(unit_watch_pid(c, 4711) >= 0); + assert_se(unit_watch_pid(c, 4711, false) >= 0); u = manager_get_unit_by_pid(m, 4711); assert_se(u == a || u == b || u == c);