You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
171 lines
6.0 KiB
171 lines
6.0 KiB
From 1ac6c613ef11a9ee9c36b25133cc302c4be1a858 Mon Sep 17 00:00:00 2001 |
|
From: Lennart Poettering <lennart@poettering.net> |
|
Date: Wed, 24 Jan 2018 19:59:55 +0100 |
|
Subject: [PATCH] core: rework how we count the n_on_console counter |
|
|
|
Let's add a per-unit boolean that tells us whether our unit is currently |
|
counted or not. This way it's unlikely we get out of sync again and |
|
things are generally more robust. |
|
|
|
This also allows us to remove the counting logic specific to service |
|
units (which was in fact mostly a copy from the generic implementation), |
|
in favour of fully generic code. |
|
|
|
Replaces: #7824 |
|
(cherry picked from commit adefcf2821a386184991054ed2bb6dacc90d7419) |
|
|
|
Resolves: #1524359 |
|
--- |
|
src/core/manager.c | 15 +++++++++++++++ |
|
src/core/manager.h | 3 +++ |
|
src/core/service.c | 20 -------------------- |
|
src/core/unit.c | 39 +++++++++++++++++++++------------------ |
|
src/core/unit.h | 1 + |
|
5 files changed, 40 insertions(+), 38 deletions(-) |
|
|
|
diff --git a/src/core/manager.c b/src/core/manager.c |
|
index 88d156e8fb..4c87ad8a2f 100644 |
|
--- a/src/core/manager.c |
|
+++ b/src/core/manager.c |
|
@@ -3379,6 +3379,21 @@ ManagerState manager_state(Manager *m) { |
|
return MANAGER_RUNNING; |
|
} |
|
|
|
+void manager_ref_console(Manager *m) { |
|
+ assert(m); |
|
+ |
|
+ m->n_on_console++; |
|
+} |
|
+ |
|
+void manager_unref_console(Manager *m) { |
|
+ |
|
+ assert(m->n_on_console > 0); |
|
+ m->n_on_console--; |
|
+ |
|
+ if (m->n_on_console == 0) |
|
+ m->no_console_output = false; /* unset no_console_output flag, since the console is definitely free now */ |
|
+} |
|
+ |
|
static const char *const manager_state_table[_MANAGER_STATE_MAX] = { |
|
[MANAGER_INITIALIZING] = "initializing", |
|
[MANAGER_STARTING] = "starting", |
|
diff --git a/src/core/manager.h b/src/core/manager.h |
|
index b0e4cad1fc..cfc564dfb6 100644 |
|
--- a/src/core/manager.h |
|
+++ b/src/core/manager.h |
|
@@ -379,5 +379,8 @@ const char *manager_get_runtime_prefix(Manager *m); |
|
|
|
ManagerState manager_state(Manager *m); |
|
|
|
+void manager_ref_console(Manager *m); |
|
+void manager_unref_console(Manager *m); |
|
+ |
|
const char *manager_state_to_string(ManagerState m) _const_; |
|
ManagerState manager_state_from_string(const char *s) _pure_; |
|
diff --git a/src/core/service.c b/src/core/service.c |
|
index 8a8f4be149..ea71c9e237 100644 |
|
--- a/src/core/service.c |
|
+++ b/src/core/service.c |
|
@@ -914,26 +914,6 @@ static void service_set_state(Service *s, ServiceState state) { |
|
if (state == SERVICE_EXITED && UNIT(s)->manager->n_reloading <= 0) |
|
unit_destroy_cgroup_if_empty(UNIT(s)); |
|
|
|
- /* For remain_after_exit services, let's see if we can "release" the |
|
- * hold on the console, since unit_notify() only does that in case of |
|
- * change of state */ |
|
- if (state == SERVICE_EXITED && |
|
- s->remain_after_exit && |
|
- UNIT(s)->manager->n_on_console > 0) { |
|
- |
|
- ExecContext *ec; |
|
- |
|
- ec = unit_get_exec_context(UNIT(s)); |
|
- if (ec && exec_context_may_touch_console(ec)) { |
|
- Manager *m = UNIT(s)->manager; |
|
- |
|
- m->n_on_console --; |
|
- if (m->n_on_console == 0) |
|
- /* unset no_console_output flag, since the console is free */ |
|
- m->no_console_output = false; |
|
- } |
|
- } |
|
- |
|
if (old_state != state) |
|
log_unit_debug(UNIT(s)->id, "%s changed %s -> %s", UNIT(s)->id, service_state_to_string(old_state), service_state_to_string(state)); |
|
|
|
diff --git a/src/core/unit.c b/src/core/unit.c |
|
index 48358bc026..294c9eb70f 100644 |
|
--- a/src/core/unit.c |
|
+++ b/src/core/unit.c |
|
@@ -544,6 +544,9 @@ void unit_free(Unit *u) { |
|
u->manager->n_in_gc_queue--; |
|
} |
|
|
|
+ if (u->on_console) |
|
+ manager_unref_console(u->manager); |
|
+ |
|
condition_free_list(u->conditions); |
|
condition_free_list(u->asserts); |
|
|
|
@@ -1741,6 +1744,23 @@ void unit_trigger_notify(Unit *u) { |
|
UNIT_VTABLE(other)->trigger_notify(other, u); |
|
} |
|
|
|
+static void unit_update_on_console(Unit *u) { |
|
+ bool b; |
|
+ |
|
+ assert(u); |
|
+ |
|
+ b = unit_needs_console(u); |
|
+ if (u->on_console == b) |
|
+ return; |
|
+ |
|
+ u->on_console = b; |
|
+ if (b) |
|
+ manager_ref_console(u->manager); |
|
+ else |
|
+ manager_unref_console(u->manager); |
|
+ |
|
+} |
|
+ |
|
void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_success) { |
|
Manager *m; |
|
bool unexpected; |
|
@@ -1784,24 +1804,7 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su |
|
if (UNIT_IS_INACTIVE_OR_FAILED(ns)) |
|
unit_destroy_cgroup_if_empty(u); |
|
|
|
- /* Note that this doesn't apply to RemainAfterExit services exiting |
|
- * successfully, since there's no change of state in that case. Which is |
|
- * why it is handled in service_set_state() */ |
|
- if (UNIT_IS_INACTIVE_OR_FAILED(os) != UNIT_IS_INACTIVE_OR_FAILED(ns)) { |
|
- ExecContext *ec; |
|
- |
|
- ec = unit_get_exec_context(u); |
|
- if (ec && exec_context_may_touch_console(ec)) { |
|
- if (UNIT_IS_INACTIVE_OR_FAILED(ns)) { |
|
- m->n_on_console --; |
|
- |
|
- if (m->n_on_console == 0) |
|
- /* unset no_console_output flag, since the console is free */ |
|
- m->no_console_output = false; |
|
- } else |
|
- m->n_on_console ++; |
|
- } |
|
- } |
|
+ unit_update_on_console(u); |
|
|
|
if (u->job) { |
|
unexpected = false; |
|
diff --git a/src/core/unit.h b/src/core/unit.h |
|
index fa7de11645..719fc95260 100644 |
|
--- a/src/core/unit.h |
|
+++ b/src/core/unit.h |
|
@@ -238,6 +238,7 @@ struct Unit { |
|
bool no_gc:1; |
|
|
|
bool in_audit:1; |
|
+ bool on_console:1; |
|
|
|
bool cgroup_realized:1; |
|
bool cgroup_members_mask_valid:1;
|
|
|