]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/core/service.c
core: move pid watch/unwatch logic of the service manager to pidfd
[thirdparty/systemd.git] / src / core / service.c
index edb39c6df6a64f44cb08b2a08463f0d9fb401876..8dc98813502eaeed39f8bef5288136013d45d084 100644 (file)
@@ -155,7 +155,7 @@ static void service_unwatch_control_pid(Service *s) {
         if (!pidref_is_set(&s->control_pid))
                 return;
 
-        unit_unwatch_pid(UNIT(s), s->control_pid.pid);
+        unit_unwatch_pidref(UNIT(s), &s->control_pid);
         pidref_done(&s->control_pid);
 }
 
@@ -165,7 +165,7 @@ static void service_unwatch_main_pid(Service *s) {
         if (!pidref_is_set(&s->main_pid))
                 return;
 
-        unit_unwatch_pid(UNIT(s), s->main_pid.pid);
+        unit_unwatch_pidref(UNIT(s), &s->main_pid);
         pidref_done(&s->main_pid);
 }
 
@@ -620,33 +620,9 @@ static usec_t service_running_timeout(Service *s) {
 }
 
 static int service_arm_timer(Service *s, bool relative, usec_t usec) {
-        int r;
-
         assert(s);
 
-        if (s->timer_event_source) {
-                r = (relative ? sd_event_source_set_time_relative : sd_event_source_set_time)(s->timer_event_source, usec);
-                if (r < 0)
-                        return r;
-
-                return sd_event_source_set_enabled(s->timer_event_source, SD_EVENT_ONESHOT);
-        }
-
-        if (usec == USEC_INFINITY)
-                return 0;
-
-        r = (relative ? sd_event_add_time_relative : sd_event_add_time)(
-                        UNIT(s)->manager->event,
-                        &s->timer_event_source,
-                        CLOCK_MONOTONIC,
-                        usec, 0,
-                        service_dispatch_timer, s);
-        if (r < 0)
-                return r;
-
-        (void) sd_event_source_set_description(s->timer_event_source, "service-timer");
-
-        return 0;
+        return unit_arm_timer(UNIT(s), &s->timer_event_source, relative, usec, service_dispatch_timer);
 }
 
 static int service_verify(Service *s) {
@@ -1088,28 +1064,28 @@ static void service_dump(Unit *u, FILE *f, const char *prefix) {
         cgroup_context_dump(UNIT(s), f, prefix);
 }
 
-static int service_is_suitable_main_pid(Service *s, pid_t pid, int prio) {
+static int service_is_suitable_main_pid(Service *s, PidRef *pid, int prio) {
         Unit *owner;
 
         assert(s);
-        assert(pid_is_valid(pid));
+        assert(pidref_is_set(pid));
 
         /* Checks whether the specified PID is suitable as main PID for this service. returns negative if not, 0 if the
          * PID is questionnable but should be accepted if the source of configuration is trusted. > 0 if the PID is
          * good */
 
-        if (pid == getpid_cached() || pid == 1)
-                return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the manager, refusing.", pid);
+        if (pid->pid == getpid_cached() || pid->pid == 1)
+                return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the manager, refusing.", pid->pid);
 
-        if (pid == s->control_pid.pid)
-                return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the control process, refusing.", pid);
+        if (pidref_equal(pid, &s->control_pid))
+                return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(EPERM), "New main PID "PID_FMT" is the control process, refusing.", pid->pid);
 
-        if (!pid_is_alive(pid))
-                return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(ESRCH), "New main PID "PID_FMT" does not exist or is a zombie.", pid);
+        if (!pid_is_alive(pid->pid))
+                return log_unit_full_errno(UNIT(s), prio, SYNTHETIC_ERRNO(ESRCH), "New main PID "PID_FMT" does not exist or is a zombie.", pid->pid);
 
-        owner = manager_get_unit_by_pid(UNIT(s)->manager, pid);
+        owner = manager_get_unit_by_pidref(UNIT(s)->manager, pid);
         if (owner == UNIT(s)) {
-                log_unit_debug(UNIT(s), "New main PID "PID_FMT" belongs to service, we are happy.", pid);
+                log_unit_debug(UNIT(s), "New main PID "PID_FMT" belongs to service, we are happy.", pid->pid);
                 return 1; /* Yay, it's definitely a good PID */
         }
 
@@ -1122,7 +1098,6 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         _cleanup_free_ char *k = NULL;
         _cleanup_close_ int fd = -EBADF;
         int r, prio;
-        pid_t pid;
 
         assert(s);
 
@@ -1152,18 +1127,14 @@ static int service_load_pid_file(Service *s, bool may_warn) {
                                             "Can't convert PID files %s O_PATH file descriptor to proper file descriptor: %m",
                                             s->pid_file);
 
-        r = parse_pid(k, &pid);
+        r = pidref_set_pidstr(&pidref, k);
         if (r < 0)
                 return log_unit_full_errno(UNIT(s), prio, r, "Failed to parse PID from file %s: %m", s->pid_file);
 
-        if (s->main_pid_known && pid == s->main_pid.pid)
+        if (s->main_pid_known && pidref_equal(&pidref, &s->main_pid))
                 return 0;
 
-        r = pidref_set_pid(&pidref, pid);
-        if (r < 0)
-                return log_unit_full_errno(UNIT(s), prio, r, "Failed to pin PID " PID_FMT ": %m", pid);
-
-        r = service_is_suitable_main_pid(s, pidref.pid, prio);
+        r = service_is_suitable_main_pid(s, &pidref, prio);
         if (r < 0)
                 return r;
         if (r == 0) {
@@ -1197,7 +1168,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), s->main_pid.pid, /* exclusive= */ false);
+        r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ 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", s->main_pid.pid);
 
@@ -1205,7 +1176,7 @@ static int service_load_pid_file(Service *s, bool may_warn) {
 }
 
 static void service_search_main_pid(Service *s) {
-        pid_t pid = 0;
+        _cleanup_(pidref_done) PidRef pid = PIDREF_NULL;
         int r;
 
         assert(s);
@@ -1222,11 +1193,11 @@ static void service_search_main_pid(Service *s) {
         if (unit_search_main_pid(UNIT(s), &pid) < 0)
                 return;
 
-        log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid);
-        if (service_set_main_pid(s, pid) < 0)
+        log_unit_debug(UNIT(s), "Main PID guessed: "PID_FMT, pid.pid);
+        if (service_set_main_pidref(s, &pid) < 0)
                 return;
 
-        r = unit_watch_pid(UNIT(s), s->main_pid.pid, /* exclusive= */ false);
+        r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ 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", s->main_pid.pid);
@@ -1366,7 +1337,7 @@ static int service_coldplug(Unit *u) {
                     SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY,
                     SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                     SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL))) {
-                r = unit_watch_pid(UNIT(s), s->main_pid.pid, /* exclusive= */ false);
+                r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
                 if (r < 0)
                         return r;
         }
@@ -1379,7 +1350,7 @@ static int service_coldplug(Unit *u) {
                    SERVICE_STOP, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL, SERVICE_STOP_POST,
                    SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
                    SERVICE_CLEANING)) {
-                r = unit_watch_pid(UNIT(s), s->control_pid.pid, /* exclusive= */ false);
+                r = unit_watch_pidref(UNIT(s), &s->control_pid, /* exclusive= */ false);
                 if (r < 0)
                         return r;
         }
@@ -1857,7 +1828,7 @@ static int service_spawn_internal(
         if (r < 0)
                 return r;
 
-        r = unit_watch_pid(UNIT(s), pidref.pid, /* exclusive= */ true);
+        r = unit_watch_pidref(UNIT(s), &pidref, /* exclusive= */ true);
         if (r < 0)
                 return r;
 
@@ -2037,8 +2008,11 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
                 restart_usec_next = service_restart_usec_next(s);
 
                 r = service_arm_timer(s, /* relative= */ true, restart_usec_next);
-                if (r < 0)
-                        goto fail;
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to install restart timer: %m");
+                        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ false);
+                        return;
+                }
 
                 log_unit_debug(UNIT(s), "Next restart interval calculated as: %s", FORMAT_TIMESPAN(restart_usec_next, 0));
 
@@ -2082,12 +2056,6 @@ static void service_enter_dead(Service *s, ServiceResult f, bool allow_restart)
 
         /* Reset TTY ownership if necessary */
         exec_context_revert_tty(&s->exec_context);
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run install restart timer: %m");
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
 }
 
 static void service_enter_stop_post(Service *s, ServiceResult f) {
@@ -2110,18 +2078,15 @@ static void service_enter_stop_post(Service *s, ServiceResult f) {
                                   s->timeout_stop_usec,
                                   EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_IS_CONTROL|EXEC_SETENV_RESULT|EXEC_CONTROL_CGROUP,
                                   &s->control_pid);
-                if (r < 0)
-                        goto fail;
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop-post' task: %m");
+                        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
+                        return;
+                }
 
                 service_set_state(s, SERVICE_STOP_POST);
         } else
                 service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop-post' task: %m");
-        service_enter_signal(s, SERVICE_FINAL_SIGTERM, SERVICE_FAILURE_RESOURCES);
 }
 
 static int state_to_kill_operation(Service *s, ServiceState state) {
@@ -2171,14 +2136,18 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
                         &s->main_pid,
                         &s->control_pid,
                         s->main_pid_alien);
-        if (r < 0)
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
                 goto fail;
+        }
 
         if (r > 0) {
                 r = service_arm_timer(s, /* relative= */ true,
                                       kill_operation == KILL_WATCHDOG ? service_timeout_abort_usec(s) : s->timeout_stop_usec);
-                if (r < 0)
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
                         goto fail;
+                }
 
                 service_set_state(s, state);
         } else if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM) && s->kill_context.send_sigkill)
@@ -2188,25 +2157,30 @@ static void service_enter_signal(Service *s, ServiceState state, ServiceResult f
         else if (IN_SET(state, SERVICE_FINAL_WATCHDOG, SERVICE_FINAL_SIGTERM) && s->kill_context.send_sigkill)
                 service_enter_signal(s, SERVICE_FINAL_SIGKILL, SERVICE_SUCCESS);
         else
-                service_enter_dead(s, SERVICE_SUCCESS, true);
+                service_enter_dead(s, SERVICE_SUCCESS, /* allow_restart= */ true);
 
         return;
 
 fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to kill processes: %m");
-
         if (IN_SET(state, SERVICE_STOP_WATCHDOG, SERVICE_STOP_SIGTERM, SERVICE_STOP_SIGKILL))
                 service_enter_stop_post(s, SERVICE_FAILURE_RESOURCES);
         else
-                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
 }
 
 static void service_enter_stop_by_notify(Service *s) {
+        int r;
+
         assert(s);
 
         (void) unit_enqueue_rewatch_pids(UNIT(s));
 
-        service_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
+        r = service_arm_timer(s, /* relative= */ true, s->timeout_stop_usec);
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+                return;
+        }
 
         /* The service told us it's stopping, so it's as if we SIGTERM'd it. */
         service_set_state(s, SERVICE_STOP_SIGTERM);
@@ -2233,18 +2207,15 @@ static void service_enter_stop(Service *s, ServiceResult f) {
                                   s->timeout_stop_usec,
                                   EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_SETENV_RESULT|EXEC_CONTROL_CGROUP,
                                   &s->control_pid);
-                if (r < 0)
-                        goto fail;
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'stop' task: %m");
+                        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+                        return;
+                }
 
                 service_set_state(s, SERVICE_STOP);
         } else
                 service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'stop' task: %m");
-        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
 }
 
 static bool service_good(Service *s) {
@@ -2268,6 +2239,8 @@ static bool service_good(Service *s) {
 }
 
 static void service_enter_running(Service *s, ServiceResult f) {
+        int r;
+
         assert(s);
 
         if (s->result == SERVICE_SUCCESS)
@@ -2286,7 +2259,13 @@ static void service_enter_running(Service *s, ServiceResult f) {
                         service_enter_stop_by_notify(s);
                 else {
                         service_set_state(s, SERVICE_RUNNING);
-                        service_arm_timer(s, /* relative= */ false, service_running_timeout(s));
+
+                        r = service_arm_timer(s, /* relative= */ false, service_running_timeout(s));
+                        if (r < 0) {
+                                log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+                                service_enter_running(s, SERVICE_FAILURE_RESOURCES);
+                                return;
+                        }
                 }
 
         } else if (s->remain_after_exit)
@@ -2312,18 +2291,15 @@ static void service_enter_start_post(Service *s) {
                                   s->timeout_start_usec,
                                   EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
                                   &s->control_pid);
-                if (r < 0)
-                        goto fail;
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-post' task: %m");
+                        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+                        return;
+                }
 
                 service_set_state(s, SERVICE_START_POST);
         } else
                 service_enter_running(s, SERVICE_SUCCESS);
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-post' task: %m");
-        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
 }
 
 static void service_kill_control_process(Service *s) {
@@ -2425,8 +2401,10 @@ static void service_enter_start(Service *s) {
                           timeout,
                           EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_WRITE_CREDENTIALS|EXEC_SETENV_MONITOR_RESULT,
                           &pidref);
-        if (r < 0)
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start' task: %m");
                 goto fail;
+        }
 
         if (IN_SET(s->type, SERVICE_SIMPLE, SERVICE_IDLE)) {
                 /* For simple services we immediately start
@@ -2459,7 +2437,6 @@ static void service_enter_start(Service *s) {
         return;
 
 fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'start' task: %m");
         service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
 }
 
@@ -2484,8 +2461,10 @@ static void service_enter_start_pre(Service *s) {
                                   s->timeout_start_usec,
                                   EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN|EXEC_SETENV_MONITOR_RESULT|EXEC_WRITE_CREDENTIALS,
                                   &s->control_pid);
-                if (r < 0)
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'start-pre' task: %m");
                         goto fail;
+                }
 
                 service_set_state(s, SERVICE_START_PRE);
         } else
@@ -2494,8 +2473,7 @@ static void service_enter_start_pre(Service *s) {
         return;
 
 fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'start-pre' task: %m");
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
 }
 
 static void service_enter_condition(Service *s) {
@@ -2521,8 +2499,10 @@ static void service_enter_condition(Service *s) {
                                   EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_APPLY_TTY_STDIN,
                                   &s->control_pid);
 
-                if (r < 0)
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'exec-condition' task: %m");
                         goto fail;
+                }
 
                 service_set_state(s, SERVICE_CONDITION);
         } else
@@ -2531,8 +2511,7 @@ static void service_enter_condition(Service *s) {
         return;
 
 fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run 'exec-condition' task: %m");
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
+        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
 }
 
 static void service_enter_restart(Service *s) {
@@ -2550,8 +2529,11 @@ static void service_enter_restart(Service *s) {
         /* Any units that are bound to this service must also be restarted. We use JOB_START for ourselves
          * but then set JOB_RESTART_DEPENDENCIES which will enqueue JOB_RESTART for those dependency jobs. */
         r = manager_add_job(UNIT(s)->manager, JOB_START, UNIT(s), JOB_RESTART_DEPENDENCIES, NULL, &error, NULL);
-        if (r < 0)
-                goto fail;
+        if (r < 0) {
+                log_unit_warning(UNIT(s), "Failed to schedule restart job: %s", bus_error_message(&error, r));
+                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ false);
+                return;
+        }
 
         /* Count the jobs we enqueue for restarting. This counter is maintained as long as the unit isn't
          * fully stopped, i.e. as long as it remains up or remains in auto-start states. The user can reset
@@ -2572,11 +2554,6 @@ static void service_enter_restart(Service *s) {
 
         /* Notify clients about changed restart counter */
         unit_add_to_dbus_queue(UNIT(s));
-        return;
-
-fail:
-        log_unit_warning(UNIT(s), "Failed to schedule restart job: %s", bus_error_message(&error, r));
-        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, false);
 }
 
 static void service_enter_reload_by_notify(Service *s) {
@@ -2585,13 +2562,20 @@ static void service_enter_reload_by_notify(Service *s) {
 
         assert(s);
 
-        service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+        r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+                s->reload_result = SERVICE_FAILURE_RESOURCES;
+                service_enter_running(s, SERVICE_SUCCESS);
+                return;
+        }
+
         service_set_state(s, SERVICE_RELOAD_NOTIFY);
 
         /* service_enter_reload_by_notify is never called during a reload, thus no loops are possible. */
         r = manager_propagate_reload(UNIT(s)->manager, UNIT(s), JOB_FAIL, &error);
         if (r < 0)
-                log_unit_warning(UNIT(s), "Failed to schedule propagation of reload: %s", bus_error_message(&error, r));
+                log_unit_warning(UNIT(s), "Failed to schedule propagation of reload, ignoring: %s", bus_error_message(&error, r));
 }
 
 static void service_enter_reload(Service *s) {
@@ -2626,13 +2610,18 @@ static void service_enter_reload(Service *s) {
                                   EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_IS_CONTROL|EXEC_CONTROL_CGROUP,
                                   &s->control_pid);
                 if (r < 0) {
-                        log_unit_warning_errno(UNIT(s), r, "Failed to run 'reload' task: %m");
+                        log_unit_warning_errno(UNIT(s), r, "Failed to spawn 'reload' task: %m");
                         goto fail;
                 }
 
                 service_set_state(s, SERVICE_RELOAD);
         } else if (killed) {
-                service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+                r = service_arm_timer(s, /* relative= */ true, s->timeout_start_usec);
+                if (r < 0) {
+                        log_unit_warning_errno(UNIT(s), r, "Failed to install timer: %m");
+                        goto fail;
+                }
+
                 service_set_state(s, SERVICE_RELOAD_SIGNAL);
         } else {
                 service_enter_running(s, SERVICE_SUCCESS);
@@ -2681,23 +2670,19 @@ static void service_run_next_control(Service *s) {
                           (IN_SET(s->control_command_id, SERVICE_EXEC_START_PRE, SERVICE_EXEC_START) ? EXEC_SETENV_MONITOR_RESULT : 0)|
                           (IN_SET(s->control_command_id, SERVICE_EXEC_START_POST, SERVICE_EXEC_RELOAD, SERVICE_EXEC_STOP, SERVICE_EXEC_STOP_POST) ? EXEC_CONTROL_CGROUP : 0),
                           &s->control_pid);
-        if (r < 0)
-                goto fail;
-
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run next control task: %m");
-
-        if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START_POST, SERVICE_STOP))
-                service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
-        else if (s->state == SERVICE_STOP_POST)
-                service_enter_dead(s, SERVICE_FAILURE_RESOURCES, true);
-        else if (s->state == SERVICE_RELOAD) {
-                s->reload_result = SERVICE_FAILURE_RESOURCES;
-                service_enter_running(s, SERVICE_SUCCESS);
-        } else
-                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to spawn next control task: %m");
+
+                if (IN_SET(s->state, SERVICE_CONDITION, SERVICE_START_PRE, SERVICE_START_POST, SERVICE_STOP))
+                        service_enter_signal(s, SERVICE_STOP_SIGTERM, SERVICE_FAILURE_RESOURCES);
+                else if (s->state == SERVICE_STOP_POST)
+                        service_enter_dead(s, SERVICE_FAILURE_RESOURCES, /* allow_restart= */ true);
+                else if (s->state == SERVICE_RELOAD) {
+                        s->reload_result = SERVICE_FAILURE_RESOURCES;
+                        service_enter_running(s, SERVICE_SUCCESS);
+                } else
+                        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+        }
 }
 
 static void service_run_next_main(Service *s) {
@@ -2717,15 +2702,13 @@ static void service_run_next_main(Service *s) {
                           s->timeout_start_usec,
                           EXEC_PASS_FDS|EXEC_APPLY_SANDBOXING|EXEC_APPLY_CHROOT|EXEC_APPLY_TTY_STDIN|EXEC_SET_WATCHDOG|EXEC_SETENV_MONITOR_RESULT|EXEC_WRITE_CREDENTIALS,
                           &pidref);
-        if (r < 0)
-                goto fail;
+        if (r < 0) {
+                log_unit_warning_errno(UNIT(s), r, "Failed to spawn next main task: %m");
+                service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
+                return;
+        }
 
         (void) service_set_main_pidref(s, &pidref);
-        return;
-
-fail:
-        log_unit_warning_errno(UNIT(s), r, "Failed to run next main task: %m");
-        service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
 }
 
 static int service_start(Unit *u) {
@@ -3487,18 +3470,17 @@ static int service_watch_pid_file(Service *s) {
         log_unit_debug(UNIT(s), "Setting watch for PID file %s", s->pid_file_pathspec->path);
 
         r = path_spec_watch(s->pid_file_pathspec, service_dispatch_inotify_io);
-        if (r < 0)
-                goto fail;
+        if (r < 0) {
+                log_unit_error_errno(UNIT(s), r, "Failed to set a watch for PID file %s: %m", s->pid_file_pathspec->path);
+                service_unwatch_pid_file(s);
+                return r;
+        }
 
         /* the pidfile might have appeared just before we set the watch */
         log_unit_debug(UNIT(s), "Trying to read PID file %s in case it changed", s->pid_file_pathspec->path);
         service_retry_pid_file(s);
 
         return 0;
-fail:
-        log_unit_error_errno(UNIT(s), r, "Failed to set a watch for PID file %s: %m", s->pid_file_pathspec->path);
-        service_unwatch_pid_file(s);
-        return r;
 }
 
 static int service_demand_pid_file(Service *s) {
@@ -4412,28 +4394,29 @@ static void service_notify_message(
         /* Interpret MAINPID= */
         e = strv_find_startswith(tags, "MAINPID=");
         if (e && IN_SET(s->state, SERVICE_START, SERVICE_START_POST, SERVICE_RUNNING, SERVICE_RELOAD, SERVICE_RELOAD_SIGNAL, SERVICE_RELOAD_NOTIFY)) {
-                pid_t new_main_pid;
+                _cleanup_(pidref_done) PidRef new_main_pid = PIDREF_NULL;
 
-                if (parse_pid(e, &new_main_pid) < 0)
-                        log_unit_warning(u, "Failed to parse MAINPID= field in notification message, ignoring: %s", e);
-                else if (!s->main_pid_known || new_main_pid != s->main_pid.pid) {
+                r = pidref_set_pidstr(&new_main_pid, e);
+                if (r < 0)
+                        log_unit_warning_errno(u, r, "Failed to parse MAINPID=%s field in notification message, ignoring: %m", e);
+                else if (!s->main_pid_known || !pidref_equal(&new_main_pid, &s->main_pid)) {
 
-                        r = service_is_suitable_main_pid(s, new_main_pid, LOG_WARNING);
+                        r = service_is_suitable_main_pid(s, &new_main_pid, LOG_WARNING);
                         if (r == 0) {
                                 /* The new main PID is a bit suspicious, which is OK if the sender is privileged. */
 
                                 if (ucred->uid == 0) {
-                                        log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, but we'll accept it as the request to change it came from a privileged process.", new_main_pid);
+                                        log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, but we'll accept it as the request to change it came from a privileged process.", new_main_pid.pid);
                                         r = 1;
                                 } else
-                                        log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, refusing.", new_main_pid);
+                                        log_unit_debug(u, "New main PID "PID_FMT" does not belong to service, refusing.", new_main_pid.pid);
                         }
                         if (r > 0) {
-                                (void) service_set_main_pid(s, new_main_pid);
+                                (void) service_set_main_pidref(s, &new_main_pid);
 
-                                r = unit_watch_pid(UNIT(s), new_main_pid, /* exclusive= */ false);
+                                r = unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ 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);
+                                        log_unit_warning_errno(UNIT(s), r, "Failed to watch new main PID "PID_FMT" for service: %m", s->main_pid.pid);
 
                                 notify_dbus = true;
                         }
@@ -4666,6 +4649,7 @@ static bool pick_up_pid_from_bus_name(Service *s) {
 }
 
 static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, sd_bus_error *ret_error) {
+        _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
         const sd_bus_error *e;
         Unit *u = ASSERT_PTR(userdata);
         uint32_t pid;
@@ -4693,15 +4677,16 @@ static int bus_name_pid_lookup_callback(sd_bus_message *reply, void *userdata, s
                 return 1;
         }
 
-        if (!pid_is_valid(pid)) {
-                log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "GetConnectionUnixProcessID() returned invalid PID");
+        r = pidref_set_pid(&pidref, pid);
+        if (r < 0) {
+                log_debug_errno(r, "GetConnectionUnixProcessID() returned invalid PID: %m");
                 return 1;
         }
 
-        log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, (pid_t) pid);
+        log_unit_debug(u, "D-Bus name %s is now owned by process " PID_FMT, s->bus_name, pidref.pid);
 
-        (void) service_set_main_pid(s, pid);
-        (void) unit_watch_pid(UNIT(s), pid, /* exclusive= */ false);
+        (void) service_set_main_pidref(s, &pidref);
+        (void) unit_watch_pidref(UNIT(s), &s->main_pid, /* exclusive= */ false);
         return 1;
 }
 
@@ -4929,18 +4914,21 @@ static int service_clean(Unit *u, ExecCleanMask mask) {
         s->control_command_id = _SERVICE_EXEC_COMMAND_INVALID;
 
         r = service_arm_timer(s, /* relative= */ true, s->exec_context.timeout_clean_usec);
-        if (r < 0)
+        if (r < 0) {
+                log_unit_warning_errno(u, r, "Failed to install timer: %m");
                 goto fail;
+        }
 
         r = unit_fork_and_watch_rm_rf(u, l, &s->control_pid);
-        if (r < 0)
+        if (r < 0) {
+                log_unit_warning_errno(u, r, "Failed to spawn cleaning task: %m");
                 goto fail;
+        }
 
         service_set_state(s, SERVICE_CLEANING);
         return 0;
 
 fail:
-        log_unit_warning_errno(u, r, "Failed to initiate cleaning: %m");
         s->clean_result = SERVICE_FAILURE_RESOURCES;
         s->timer_event_source = sd_event_source_disable_unref(s->timer_event_source);
         return r;