[systemd-devel] [PATCH] Set StopWhenUnneeded=no, if unit started manually
Zbigniew Jędrzejewski-Szmek
zbyszek at in.waw.pl
Mon Feb 4 17:30:12 PST 2013
On Sat, Feb 02, 2013 at 08:40:22PM +0200, Oleksii Shevchuk wrote:
>
> 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.
Hi Oleksii,
thank you for providing this explanation, it provides the rationale
for the patch. Still, I don't know if this change is warranted.
Even without this patch, the unit would be started, and *then* stopped
immediately, so it's not true that the user doesn not know if will be
started. I mean that if someone doesn't want to have the semantics
provided by StopWhenUnneeded=true, maybe they should not set it.
Let's see what others think.
Zbyszek
> 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
> _______________________________________________
> systemd-devel mailing list
> systemd-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/systemd-devel
>
More information about the systemd-devel
mailing list