From 6fcbec6f9b15e534badd069610e35f4c5303c502 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 27 Nov 2018 20:15:45 +0100 Subject: [PATCH] core: whenever we change state of a unit, force out PropertiesChanged bus signal This allows clients to follow our internal state changes safely. Previously, quick state changes (for example, when we restart a unit due to Restart= after it quickly transitioned through DEAD/FAILED states) would be coalesced into one bus signal event, with this change there's the guarantee that all state changes after the unit was announced ones are reflected on th bus. Note we only do this kind of guaranteed flushing only for unit state changes, not for other unit property changes, where clients still have to expect coalescing. This is because the unit state is a very important, high-level concept. Fixes: #10185 --- src/core/automount.c | 4 ++++ src/core/dbus-unit.c | 21 +++++++++++++++++++++ src/core/dbus-unit.h | 1 + src/core/device.c | 4 ++++ src/core/mount.c | 4 ++++ src/core/path.c | 4 ++++ src/core/scope.c | 4 ++++ src/core/service.c | 4 ++++ src/core/slice.c | 4 ++++ src/core/socket.c | 4 ++++ src/core/swap.c | 4 ++++ src/core/target.c | 4 ++++ src/core/timer.c | 4 ++++ 13 files changed, 66 insertions(+) diff --git a/src/core/automount.c b/src/core/automount.c index 3d8348e0b7..de8010bf2e 100644 --- a/src/core/automount.c +++ b/src/core/automount.c @@ -16,6 +16,7 @@ #include "bus-error.h" #include "bus-util.h" #include "dbus-automount.h" +#include "dbus-unit.h" #include "fd-util.h" #include "format-util.h" #include "io-util.h" @@ -237,6 +238,9 @@ static void automount_set_state(Automount *a, AutomountState state) { AutomountState old_state; assert(a); + if (a->state != state) + bus_unit_send_pending_change_signal(UNIT(a), false); + old_state = a->state; a->state = state; diff --git a/src/core/dbus-unit.c b/src/core/dbus-unit.c index 6d9b559d2c..4cf7364c50 100644 --- a/src/core/dbus-unit.c +++ b/src/core/dbus-unit.c @@ -1202,6 +1202,27 @@ void bus_unit_send_change_signal(Unit *u) { u->sent_dbus_new_signal = true; } +void bus_unit_send_pending_change_signal(Unit *u, bool including_new) { + + /* Sends out any pending change signals, but only if they really are pending. This call is used when we are + * about to change state in order to force out a PropertiesChanged signal beforehand if there was one pending + * so that clients can follow the full state transition */ + + if (!u->in_dbus_queue) /* If not enqueued, don't bother */ + return; + + if (!u->sent_dbus_new_signal && !including_new) /* If the unit was never announced, don't bother, it's fine if + * the unit appears in the new state right-away (except if the + * caller explicitly asked us to send it anyway) */ + return; + + if (MANAGER_IS_RELOADING(u->manager)) /* Don't generate unnecessary PropertiesChanged signals for the same unit + * when we are reloading. */ + return; + + bus_unit_send_change_signal(u); +} + static int send_removed_signal(sd_bus *bus, void *userdata) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; _cleanup_free_ char *p = NULL; diff --git a/src/core/dbus-unit.h b/src/core/dbus-unit.h index 68eb621836..345345e3eb 100644 --- a/src/core/dbus-unit.h +++ b/src/core/dbus-unit.h @@ -11,6 +11,7 @@ extern const sd_bus_vtable bus_unit_vtable[]; extern const sd_bus_vtable bus_unit_cgroup_vtable[]; void bus_unit_send_change_signal(Unit *u); +void bus_unit_send_pending_change_signal(Unit *u, bool including_new); void bus_unit_send_removed_signal(Unit *u); int bus_unit_method_start_generic(sd_bus_message *message, Unit *u, JobType job_type, bool reload_if_possible, sd_bus_error *error); diff --git a/src/core/device.c b/src/core/device.c index 8b6126c4cf..5acd9b7a70 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -6,6 +6,7 @@ #include "alloc-util.h" #include "bus-error.h" #include "dbus-device.h" +#include "dbus-unit.h" #include "device-private.h" #include "device-util.h" #include "device.h" @@ -115,6 +116,9 @@ static void device_set_state(Device *d, DeviceState state) { DeviceState old_state; assert(d); + if (d->state != state) + bus_unit_send_pending_change_signal(UNIT(d), false); + old_state = d->state; d->state = state; diff --git a/src/core/mount.c b/src/core/mount.c index 99b2aa0904..afdbaa1d9d 100644 --- a/src/core/mount.c +++ b/src/core/mount.c @@ -11,6 +11,7 @@ #include "alloc-util.h" #include "dbus-mount.h" +#include "dbus-unit.h" #include "device.h" #include "escape.h" #include "exit-status.h" @@ -640,6 +641,9 @@ static void mount_set_state(Mount *m, MountState state) { MountState old_state; assert(m); + if (m->state != state) + bus_unit_send_pending_change_signal(UNIT(m), false); + old_state = m->state; m->state = state; diff --git a/src/core/path.c b/src/core/path.c index 01019b0cf7..831e49df29 100644 --- a/src/core/path.c +++ b/src/core/path.c @@ -8,6 +8,7 @@ #include "bus-error.h" #include "bus-util.h" #include "dbus-path.h" +#include "dbus-unit.h" #include "fd-util.h" #include "fs-util.h" #include "glob-util.h" @@ -410,6 +411,9 @@ static void path_set_state(Path *p, PathState state) { PathState old_state; assert(p); + if (p->state != state) + bus_unit_send_pending_change_signal(UNIT(p), false); + old_state = p->state; p->state = state; diff --git a/src/core/scope.c b/src/core/scope.c index 151b8989a6..e478661f94 100644 --- a/src/core/scope.c +++ b/src/core/scope.c @@ -5,6 +5,7 @@ #include "alloc-util.h" #include "dbus-scope.h" +#include "dbus-unit.h" #include "load-dropin.h" #include "log.h" #include "scope.h" @@ -82,6 +83,9 @@ static void scope_set_state(Scope *s, ScopeState state) { ScopeState old_state; assert(s); + if (s->state != state) + bus_unit_send_pending_change_signal(UNIT(s), false); + old_state = s->state; s->state = state; diff --git a/src/core/service.c b/src/core/service.c index 964a7fd057..76f1e16069 100644 --- a/src/core/service.c +++ b/src/core/service.c @@ -12,6 +12,7 @@ #include "bus-kernel.h" #include "bus-util.h" #include "dbus-service.h" +#include "dbus-unit.h" #include "def.h" #include "env-util.h" #include "escape.h" @@ -1035,6 +1036,9 @@ static void service_set_state(Service *s, ServiceState state) { assert(s); + if (s->state != state) + bus_unit_send_pending_change_signal(UNIT(s), false); + table = s->type == SERVICE_IDLE ? state_translation_table_idle : state_translation_table; old_state = s->state; diff --git a/src/core/slice.c b/src/core/slice.c index dc087680e1..15b18bcad3 100644 --- a/src/core/slice.c +++ b/src/core/slice.c @@ -4,6 +4,7 @@ #include "alloc-util.h" #include "dbus-slice.h" +#include "dbus-unit.h" #include "log.h" #include "serialize.h" #include "slice.h" @@ -29,6 +30,9 @@ static void slice_set_state(Slice *t, SliceState state) { SliceState old_state; assert(t); + if (t->state != state) + bus_unit_send_pending_change_signal(UNIT(t), false); + old_state = t->state; t->state = state; diff --git a/src/core/socket.c b/src/core/socket.c index f725c9eb00..d3dc0a3216 100644 --- a/src/core/socket.c +++ b/src/core/socket.c @@ -17,6 +17,7 @@ #include "bus-util.h" #include "copy.h" #include "dbus-socket.h" +#include "dbus-unit.h" #include "def.h" #include "exit-status.h" #include "fd-util.h" @@ -1748,6 +1749,9 @@ static void socket_set_state(Socket *s, SocketState state) { SocketState old_state; assert(s); + if (s->state != state) + bus_unit_send_pending_change_signal(UNIT(s), false); + old_state = s->state; s->state = state; diff --git a/src/core/swap.c b/src/core/swap.c index db806fe0bb..90207a48fa 100644 --- a/src/core/swap.c +++ b/src/core/swap.c @@ -9,6 +9,7 @@ #include "alloc-util.h" #include "dbus-swap.h" +#include "dbus-unit.h" #include "device-private.h" #include "device-util.h" #include "device.h" @@ -480,6 +481,9 @@ static void swap_set_state(Swap *s, SwapState state) { assert(s); + if (s->state != state) + bus_unit_send_pending_change_signal(UNIT(s), false); + old_state = s->state; s->state = state; diff --git a/src/core/target.c b/src/core/target.c index b8b8e32805..421a304c73 100644 --- a/src/core/target.c +++ b/src/core/target.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1+ */ #include "dbus-target.h" +#include "dbus-unit.h" #include "log.h" #include "serialize.h" #include "special.h" @@ -18,6 +19,9 @@ static void target_set_state(Target *t, TargetState state) { TargetState old_state; assert(t); + if (t->state != state) + bus_unit_send_pending_change_signal(UNIT(t), false); + old_state = t->state; t->state = state; diff --git a/src/core/timer.c b/src/core/timer.c index 1527aab158..d9ba2f76b3 100644 --- a/src/core/timer.c +++ b/src/core/timer.c @@ -6,6 +6,7 @@ #include "bus-error.h" #include "bus-util.h" #include "dbus-timer.h" +#include "dbus-unit.h" #include "fs-util.h" #include "parse-util.h" #include "random-util.h" @@ -247,6 +248,9 @@ static void timer_set_state(Timer *t, TimerState state) { TimerState old_state; assert(t); + if (t->state != state) + bus_unit_send_pending_change_signal(UNIT(t), false); + old_state = t->state; t->state = state;