[systemd-devel] [PATCH] Set StopWhenUnneeded=no, if unit started manually
Oleksii Shevchuk
alxchk at gmail.com
Sat Feb 2 10:40:22 PST 2013
Current one:
- If StopWhenUnneeded=yes and RequiredBy=, WantedBy=, BoundBy= empty
Then stop unit.
The side effect is:
- If user starts unit, that not wanted by any started target, then unit
will be immediately stopped.
The problems are:
- The user can not be sure that the launch of a unit means that it will
be actually started
- We already have RefuseManualStart=
Patched one:
- When unit starts, If RequiredBy=, WantedBy=, BoundBy= empty
Then set StopWhenUnneeded=yes
The side effect is:
- User can be sure - the launch of the unit means that it will be
started
- If unit started when WantedBy=/... unit running, the unit will be stopped
with the parent one
- If unit started when WantedBy=/... are empty, then unit will not be
stopped even after such units started, unitil it will be actually
stopped.
Path introduces next changes:
- unit:
+ Replace stop_when_unneeded field in Unit structure to
* stop_when_unneeded_unit -- for default value from unit file
* stop_when_unneeded_runtime -- for runtime value setted up in
unit_start
+ Decision logic moved to unit_unneeded function
+ Add logic to unit_start
* When unit starts:
set stop_when_unneeded_runtime=stop_when_unneeded_unit
If unit_unneeded Then set stop_when_unneeded_runtime=no
+ Add unit_stop_when_unneeded_state function, to return actual
StopWhenUnneeded= state with next logic:
* For starting and started units return runtime state
* For other states return default value from StopWhenUnneeded= unit
field
+ For unit_dump use default value from unit file
+ For serialization (daemon-reexec) use runtime value from unit state
* "stop-when-unneeded-runtime" serialization field added
- dbus interface:
+ Add bus_unit_append_stop_when_unneeded function, to return actual
StopWhenUnneeded= state via unit_stop_when_unneeded_state and use
it instead of direct u->stop_when_unneeded serialization
---
src/core/dbus-unit.c | 18 +++++++++-
src/core/load-fragment-gperf.gperf.m4 | 2 +-
src/core/unit.c | 67 +++++++++++++++++++++++++++--------
src/core/unit.h | 5 ++-
4 files changed, 75 insertions(+), 17 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/load-fragment-gperf.gperf.m4 b/src/core/load-fragment-gperf.gperf.m4
index 1783ad0..6fad6c9 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/unit.c b/src/core/unit.c
index f7d00b6..db5dac9 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(u->stop_when_unneeded_unit),
prefix, yes_no(u->refuse_manual_start),
prefix, yes_no(u->refuse_manual_stop),
prefix, yes_no(u->default_dependencies),
@@ -1064,6 +1077,14 @@ int unit_start(Unit *u) {
return -EALREADY;
}
+ u->stop_when_unneeded_runtime = u->stop_when_unneeded_unit;
+
+ if (unit_unneeded(u)) {
+ log_debug("Started unneded unit %s with StopWhenUnneeded=yes."
+ "Disabling unneeded property.", u->id);
+ u->stop_when_unneeded_runtime = false;
+ }
+
/* Forward to the main object, if we aren't it. */
if ((following = unit_following(u))) {
log_debug("Redirecting start request from %s to %s.", u->id, following->id);
@@ -1179,36 +1200,44 @@ 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 (!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);
@@ -2335,6 +2364,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));
@@ -2464,6 +2494,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
More information about the systemd-devel
mailing list