core/socket: stop hardcoding every service inactive state

History (c068650fcf,
941a12dcba) has proven
that we're not good at keeping socket and service states
in sync. Instead, let's query the high-level unit_active_state()
first, and only hardcode the two special auto-restart
service states.

Additionally, allow returning to listening state on SERVICE_CLEANING.
This commit is contained in:
Mike Yuan
2024-07-31 20:02:05 +02:00
parent 067c91fcb8
commit 4c523d62d2

View File

@@ -91,6 +91,26 @@ static bool SOCKET_STATE_WITH_PROCESS(SocketState state) {
SOCKET_CLEANING);
}
static bool SOCKET_SERVICE_IS_ACTIVE(Service *s, bool allow_finalize) {
assert(s);
/* If unit_active_state() reports inactive/failed then it's all good, otherwise we need to
* manually exclude SERVICE_AUTO_RESTART and SERVICE_AUTO_RESTART_QUEUED, in which cases
* the start job hasn't been enqueued/run, but are only placeholders in order to allow
* canceling auto restart. */
if (UNIT_IS_INACTIVE_OR_FAILED(unit_active_state(UNIT(s))))
return false;
if (IN_SET(s->state, SERVICE_AUTO_RESTART, SERVICE_AUTO_RESTART_QUEUED))
return false;
if (allow_finalize && IN_SET(s->state, SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL, SERVICE_CLEANING))
return false;
return true;
}
static void socket_init(Unit *u) {
Socket *s = SOCKET(u);
@@ -2469,19 +2489,14 @@ static int socket_start(Unit *u) {
/* Cannot run this without the service being around */
if (UNIT_ISSET(s->service)) {
Service *service;
service = SERVICE(UNIT_DEREF(s->service));
Service *service = ASSERT_PTR(SERVICE(UNIT_DEREF(s->service)));
if (UNIT(service)->load_state != UNIT_LOADED)
return log_unit_error_errno(u, SYNTHETIC_ERRNO(ENOENT),
"Socket service %s not loaded, refusing.", UNIT(service)->id);
/* If the service is already active we cannot start the
* socket */
if (!IN_SET(service->state,
SERVICE_DEAD, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_DEAD_RESOURCES_PINNED, SERVICE_FAILED, SERVICE_FAILED_BEFORE_AUTO_RESTART,
SERVICE_AUTO_RESTART, SERVICE_AUTO_RESTART_QUEUED))
/* If the service is already active we cannot start the socket */
if (SOCKET_SERVICE_IS_ACTIVE(service, /* allow_finalize = */ false))
return log_unit_error_errno(u, SYNTHETIC_ERRNO(EBUSY),
"Socket service %s already active, refusing.", UNIT(service)->id);
}
@@ -3346,7 +3361,8 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
/* Filter out invocations with bogus state */
assert(UNIT_IS_LOAD_COMPLETE(other->load_state));
assert(other->type == UNIT_SERVICE);
Service *service = ASSERT_PTR(SERVICE(other));
/* Don't propagate state changes from the service if we are already down */
if (!IN_SET(s->state, SOCKET_RUNNING, SOCKET_LISTENING))
@@ -3366,11 +3382,8 @@ static void socket_trigger_notify(Unit *u, Unit *other) {
if (other->job)
return;
if (IN_SET(SERVICE(other)->state,
SERVICE_DEAD, SERVICE_DEAD_BEFORE_AUTO_RESTART, SERVICE_DEAD_RESOURCES_PINNED, SERVICE_FAILED, SERVICE_FAILED_BEFORE_AUTO_RESTART,
SERVICE_FINAL_SIGTERM, SERVICE_FINAL_SIGKILL,
SERVICE_AUTO_RESTART, SERVICE_AUTO_RESTART_QUEUED))
socket_enter_listening(s);
if (!SOCKET_SERVICE_IS_ACTIVE(service, /* allow_finalize = */ true))
socket_enter_listening(s);
if (SERVICE(other)->state == SERVICE_RUNNING)
socket_set_state(s, SOCKET_RUNNING);