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 3d8348e0b7f..de8010bf2e5 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 6d9b559d2c7..4cf7364c50e 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 68eb621836b..345345e3eba 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 8b6126c4cfe..5acd9b7a703 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 99b2aa0904c..afdbaa1d9d0 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 01019b0cf77..831e49df29f 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 151b8989a64..e478661f948 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 964a7fd0572..76f1e160697 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 dc087680e19..15b18bcad35 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 f725c9eb009..d3dc0a32168 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 db806fe0bb3..90207a48fa6 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 b8b8e32805e..421a304c73d 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 1527aab1582..d9ba2f76b3d 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; -- 2.39.5