[systemd-devel] [PATCH] [RFC] Set StopWhenUnneeded=no when unit unneeded, but forced

Oleksii Shevchuk alxchk at gmail.com
Wed Feb 13 15:23:06 PST 2013


---
 src/core/dbus-unit.c                  | 18 +++++++-
 src/core/job.c                        | 27 +++++++++++-
 src/core/job.h                        |  1 +
 src/core/load-fragment-gperf.gperf.m4 |  2 +-
 src/core/load-fragment.c              |  3 ++
 src/core/manager.c                    |  2 +-
 src/core/transaction.c                | 78 +++++++++++++++++++++++++++--------
 src/core/transaction.h                |  1 +
 src/core/unit.c                       | 67 +++++++++++++++++++++++-------
 src/core/unit.h                       |  5 ++-
 10 files changed, 167 insertions(+), 37 deletions(-)

diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c
index d1de46a..91b6f4f 100644
--- a/src/core/dbus-unit.c
+++ b/src/core/dbus-unit.c
@@ -202,6 +202,22 @@ static int bus_unit_append_can_stop(DBusMessageIter *i, const char *property, vo
         return 0;
 }
 
+static int bus_unit_append_stop_when_unneeded(DBusMessageIter *i, const char *property, void *data) {
+        Unit *u = data;
+        dbus_bool_t b;
+
+        assert(i);
+        assert(property);
+        assert(u);
+
+        b = unit_stop_when_unneeded_state(u);
+
+        if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
+                return -ENOMEM;
+
+        return 0;
+}
+
 static int bus_unit_append_can_reload(DBusMessageIter *i, const char *property, void *data) {
         Unit *u = data;
         dbus_bool_t b;
@@ -1236,7 +1252,7 @@ const BusProperty bus_unit_properties[] = {
         { "CanReload",            bus_unit_append_can_reload,         "b", 0 },
         { "CanIsolate",           bus_unit_append_can_isolate,        "b", 0 },
         { "Job",                  bus_unit_append_job,             "(uo)", 0 },
-        { "StopWhenUnneeded",     bus_property_append_bool,           "b", offsetof(Unit, stop_when_unneeded)                 },
+        { "StopWhenUnneeded",     bus_unit_append_stop_when_unneeded, "b", 0 },
         { "RefuseManualStart",    bus_property_append_bool,           "b", offsetof(Unit, refuse_manual_start)                },
         { "RefuseManualStop",     bus_property_append_bool,           "b", offsetof(Unit, refuse_manual_stop)                 },
         { "AllowIsolate",         bus_property_append_bool,           "b", offsetof(Unit, allow_isolate)                      },
diff --git a/src/core/job.c b/src/core/job.c
index 2bafbc1..a4fcc76 100644
--- a/src/core/job.c
+++ b/src/core/job.c
@@ -294,11 +294,13 @@ void job_dump(Job *j, FILE*f, const char *prefix) {
                 "%s-> Job %u:\n"
                 "%s\tAction: %s -> %s\n"
                 "%s\tState: %s\n"
-                "%s\tForced: %s\n",
+                "%s\tForced: %s\n"
+                "%s\tTransaction Root: %s\n",
                 prefix, j->id,
                 prefix, j->unit->id, job_type_to_string(j->type),
                 prefix, job_state_to_string(j->state),
-                prefix, yes_no(j->override));
+                prefix, yes_no(j->override),
+                prefix, yes_no(j->root));
 }
 
 /*
@@ -510,6 +512,20 @@ int job_run_and_invalidate(Job *j) {
         switch (j->type) {
 
                 case JOB_START:
+                        /* Check once again */
+                        if (unit_unneeded(j->unit)) {
+                                if (j->root && j->override) {
+                                        log_debug("Setup StopWhenUnneeded=no for unit %s just before activation",
+                                                  j->unit->id);
+                                        j->unit->stop_when_unneeded_runtime = false;
+                                } else {
+                                        log_debug("Don't start unit %s as it unneeded", j->unit->id);
+                                        unit_notify(j->unit, UNIT_ACTIVATING, UNIT_FAILED, false);
+                                        r = 0;
+                                        break;
+                                }
+                        }
+
                         r = unit_start(j->unit);
 
                         /* If this unit cannot be started, then simply wait */
@@ -946,6 +962,7 @@ int job_serialize(Job *j, FILE *f, FDSet *fds) {
         fprintf(f, "job-id=%u\n", j->id);
         fprintf(f, "job-type=%s\n", job_type_to_string(j->type));
         fprintf(f, "job-state=%s\n", job_state_to_string(j->state));
+        fprintf(f, "job-root=%s\n", yes_no(j->root));
         fprintf(f, "job-override=%s\n", yes_no(j->override));
         fprintf(f, "job-sent-dbus-new-signal=%s\n", yes_no(j->sent_dbus_new_signal));
         fprintf(f, "job-ignore-order=%s\n", yes_no(j->ignore_order));
@@ -1008,6 +1025,12 @@ int job_deserialize(Job *j, FILE *f, FDSet *fds) {
                                 log_debug("Failed to parse job state %s", v);
                         else
                                 j->state = s;
+                } else if (streq(l, "job-root")) {
+                        int b = parse_boolean(v);
+                        if (b < 0)
+                                log_debug("Failed to parse job root flag %s", v);
+                        else
+                                j->root = j->root || b;
                 } else if (streq(l, "job-override")) {
                         int b = parse_boolean(v);
                         if (b < 0)
diff --git a/src/core/job.h b/src/core/job.h
index d10e6b6..dda2298 100644
--- a/src/core/job.h
+++ b/src/core/job.h
@@ -161,6 +161,7 @@ struct Job {
         bool sent_dbus_new_signal:1;
         bool ignore_order:1;
         bool forgot_bus_clients:1;
+        bool root:1;
 };
 
 JobBusClient* job_bus_client_new(DBusConnection *connection, const char *name);
diff --git a/src/core/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 0b6a5cc..08ad459 100644
--- a/src/core/load-fragment-gperf.gperf.m4
+++ b/src/core/load-fragment-gperf.gperf.m4
@@ -114,7 +114,7 @@ Unit.ReloadPropagatedFrom,       config_parse_unit_deps,             UNIT_RELOAD
 Unit.PropagateReloadFrom,        config_parse_unit_deps,             UNIT_RELOAD_PROPAGATED_FROM,   0
 Unit.PartOf,                     config_parse_unit_deps,             UNIT_PART_OF,                  0
 Unit.RequiresMountsFor,          config_parse_unit_requires_mounts_for, 0,                          offsetof(Unit, requires_mounts_for)
-Unit.StopWhenUnneeded,           config_parse_bool,                  0,                             offsetof(Unit, stop_when_unneeded)
+Unit.StopWhenUnneeded,           config_parse_bool,                  0,                             offsetof(Unit, stop_when_unneeded_unit)
 Unit.RefuseManualStart,          config_parse_bool,                  0,                             offsetof(Unit, refuse_manual_start)
 Unit.RefuseManualStop,           config_parse_bool,                  0,                             offsetof(Unit, refuse_manual_stop)
 Unit.AllowIsolate,               config_parse_bool,                  0,                             offsetof(Unit, allow_isolate)
diff --git a/src/core/load-fragment.c b/src/core/load-fragment.c
index 6e333aa..6c0e0a9 100644
--- a/src/core/load-fragment.c
+++ b/src/core/load-fragment.c
@@ -2492,6 +2492,9 @@ static int load_from_path(Unit *u, const char *path) {
                         u->source_mtime = 0;
         }
 
+        /* Syncing unit options to runtime state */
+        u->stop_when_unneeded_runtime = u->stop_when_unneeded_unit;
+
         r = 0;
 
 finish:
diff --git a/src/core/manager.c b/src/core/manager.c
index 28f169d..e99f585 100644
--- a/src/core/manager.c
+++ b/src/core/manager.c
@@ -770,7 +770,7 @@ int manager_add_job(Manager *m, JobType type, Unit *unit, JobMode mode, bool ove
         if (!tr)
                 return -ENOMEM;
 
-        r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, override, false,
+        r = transaction_add_job_and_dependencies(tr, type, unit, NULL, true, true, override, false,
                                                  mode == JOB_IGNORE_DEPENDENCIES || mode == JOB_IGNORE_REQUIREMENTS,
                                                  mode == JOB_IGNORE_DEPENDENCIES, e);
         if (r < 0)
diff --git a/src/core/transaction.c b/src/core/transaction.c
index dbc30af..d989c32 100644
--- a/src/core/transaction.c
+++ b/src/core/transaction.c
@@ -740,7 +740,7 @@ int transaction_activate(Transaction *tr, Manager *m, JobMode mode, DBusError *e
         return 0;
 }
 
-static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool override, bool *is_new) {
+static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, bool root, bool override, bool *is_new) {
         Job *j, *f;
 
         assert(tr);
@@ -770,6 +770,7 @@ static Job* transaction_add_one_job(Transaction *tr, JobType type, Unit *unit, b
         j->marker = NULL;
         j->matters_to_anchor = false;
         j->override = override;
+        j->root = root;
 
         LIST_PREPEND(Job, transaction, f, j);
 
@@ -821,11 +822,50 @@ static void transaction_unlink_job(Transaction *tr, Job *j, bool delete_dependen
         }
 }
 
+static bool transaction_unneeded_setup_and_check(Unit *u, JobType type, bool root, bool override) {
+        Iterator i;
+        Unit *other;
+
+        assert(u);
+
+        if (type != JOB_START)
+                return false;
+
+        /* Follow merge if any */
+        if (!unit_stop_when_unneeded_state(u))
+                return false;
+
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
+                return false;
+
+        SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
+                return false;
+
+        SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
+                return false;
+
+        SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
+                return false;
+
+        /* No potential tranaction found. Dead end */
+        if (root && override) {
+                u->stop_when_unneeded_runtime = false;
+                log_debug("Setup StopWhenUnneeded=no for certanly unneeded transaction for unit %s",
+                          u->id);
+                return false;
+        } else {
+                log_debug("Leave StopWhenUnneeded=yes for certanly unneeded transaction for unit %s"
+                          " and drop it", u->id);
+                return true;
+        }
+}
+
 int transaction_add_job_and_dependencies(
                 Transaction *tr,
                 JobType type,
                 Unit *unit,
                 Job *by,
+                bool root,
                 bool matters,
                 bool override,
                 bool conflicts,
@@ -875,8 +915,12 @@ int transaction_add_job_and_dependencies(
                 return -EBADR;
         }
 
-        /* First add the job. */
-        ret = transaction_add_one_job(tr, type, unit, override, &is_new);
+        /* Check, is transaction a dead end */
+        if (transaction_unneeded_setup_and_check(unit, type, root, override))
+                return 0;
+
+        /* First add the root job. */
+        ret = transaction_add_one_job(tr, type, unit, root, override, &is_new);
         if (!ret)
                 return -ENOMEM;
 
@@ -899,7 +943,7 @@ int transaction_add_job_and_dependencies(
                  * add all dependencies of everybody following. */
                 if (unit_following_set(ret->unit, &following) > 0) {
                         SET_FOREACH(dep, following, i) {
-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, false, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_warning_unit(dep->id,
                                                          "Cannot add dependency job for unit %s, ignoring: %s",
@@ -916,7 +960,7 @@ int transaction_add_job_and_dependencies(
                 /* Finally, recursively add in all dependencies. */
                 if (type == JOB_START || type == JOB_RESTART) {
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, true, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -927,7 +971,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BINDS_TO], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, true, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -938,7 +982,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRES_OVERRIDABLE], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, !override, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, !override, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
                                                       "Cannot add dependency job for unit %s, ignoring: %s",
@@ -950,7 +994,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_WANTS], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_START, dep, ret, false, false, false, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
                                                       "Cannot add dependency job for unit %s, ignoring: %s",
@@ -962,7 +1006,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, false, true, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -973,7 +1017,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUISITE_OVERRIDABLE], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, ret, !override, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_VERIFY_ACTIVE, dep, false, ret, !override, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_full_unit(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_WARNING, dep->id,
                                                       "Cannot add dependency job for unit %s, ignoring: %s",
@@ -985,7 +1029,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTS], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, true, override, true, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, true, override, true, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -996,7 +1040,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONFLICTED_BY], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_STOP, dep, ret, false, false, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_warning_unit(dep->id,
                                                          "Cannot add dependency job for unit %s, ignoring: %s",
@@ -1012,7 +1056,7 @@ int transaction_add_job_and_dependencies(
                 if (type == JOB_STOP || type == JOB_RESTART) {
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_REQUIRED_BY], i) {
-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, true, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1023,7 +1067,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_BOUND_BY], i) {
-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, true, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1034,7 +1078,7 @@ int transaction_add_job_and_dependencies(
                         }
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_CONSISTS_OF], i) {
-                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, true, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, type, dep, ret, false, true, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         if (r != -EBADR)
                                                 goto fail;
@@ -1049,7 +1093,7 @@ int transaction_add_job_and_dependencies(
                 if (type == JOB_RELOAD) {
 
                         SET_FOREACH(dep, ret->unit->dependencies[UNIT_PROPAGATES_RELOAD_TO], i) {
-                                r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, override, false, false, ignore_order, e);
+                                r = transaction_add_job_and_dependencies(tr, JOB_RELOAD, dep, ret, false, false, override, false, false, ignore_order, e);
                                 if (r < 0) {
                                         log_warning_unit(dep->id,
                                                          "Cannot add dependency reload job for unit %s, ignoring: %s",
@@ -1096,7 +1140,7 @@ int transaction_add_isolate_jobs(Transaction *tr, Manager *m) {
                 if (hashmap_get(tr->jobs, u))
                         continue;
 
-                r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, true, false, false, false, false, NULL);
+                r = transaction_add_job_and_dependencies(tr, JOB_STOP, u, tr->anchor_job, false, true, false, false, false, false, NULL);
                 if (r < 0)
                         log_warning_unit(u->id,
                                          "Cannot add isolate job for unit %s, ignoring: %s",
diff --git a/src/core/transaction.h b/src/core/transaction.h
index 67ace4d..f0d0fd2 100644
--- a/src/core/transaction.h
+++ b/src/core/transaction.h
@@ -43,6 +43,7 @@ int transaction_add_job_and_dependencies(
                 JobType type,
                 Unit *unit,
                 Job *by,
+                bool root,
                 bool matters,
                 bool override,
                 bool conflicts,
diff --git a/src/core/unit.c b/src/core/unit.c
index 360da07..05b7751 100644
--- a/src/core/unit.c
+++ b/src/core/unit.c
@@ -436,6 +436,19 @@ const char* unit_sub_state_to_string(Unit *u) {
         return UNIT_VTABLE(u)->sub_state_to_string(u);
 }
 
+bool unit_stop_when_unneeded_state(Unit *u)
+{
+        assert(u);
+
+        if (u->load_state == UNIT_MERGED)
+                return unit_stop_when_unneeded_state(unit_follow_merge(u));
+
+        if (UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return u->stop_when_unneeded_runtime;
+        else
+                return u->stop_when_unneeded_unit;
+}
+
 static void complete_move(Set **s, Set **other) {
         assert(s);
         assert(other);
@@ -732,7 +745,7 @@ void unit_dump(Unit *u, FILE *f, const char *prefix) {
                         "%s\tOnFailureIsolate: %s\n"
                         "%s\tIgnoreOnIsolate: %s\n"
                         "%s\tIgnoreOnSnapshot: %s\n",
-                        prefix, yes_no(u->stop_when_unneeded),
+                        prefix, yes_no(unit_stop_when_unneeded_state(u)),
                         prefix, yes_no(u->refuse_manual_start),
                         prefix, yes_no(u->refuse_manual_stop),
                         prefix, yes_no(u->default_dependencies),
@@ -1112,6 +1125,9 @@ int unit_stop(Unit *u) {
 
         assert(u);
 
+        /* Drop stop_when_unneeded anyway */
+        u->stop_when_unneeded_runtime = u->stop_when_unneeded_unit;
+
         state = unit_active_state(u);
         if (UNIT_IS_INACTIVE_OR_FAILED(state))
                 return -EALREADY;
@@ -1179,36 +1195,47 @@ bool unit_can_reload(Unit *u) {
         return UNIT_VTABLE(u)->can_reload(u);
 }
 
-static void unit_check_unneeded(Unit *u) {
+bool unit_unneeded(Unit *u) {
         Iterator i;
         Unit *other;
 
         assert(u);
 
-        /* If this service shall be shut down when unneeded then do
-         * so. */
-
-        if (!u->stop_when_unneeded)
-                return;
+        if (u->load_state == UNIT_MERGED)
+                return unit_unneeded(unit_follow_merge(u));
 
-        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
-                return;
+        if (!unit_stop_when_unneeded_state(u))
+                return false;
 
         SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY], i)
                 if (unit_pending_active(other))
-                        return;
+                        return false;
 
         SET_FOREACH(other, u->dependencies[UNIT_REQUIRED_BY_OVERRIDABLE], i)
                 if (unit_pending_active(other))
-                        return;
+                        return false;
 
         SET_FOREACH(other, u->dependencies[UNIT_WANTED_BY], i)
                 if (unit_pending_active(other))
-                        return;
+                        return false;
 
         SET_FOREACH(other, u->dependencies[UNIT_BOUND_BY], i)
                 if (unit_pending_active(other))
-                        return;
+                        return false;
+
+        return true;
+}
+
+static void unit_check_unneeded(Unit *u) {
+
+        /* If this service shall be shut down when unneeded then do
+         * so. */
+
+        if (!UNIT_IS_ACTIVE_OR_ACTIVATING(unit_active_state(u)))
+                return;
+
+        if (! unit_unneeded(u))
+                return;
 
         log_info("Service %s is not needed anymore. Stopping.", u->id);
 
@@ -1435,8 +1462,10 @@ void unit_notify(Unit *u, UnitActiveState os, UnitActiveState ns, bool reload_su
                 }
 
                 /* stop unneeded units regardless if going down was expected or not */
-                if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns))
+                if (UNIT_IS_ACTIVE_OR_ACTIVATING(os) && UNIT_IS_INACTIVE_OR_DEACTIVATING(ns)) {
+                        log_debug("Check dependencies when n_reloading: %d", u->manager->n_reloading);
                         check_unneeded_dependencies(u);
+                }
 
                 if (ns != os && ns == UNIT_FAILED) {
                         log_struct_unit(LOG_NOTICE,
@@ -2336,6 +2365,7 @@ int unit_serialize(Unit *u, FILE *f, FDSet *fds, bool serialize_jobs) {
         dual_timestamp_serialize(f, "active-exit-timestamp", &u->active_exit_timestamp);
         dual_timestamp_serialize(f, "inactive-enter-timestamp", &u->inactive_enter_timestamp);
         dual_timestamp_serialize(f, "condition-timestamp", &u->condition_timestamp);
+        unit_serialize_item(u, f, "stop-when-unneeded-runtime", yes_no(u->stop_when_unneeded_runtime));
 
         if (dual_timestamp_is_set(&u->condition_timestamp))
                 unit_serialize_item(u, f, "condition-result", yes_no(u->condition_result));
@@ -2465,6 +2495,15 @@ int unit_deserialize(Unit *u, FILE *f, FDSet *fds) {
                                 u->condition_result = b;
 
                         continue;
+                } else if (streq(l, "stop-when-unneeded-runtime")) {
+                        int b;
+
+                        if ((b = parse_boolean(v)) < 0)
+                                log_debug("Failed to parse StopWhenUnneeded runtime state %s", v);
+                        else
+                                u->stop_when_unneeded_runtime = b;
+
+                        continue;
                 }
 
                 if ((r = UNIT_VTABLE(u)->deserialize_item(u, l, v, fds)) < 0)
diff --git a/src/core/unit.h b/src/core/unit.h
index c902103..9093721 100644
--- a/src/core/unit.h
+++ b/src/core/unit.h
@@ -199,7 +199,8 @@ struct Unit {
         UnitFileState unit_file_state;
 
         /* Garbage collect us we nobody wants or requires us anymore */
-        bool stop_when_unneeded;
+        bool stop_when_unneeded_unit;
+        bool stop_when_unneeded_runtime;
 
         /* Create default dependencies */
         bool default_dependencies;
@@ -479,10 +480,12 @@ void unit_dump(Unit *u, FILE *f, const char *prefix);
 bool unit_can_reload(Unit *u);
 bool unit_can_start(Unit *u);
 bool unit_can_isolate(Unit *u);
+bool unit_stop_when_unneeded_state(Unit *u);
 
 int unit_start(Unit *u);
 int unit_stop(Unit *u);
 int unit_reload(Unit *u);
+bool unit_unneeded(Unit *u);
 
 int unit_kill(Unit *u, KillWho w, int signo, DBusError *error);
 
-- 
1.8.1.2



More information about the systemd-devel mailing list