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