static int service_dispatch_exec_io(sd_event_source *source, int fd, uint32_t events, void *userdata);
static void service_enter_signal(Service *s, ServiceState state, ServiceResult f);
+
+static void service_reload_finish(Service *s, ServiceResult f);
static void service_enter_reload_by_notify(Service *s);
static bool SERVICE_STATE_WITH_MAIN_PROCESS(ServiceState state) {
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;
+ return service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
}
service_set_state(s, SERVICE_RELOAD_NOTIFY);
}
service_set_state(s, SERVICE_RELOAD_SIGNAL);
- } else {
- service_enter_running(s, SERVICE_SUCCESS);
- return;
- }
+ } else
+ return service_reload_finish(s, SERVICE_SUCCESS);
/* Store the timestamp when we started reloading: when reloading via SIGHUP we won't leave the reload
* state until we received both RELOADING=1 and READY=1 with MONOTONIC_USEC= set to a value above
return;
fail:
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
+ service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
}
static bool service_should_reload_extensions(Service *s) {
return;
fail:
- s->reload_result = SERVICE_FAILURE_RESOURCES;
- service_enter_running(s, SERVICE_SUCCESS);
+ service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
}
static void service_run_next_control(Service *s) {
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
+ else if (s->state == SERVICE_RELOAD)
+ service_reload_finish(s, SERVICE_FAILURE_RESOURCES);
+ else
service_enter_stop(s, SERVICE_FAILURE_RESOURCES);
}
}
if (r < 0)
return r;
- s->result = SERVICE_SUCCESS;
- s->reload_result = SERVICE_SUCCESS;
s->main_pid_known = false;
s->main_pid_alien = false;
s->forbid_restart = false;
if (s->state != SERVICE_AUTO_RESTART_QUEUED)
s->n_restarts = 0;
+ s->result = SERVICE_SUCCESS;
+ s->reload_result = SERVICE_SUCCESS;
+ s->reload_begin_usec = USEC_INFINITY;
+
s->status_text = mfree(s->status_text);
s->status_errno = 0;
s->status_bus_error = mfree(s->status_bus_error);
s->mount_request = sd_bus_message_unref(s->mount_request);
}
+static void service_reload_finish(Service *s, ServiceResult f) {
+ assert(s);
+
+ s->reload_result = f;
+ s->reload_begin_usec = USEC_INFINITY;
+
+ /* If notify state is still in dangling NOTIFY_RELOADING, reset it so service_enter_running()
+ * won't get confused (see #37515) */
+ if (s->notify_state == NOTIFY_RELOADING)
+ s->notify_state = _NOTIFY_STATE_INVALID;
+
+ service_enter_running(s, SERVICE_SUCCESS);
+}
+
static int service_stop(Unit *u) {
Service *s = ASSERT_PTR(SERVICE(u));
if (service_load_pid_file(s, true) < 0)
service_search_main_pid(s);
- s->reload_result = f;
-
/* If the last notification we received from the service process indicates
* we are still reloading, then don't leave reloading state just yet, just
* transition into SERVICE_RELOAD_NOTIFY, to wait for the READY=1 coming,
* too. */
- if (s->notify_state == NOTIFY_RELOADING)
+ if (s->notify_state == NOTIFY_RELOADING) {
+ s->reload_result = f;
service_set_state(s, SERVICE_RELOAD_NOTIFY);
- else
- service_enter_running(s, SERVICE_SUCCESS);
+ } else
+ service_reload_finish(s, f);
break;
case SERVICE_REFRESH_EXTENSIONS:
case SERVICE_REFRESH_EXTENSIONS:
log_unit_warning(UNIT(s), "Reload operation timed out. Killing reload process.");
service_kill_control_process(s);
- s->reload_result = SERVICE_FAILURE_TIMEOUT;
- service_enter_running(s, SERVICE_SUCCESS);
+ service_reload_finish(s, SERVICE_FAILURE_TIMEOUT);
break;
case SERVICE_MOUNTING:
monotonic_usec != USEC_INFINITY &&
monotonic_usec >= s->reload_begin_usec)
/* Valid Type=notify-reload protocol? Then we're all good. */
- service_enter_running(s, SERVICE_SUCCESS);
+ service_reload_finish(s, SERVICE_SUCCESS);
else if (s->state == SERVICE_RUNNING) {
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
/* Sending READY=1 while we are reloading informs us that the reloading is complete. */
if (s->state == SERVICE_RELOAD_NOTIFY)
- service_enter_running(s, SERVICE_SUCCESS);
+ service_reload_finish(s, SERVICE_SUCCESS);
} else if (strv_contains(tags, "RELOADING=1")) {