[PATCH v2 1/2] service: Implement ServicesAdded and ServicesRemoved signals

patrik.flykt at linux.intel.com patrik.flykt at linux.intel.com
Wed Feb 8 01:09:50 PST 2012


From: Patrik Flykt <patrik.flykt at linux.intel.com>

When services are added or removed, collect them into separate
lists in order to send as many as possible in one go and with
then removed ones sent first. Add a wait of 100ms to collect
more services in one batch. When removing a service check
whether it was also on the added list; if so, remove it from
that list.
---
v2: Do proper cleanup in __connman_service_cleanup()

 src/manager.c |    2 +
 src/service.c |  148 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+), 0 deletions(-)

diff --git a/src/manager.c b/src/manager.c
index cf2c624..7cf1eec 100644
--- a/src/manager.c
+++ b/src/manager.c
@@ -439,6 +439,8 @@ static GDBusSignalTable manager_signals[] = {
 	{ "PropertyChanged", "sv" },
 	{ "TechnologyAdded", "a{sv}" },
 	{ "TechnologyRemoved", "o" },
+	{ "ServicesAdded",   "a(oa{sv})" },
+	{ "ServicesRemoved", "a{o}" },
 	{ },
 };
 
diff --git a/src/service.c b/src/service.c
index b0acd5f..3468ba3 100644
--- a/src/service.c
+++ b/src/service.c
@@ -3318,6 +3318,143 @@ static DBusMessage *reset_counters(DBusConnection *conn,
 	return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
+static struct _services_notify {
+	int id;
+	GSList *added;
+	GSList *removed;
+} *services_notify;
+
+static void service_send_removed(void)
+{
+	DBusMessage *signal;
+	DBusMessageIter iter, array;
+	GSList *list, *next;
+
+	if (services_notify->removed == NULL)
+		return;
+
+	signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+			CONNMAN_MANAGER_INTERFACE, "ServicesRemoved");
+	if (signal == NULL)
+		return;
+
+	dbus_message_iter_init_append(signal, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_TYPE_OBJECT_PATH_AS_STRING, &array);
+
+	list = services_notify->removed;
+	services_notify->removed = NULL;
+
+	while (list != NULL) {
+		char *path = list->data;
+		DBG("removing %s", path);
+		next = list->next;
+		dbus_message_iter_append_basic(&array,
+				DBUS_TYPE_OBJECT_PATH, &list->data);
+		g_free(list->data);
+		g_slist_free_1(list);
+		list = next;
+	}
+	dbus_message_iter_close_container(&iter, &array);
+
+	dbus_connection_send(connection, signal, NULL);
+	dbus_message_unref(signal);
+}
+
+static void service_send_added(void)
+{
+	DBusMessage *signal;
+	DBusMessageIter iter, array;
+	GSList *list, *next;
+
+	if (services_notify->added == NULL)
+		return;
+
+	signal = dbus_message_new_signal(CONNMAN_MANAGER_PATH,
+			CONNMAN_MANAGER_INTERFACE, "ServicesAdded");
+	if (signal == NULL)
+		return;
+
+	dbus_message_iter_init_append(signal, &iter);
+	dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+			DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+			DBUS_TYPE_OBJECT_PATH_AS_STRING
+			DBUS_TYPE_ARRAY_AS_STRING
+				DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+					DBUS_TYPE_STRING_AS_STRING
+					DBUS_TYPE_VARIANT_AS_STRING
+				DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+			DBUS_STRUCT_END_CHAR_AS_STRING, &array);
+
+	list = services_notify->added;
+	services_notify->added = NULL;
+
+	while (list != NULL) {
+		struct connman_service *srv = list->data;
+		DBG("adding %s", srv->path);
+		next = list->next;
+		append_struct(list->data, &array);
+		g_slist_free_1(list);
+		list = next;
+	}
+
+	dbus_message_iter_close_container(&iter, &array);
+
+	dbus_connection_send(connection, signal, NULL);
+	dbus_message_unref(signal);
+}
+
+static gboolean service_send_signals(gpointer data)
+{
+	service_send_removed();
+	service_send_added();
+
+	services_notify->id = 0;
+	return FALSE;
+}
+
+static void service_schedule_signals(void)
+{
+	if (services_notify->id != 0)
+		g_source_remove(services_notify->id);
+
+	services_notify->id = g_timeout_add(100, service_send_signals, NULL);
+}
+
+static void service_schedule_added(struct connman_service *service)
+{
+	DBG("service %p", service);
+
+	services_notify->added = g_slist_prepend(services_notify->added,
+			service);
+
+	service_schedule_signals();
+}
+
+static void service_schedule_removed(struct connman_service *service)
+{
+	GSList *list;
+
+	DBG("service %p", service);
+
+	for (list = services_notify->added; list != NULL; list = list->next) {
+		struct connman_service *srv = list->data;
+		if (service == srv) {
+			DBG("delete service %p from added list", srv);
+			break;
+		}
+	}
+
+	if (list != NULL)
+		services_notify->added =
+			g_slist_delete_link(services_notify->added, list);
+
+	services_notify->removed = g_slist_prepend(services_notify->removed,
+			g_strdup(service->path));
+
+	service_schedule_signals();
+}
+
 static GDBusMethodTable service_methods[] = {
 	{ "GetProperties", "",   "a{sv}", get_properties     },
 	{ "SetProperty",   "sv", "",      set_property       },
@@ -3349,6 +3486,7 @@ static void service_free(gpointer user_data)
 	g_hash_table_remove(service_hash, service->identifier);
 
 	__connman_notifier_service_remove(service);
+	service_schedule_removed(service);
 
 	stats_stop(service);
 
@@ -5247,6 +5385,7 @@ struct connman_service * __connman_service_create_from_network(struct connman_ne
 	}
 
 	__connman_notifier_service_add(service, service->name);
+	service_schedule_added(service);
 
 	return service;
 }
@@ -5388,6 +5527,7 @@ __connman_service_create_from_provider(struct connman_provider *provider)
 	service_register(service);
 
 	__connman_notifier_service_add(service, service->name);
+	service_schedule_added(service);
 
 	return service;
 }
@@ -5403,6 +5543,8 @@ int __connman_service_init(void)
 
 	service_list = g_sequence_new(service_free);
 
+	services_notify = g_new0(struct _services_notify, 1);
+
 	return 0;
 }
 
@@ -5422,5 +5564,11 @@ void __connman_service_cleanup(void)
 	g_slist_free(counter_list);
 	counter_list = NULL;
 
+	if (services_notify->id != 0) {
+		g_source_remove(services_notify->id);
+		service_send_signals(NULL);
+	}
+	g_free(services_notify);
+
 	dbus_connection_unref(connection);
 }
-- 
1.7.8.3




More information about the connman mailing list