All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] dbus: Flush pending object manager signals in send_message
@ 2017-03-27 23:23 Andrew Zaborowski
  2017-03-27  9:23 ` Denis Kenzior
  0 siblings, 1 reply; 12+ messages in thread
From: Andrew Zaborowski @ 2017-03-27 23:23 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 7581 bytes --]

Make sure the PropertiesChanged and InterfacesAdded/Removed signals
related to one object path are sent to the dbus socket in the order
that they are generated in.
---
 ell/dbus-private.h |   2 +
 ell/dbus-service.c | 160 ++++++++++++++++++++++++++++++++++++-----------------
 ell/dbus.c         |   5 ++
 3 files changed, 117 insertions(+), 50 deletions(-)

diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index 441e668..9ffedb2 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -229,6 +229,8 @@ bool _dbus_object_tree_property_changed(struct l_dbus *dbus,
 					const char *interface_name,
 					const char *property_name);
 
+void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path);
+
 typedef void (*_dbus_name_owner_change_func_t)(const char *name,
 						uint64_t old_owner,
 						uint64_t new_owner,
diff --git a/ell/dbus-service.c b/ell/dbus-service.c
index 1df8f1b..5ee7d27 100644
--- a/ell/dbus-service.c
+++ b/ell/dbus-service.c
@@ -132,6 +132,7 @@ struct _dbus_object_tree {
 	struct l_queue *object_managers;
 	struct l_queue *property_changes;
 	struct l_idle *emit_signals_work;
+	bool flushing;
 };
 
 void _dbus_method_introspection(struct _dbus_method *info,
@@ -1024,71 +1025,130 @@ done:
 	return signal;
 }
 
-static void emit_signals(struct l_idle *idle, void *user_data)
-{
-	struct l_dbus *dbus = user_data;
-	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
-	struct interface_add_record *interfaces_added_rec;
-	struct interface_remove_record *interfaces_removed_rec;
-	struct property_change_record *property_changes_rec;
-	const struct l_queue_entry *entry;
+struct emit_signals_data {
+	struct l_dbus *dbus;
 	struct object_manager *manager;
+	struct object_node *node;
+};
+
+static bool emit_interfaces_removed(void *data, void *user_data)
+{
+	struct interface_remove_record *rec = data;
+	struct emit_signals_data *es = user_data;
 	struct l_dbus_message *signal;
 
-	l_idle_remove(tree->emit_signals_work);
-	tree->emit_signals_work = NULL;
+	if (es->node && rec->object != es->node)
+		return false;
 
-	for (entry = l_queue_get_entries(tree->object_managers); entry;
-			entry = entry->next) {
-		manager = entry->data;
+	signal = build_interfaces_removed_signal(es->manager, rec);
+	interface_removed_record_free(rec);
 
-		while ((interfaces_removed_rec =
-				l_queue_pop_head(manager->announce_removed))) {
-			signal = build_interfaces_removed_signal(manager,
-							interfaces_removed_rec);
-			interface_removed_record_free(interfaces_removed_rec);
+	if (signal)
+		l_dbus_send(es->manager->dbus, signal);
 
-			if (signal)
-				l_dbus_send(manager->dbus, signal);
-		}
+	return true;
+}
 
-		while ((interfaces_added_rec =
-				l_queue_pop_head(manager->announce_added))) {
-			signal = build_interfaces_added_signal(manager,
-							interfaces_added_rec);
-			interface_add_record_free(interfaces_added_rec);
+static bool emit_interfaces_added(void *data, void *user_data)
+{
+	struct interface_add_record *rec = data;
+	struct emit_signals_data *es = user_data;
+	struct l_dbus_message *signal;
+
+	if (es->node && rec->object != es->node)
+		return false;
 
+	signal = build_interfaces_added_signal(es->manager, rec);
+	interface_add_record_free(rec);
+
+	if (signal)
+		l_dbus_send(es->manager->dbus, signal);
+
+	return true;
+}
+
+static bool emit_properties_changed(void *data, void *user_data)
+{
+	struct property_change_record *rec = data;
+	struct emit_signals_data *es = user_data;
+	struct l_dbus_message *signal;
+	const struct l_queue_entry *entry;
+
+	if (es->node && rec->object != es->node)
+		return false;
+
+	if (rec->instance->interface->handle_old_style_properties)
+		for (entry = l_queue_get_entries(rec->properties);
+				entry; entry = entry->next) {
+			signal = build_old_property_changed_signal(es->dbus,
+							rec, entry->data);
 			if (signal)
-				l_dbus_send(manager->dbus, signal);
+				l_dbus_send(es->dbus, signal);
 		}
+
+	if (l_queue_find(rec->object->instances, match_interface_instance,
+				L_DBUS_INTERFACE_PROPERTIES)) {
+		signal = build_properties_changed_signal(es->dbus, rec);
+		if (signal)
+			l_dbus_send(es->dbus, signal);
 	}
 
-	while ((property_changes_rec =
-			l_queue_pop_head(tree->property_changes))) {
-		if (property_changes_rec->instance->interface->
-				handle_old_style_properties)
-			for (entry = l_queue_get_entries(property_changes_rec->
-								properties);
-					entry; entry = entry->next) {
-				signal = build_old_property_changed_signal(dbus,
-							property_changes_rec,
-							entry->data);
-				if (signal)
-					l_dbus_send(dbus, signal);
-			}
+	property_change_record_free(rec);
 
+	return true;
+}
 
-		if (l_queue_find(property_changes_rec->object->instances,
-					match_interface_instance,
-					L_DBUS_INTERFACE_PROPERTIES)) {
-			signal = build_properties_changed_signal(dbus,
-							property_changes_rec);
-			if (signal)
-				l_dbus_send(dbus, signal);
-		}
+void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path)
+{
+	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
+	const struct l_queue_entry *entry;
+	struct emit_signals_data data;
+	bool all_done = true;
+
+	if (!tree->emit_signals_work || tree->flushing)
+		return;
 
-		property_change_record_free(property_changes_rec);
+	tree->flushing = true;
+
+	data.dbus = dbus;
+	data.node = path ? _dbus_object_tree_lookup(tree, path) : NULL;
+
+	for (entry = l_queue_get_entries(tree->object_managers); entry;
+			entry = entry->next) {
+		data.manager = entry->data;
+
+		l_queue_foreach_remove(data.manager->announce_removed,
+					emit_interfaces_removed, &data);
+
+		if (!l_queue_isempty(data.manager->announce_removed))
+			all_done = false;
+
+		l_queue_foreach_remove(data.manager->announce_added,
+					emit_interfaces_added, &data);
+
+		if (!l_queue_isempty(data.manager->announce_added))
+			all_done = false;
+	}
+
+	l_queue_foreach_remove(tree->property_changes,
+				emit_properties_changed, &data);
+
+	if (!l_queue_isempty(tree->property_changes))
+		all_done = false;
+
+	if (all_done) {
+		l_idle_remove(tree->emit_signals_work);
+		tree->emit_signals_work = NULL;
 	}
+
+	tree->flushing = false;
+}
+
+static void emit_signals(struct l_idle *idle, void *user_data)
+{
+	struct l_dbus *dbus = user_data;
+
+	_dbus_object_tree_signals_flush(dbus, NULL);
 }
 
 static void schedule_emit_signals(struct l_dbus *dbus)
@@ -1356,7 +1416,7 @@ static bool match_interfaces_added_object(const void *a, const void *b)
 
 static bool match_interfaces_removed_object(const void *a, const void *b)
 {
-	const struct interface_add_record *rec = a;
+	const struct interface_remove_record *rec = a;
 
 	return rec->object == b;
 }
diff --git a/ell/dbus.c b/ell/dbus.c
index db69c0d..59795a7 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -306,6 +306,7 @@ static uint32_t send_message(struct l_dbus *dbus, bool priority,
 {
 	struct message_callback *callback;
 	enum dbus_message_type type;
+	const char *path;
 
 	type = _dbus_message_get_type(message);
 
@@ -338,6 +339,10 @@ static uint32_t send_message(struct l_dbus *dbus, bool priority,
 		return callback->serial;
 	}
 
+	path = l_dbus_message_get_path(message);
+	if (path)
+		_dbus_object_tree_signals_flush(dbus, path);
+
 	l_queue_push_tail(dbus->message_queue, callback);
 
 	if (dbus->is_ready)
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [PATCH] dbus: Flush pending object manager signals in send_message
@ 2017-03-23 15:12 Andrew Zaborowski
  2017-03-27  5:07 ` Denis Kenzior
  0 siblings, 1 reply; 12+ messages in thread
From: Andrew Zaborowski @ 2017-03-23 15:12 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 5897 bytes --]

Make sure the PropertiesChanged and InterfacesAdded/Removed signals
related to one object path are sent to the dbus socket in the order
that they are generated in.
---
 ell/dbus-private.h |  2 ++
 ell/dbus-service.c | 85 +++++++++++++++++++++++++++++++++++++++---------------
 ell/dbus.c         |  5 ++++
 3 files changed, 68 insertions(+), 24 deletions(-)

diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index 441e668..9ffedb2 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -229,6 +229,8 @@ bool _dbus_object_tree_property_changed(struct l_dbus *dbus,
 					const char *interface_name,
 					const char *property_name);
 
+void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path);
+
 typedef void (*_dbus_name_owner_change_func_t)(const char *name,
 						uint64_t old_owner,
 						uint64_t new_owner,
diff --git a/ell/dbus-service.c b/ell/dbus-service.c
index 1df8f1b..7212340 100644
--- a/ell/dbus-service.c
+++ b/ell/dbus-service.c
@@ -1024,9 +1024,29 @@ done:
 	return signal;
 }
 
-static void emit_signals(struct l_idle *idle, void *user_data)
+static bool match_interfaces_added_object(const void *a, const void *b)
+{
+	const struct interface_add_record *rec = a;
+
+	return rec->object == b || !b;
+}
+
+static bool match_interfaces_removed_object(const void *a, const void *b)
+{
+	const struct interface_remove_record *rec = a;
+
+	return rec->object == b || !b;
+}
+
+static bool match_properties_changed_object(const void *a, const void *b)
+{
+	const struct property_change_record *rec = a;
+
+	return rec->object == b || !b;
+}
+
+void _dbus_object_tree_signals_flush(struct l_dbus *dbus, const char *path)
 {
-	struct l_dbus *dbus = user_data;
 	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
 	struct interface_add_record *interfaces_added_rec;
 	struct interface_remove_record *interfaces_removed_rec;
@@ -1034,16 +1054,23 @@ static void emit_signals(struct l_idle *idle, void *user_data)
 	const struct l_queue_entry *entry;
 	struct object_manager *manager;
 	struct l_dbus_message *signal;
+	struct object_node *node = NULL;
+	bool all_done = true;
 
-	l_idle_remove(tree->emit_signals_work);
-	tree->emit_signals_work = NULL;
+	if (!tree->emit_signals_work)
+		return;
+
+	if (path)
+		node = _dbus_object_tree_lookup(tree, path);
 
 	for (entry = l_queue_get_entries(tree->object_managers); entry;
 			entry = entry->next) {
 		manager = entry->data;
 
-		while ((interfaces_removed_rec =
-				l_queue_pop_head(manager->announce_removed))) {
+		while ((interfaces_removed_rec = l_queue_remove_if(
+						manager->announce_removed,
+						match_interfaces_removed_object,
+						node))) {
 			signal = build_interfaces_removed_signal(manager,
 							interfaces_removed_rec);
 			interface_removed_record_free(interfaces_removed_rec);
@@ -1052,8 +1079,13 @@ static void emit_signals(struct l_idle *idle, void *user_data)
 				l_dbus_send(manager->dbus, signal);
 		}
 
-		while ((interfaces_added_rec =
-				l_queue_pop_head(manager->announce_added))) {
+		if (!l_queue_isempty(manager->announce_removed))
+			all_done = false;
+
+		while ((interfaces_added_rec = l_queue_remove_if(
+						manager->announce_added,
+						match_interfaces_added_object,
+						node))) {
 			signal = build_interfaces_added_signal(manager,
 							interfaces_added_rec);
 			interface_add_record_free(interfaces_added_rec);
@@ -1061,10 +1093,14 @@ static void emit_signals(struct l_idle *idle, void *user_data)
 			if (signal)
 				l_dbus_send(manager->dbus, signal);
 		}
+
+		if (!l_queue_isempty(manager->announce_added))
+			all_done = false;
 	}
 
-	while ((property_changes_rec =
-			l_queue_pop_head(tree->property_changes))) {
+	while ((property_changes_rec = l_queue_remove_if(tree->property_changes,
+						match_properties_changed_object,
+						node))) {
 		if (property_changes_rec->instance->interface->
 				handle_old_style_properties)
 			for (entry = l_queue_get_entries(property_changes_rec->
@@ -1089,6 +1125,21 @@ static void emit_signals(struct l_idle *idle, void *user_data)
 
 		property_change_record_free(property_changes_rec);
 	}
+
+	if (!l_queue_isempty(tree->property_changes))
+		all_done = false;
+
+	if (all_done) {
+		l_idle_remove(tree->emit_signals_work);
+		tree->emit_signals_work = NULL;
+	}
+}
+
+static void emit_signals(struct l_idle *idle, void *user_data)
+{
+	struct l_dbus *dbus = user_data;
+
+	_dbus_object_tree_signals_flush(dbus, NULL);
 }
 
 static void schedule_emit_signals(struct l_dbus *dbus)
@@ -1347,20 +1398,6 @@ bool _dbus_object_tree_unregister_interface(struct _dbus_object_tree *tree,
 	return true;
 }
 
-static bool match_interfaces_added_object(const void *a, const void *b)
-{
-	const struct interface_add_record *rec = a;
-
-	return rec->object == b;
-}
-
-static bool match_interfaces_removed_object(const void *a, const void *b)
-{
-	const struct interface_add_record *rec = a;
-
-	return rec->object == b;
-}
-
 bool _dbus_object_tree_add_interface(struct _dbus_object_tree *tree,
 					const char *path, const char *interface,
 					void *user_data)
diff --git a/ell/dbus.c b/ell/dbus.c
index db69c0d..59795a7 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -306,6 +306,7 @@ static uint32_t send_message(struct l_dbus *dbus, bool priority,
 {
 	struct message_callback *callback;
 	enum dbus_message_type type;
+	const char *path;
 
 	type = _dbus_message_get_type(message);
 
@@ -338,6 +339,10 @@ static uint32_t send_message(struct l_dbus *dbus, bool priority,
 		return callback->serial;
 	}
 
+	path = l_dbus_message_get_path(message);
+	if (path)
+		_dbus_object_tree_signals_flush(dbus, path);
+
 	l_queue_push_tail(dbus->message_queue, callback);
 
 	if (dbus->is_ready)
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 12+ messages in thread
* [PATCH] dbus: Flush pending object manager signals in send_message
@ 2017-03-18  1:30 Andrew Zaborowski
  2017-03-18  4:05 ` Denis Kenzior
  0 siblings, 1 reply; 12+ messages in thread
From: Andrew Zaborowski @ 2017-03-18  1:30 UTC (permalink / raw)
  To: ell

[-- Attachment #1: Type: text/plain, Size: 2277 bytes --]

Try to warrant the original ordering of PropertiesChanged and
InterfacesAdded/Removed signals in relation to other messages for
clients that rely on this ordering.  One case where this may matter
is when a method call causes a property value change followed by the
method return message in the same main loop iteration as the property
change.  In this case the property change would always be seen by
dbus after the method return because of the signals being send from
an idle callback.  Set a barrier for the object manager signals
before queuing other messages like method returns.
---
 ell/dbus-private.h | 2 ++
 ell/dbus-service.c | 8 ++++++++
 ell/dbus.c         | 2 ++
 3 files changed, 12 insertions(+)

diff --git a/ell/dbus-private.h b/ell/dbus-private.h
index a4118c6..c22b95a 100644
--- a/ell/dbus-private.h
+++ b/ell/dbus-private.h
@@ -234,6 +234,8 @@ bool _dbus_object_tree_property_changed(struct l_dbus *dbus,
 					const char *interface_name,
 					const char *property_name);
 
+void _dbus_object_tree_signals_flush(struct l_dbus *dbus);
+
 void _dbus_kernel_bloom_add(uint64_t filter[], size_t size, uint8_t num_hash,
 				const char *prefix, const char *str);
 void _dbus_kernel_bloom_add_parents(uint64_t filter[], size_t size,
diff --git a/ell/dbus-service.c b/ell/dbus-service.c
index 1df8f1b..f54d2dd 100644
--- a/ell/dbus-service.c
+++ b/ell/dbus-service.c
@@ -1101,6 +1101,14 @@ static void schedule_emit_signals(struct l_dbus *dbus)
 	tree->emit_signals_work = l_idle_create(emit_signals, dbus, NULL);
 }
 
+void _dbus_object_tree_signals_flush(struct l_dbus *dbus)
+{
+	struct _dbus_object_tree *tree = _dbus_get_tree(dbus);
+
+	if (tree->emit_signals_work)
+		emit_signals(tree->emit_signals_work, dbus);
+}
+
 static bool match_property_changes_instance(const void *a, const void *b)
 {
 	const struct property_change_record *rec = a;
diff --git a/ell/dbus.c b/ell/dbus.c
index ddc51aa..274e4ae 100644
--- a/ell/dbus.c
+++ b/ell/dbus.c
@@ -346,6 +346,8 @@ static uint32_t send_message(struct l_dbus *dbus, bool priority,
 		return callback->serial;
 	}
 
+	_dbus_object_tree_signals_flush(dbus);
+
 	l_queue_push_tail(dbus->message_queue, callback);
 
 	if (dbus->is_ready)
-- 
2.9.3


^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2017-03-27 23:23 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-03-27 23:23 [PATCH] dbus: Flush pending object manager signals in send_message Andrew Zaborowski
2017-03-27  9:23 ` Denis Kenzior
  -- strict thread matches above, loose matches on Subject: below --
2017-03-23 15:12 Andrew Zaborowski
2017-03-27  5:07 ` Denis Kenzior
2017-03-27 21:34   ` Andrew Zaborowski
2017-03-18  1:30 Andrew Zaborowski
2017-03-18  4:05 ` Denis Kenzior
2017-03-18 17:36   ` Andrew Zaborowski
2017-03-20 14:53     ` Denis Kenzior
2017-03-20 16:53       ` Andrew Zaborowski
2017-03-20 18:17         ` Denis Kenzior
2017-03-23 15:29           ` Andrew Zaborowski

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.