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
#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"
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;
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;
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);
#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"
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;
#include "alloc-util.h"
#include "dbus-mount.h"
+#include "dbus-unit.h"
#include "device.h"
#include "escape.h"
#include "exit-status.h"
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;
#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"
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;
#include "alloc-util.h"
#include "dbus-scope.h"
+#include "dbus-unit.h"
#include "load-dropin.h"
#include "log.h"
#include "scope.h"
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;
#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"
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;
#include "alloc-util.h"
#include "dbus-slice.h"
+#include "dbus-unit.h"
#include "log.h"
#include "serialize.h"
#include "slice.h"
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;
#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"
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;
#include "alloc-util.h"
#include "dbus-swap.h"
+#include "dbus-unit.h"
#include "device-private.h"
#include "device-util.h"
#include "device.h"
assert(s);
+ if (s->state != state)
+ bus_unit_send_pending_change_signal(UNIT(s), false);
+
old_state = s->state;
s->state = state;
/* SPDX-License-Identifier: LGPL-2.1+ */
#include "dbus-target.h"
+#include "dbus-unit.h"
#include "log.h"
#include "serialize.h"
#include "special.h"
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;
#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"
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;