[PATCH 2/4] hald core support for singleton addons

Rob Taylor rob.taylor at codethink.co.uk
Fri Jun 1 04:37:52 PDT 2007


Introduces a new property info.addons.singletons for specifything addon singletons for a given device.

A mapping of singleton commandlines to connection and devices serviced is
maintained in hald_dbus.c. hald now expects a call of SingletonAddonIsReady on
the interface org.freedesktop.Hal.Manager on /org/freedesktop/Hal/Manager when
an addon is ready to service requests. When a singleton is ready, DeviceReady
on the interface org.freedesktop.Hal.SingletonAddon on the object
/org/freedesktop/Hal/SingletonAddon in the addon is called for all queued
devices.
Once a singleton is ready, device adds and removes result in a direct call of
DeviceReady.
---
 hald/hald.c      |   26 +++++
 hald/hald_dbus.c |  269 +++++++++++++++++++++++++++++++++++++++++++++++++++++-
 hald/hald_dbus.h |    3 +
 3 files changed, 294 insertions(+), 4 deletions(-)

diff --git a/hald/hald.c b/hald/hald.c
index c9bc2f7..394bb1e 100644
--- a/hald/hald.c
+++ b/hald/hald.c
@@ -5,6 +5,7 @@
  *
  * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
  * Copyright (C) 2005 Danny Kukawka, <danny.kukawka at web.de>
+ * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor at codethink.co.uk>
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -123,8 +124,33 @@ gdl_store_changed (HalDeviceStore *store, HalDevice *device,
 					    command_line, hal_device_get_udi(device)));
 			}
 		}
+		for (hal_device_property_strlist_iter_init (device, "info.addons.singleton", &iter);
+		     hal_device_property_strlist_iter_is_valid (&iter);
+		     hal_device_property_strlist_iter_next (&iter)) {
+			const gchar *command_line;
+
+			command_line = hal_device_property_strlist_iter_get_value (&iter);
+
+			if (hald_singleton_device_added (command_line, device))
+				hal_device_inc_num_addons (device);
+			else
+				HAL_ERROR(("Couldn't add device to singleton"));
+		}
+
 	} else {
+		HalDeviceStrListIter iter;
+
 		HAL_INFO (("Removed device from GDL; udi=%s", hal_device_get_udi(device)));
+		for (hal_device_property_strlist_iter_init (device, "info.addons.singleton", &iter);
+		     hal_device_property_strlist_iter_is_valid (&iter);
+		     hal_device_property_strlist_iter_next (&iter)) {
+			const gchar *command_line;
+
+			command_line = hal_device_property_strlist_iter_get_value (&iter);
+
+			hald_singleton_device_removed (command_line, device);
+		}
+
 		hald_runner_kill_device(device);
 	}
 
diff --git a/hald/hald_dbus.c b/hald/hald_dbus.c
index 8cb09ae..509d66f 100644
--- a/hald/hald_dbus.c
+++ b/hald/hald_dbus.c
@@ -4,6 +4,7 @@
  * dbus.c : D-BUS interface of HAL daemon
  *
  * Copyright (C) 2003 David Zeuthen, <david at fubar.dk>
+ * Copyright (C) 2007 Codethink Ltd. Author Rob Taylor <rob.taylor at codethink.co.uk>
  *
  * Licensed under the Academic Free License version 2.1
  *
@@ -34,7 +35,8 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <sys/time.h>
-
+#include <glib.h>
+#include <glib/gprintf.h>
 #include <dbus/dbus.h>
 #include <dbus/dbus-glib-lowlevel.h>
 
@@ -61,6 +63,7 @@ static CITracker *ci_tracker = NULL;
 #ifdef HAVE_CONKIT
 static CKTracker *ck_tracker = NULL;
 #endif
+static GHashTable *singletons = NULL;
 
 static void
 raise_error (DBusConnection *connection,
@@ -3229,6 +3232,255 @@ addon_is_ready (DBusConnection * connection, DBusMessage * message, dbus_bool_t
 	return DBUS_HANDLER_RESULT_HANDLED;
 }
 
+typedef struct _SingletonInfo SingletonInfo;
+struct _SingletonInfo
+{
+	DBusConnection *connection;
+	GList *devices;
+};
+
+static void
+singleton_info_destroy (SingletonInfo *info)
+{
+	if (info->devices) {
+		HAL_ERROR (("Singleton '%s' exited with devices still to handle"));
+		/*should we signal the devices that the addon's gone?*/
+		g_list_free (info->devices);
+	}
+	g_free(info);
+}
+
+static gboolean
+singleton_remove_by_connection (char *udi,
+			   SingletonInfo *info,
+			   DBusConnection *connection)
+{
+	if (info->connection == connection)
+		return TRUE;
+	else
+		return FALSE;
+}
+
+static gboolean
+singleton_signal_device_changed (DBusConnection *connection, HalDevice *device, gboolean added)
+{
+	DBusError error;
+	DBusMessage *message;
+	DBusMessage *reply;
+	DBusMessageIter iter, iter_dict;
+	const char *udi = hal_device_get_udi (device);
+
+	message = dbus_message_new_method_call (NULL,
+		"/org/freedesktop/Hal/SingletonAddon",
+		"org.freedesktop.Hal.SingletonAddon",
+		added ? "DeviceAdded" : "DeviceRemoved");
+
+	if (message == NULL)
+		DIE (("No memory"));
+	dbus_message_iter_init_append (message, &iter);
+
+	dbus_message_iter_append_basic (&iter, DBUS_TYPE_STRING,
+					&udi);
+
+	dbus_message_iter_open_container (&iter,
+					  DBUS_TYPE_ARRAY,
+					  DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+					  DBUS_TYPE_STRING_AS_STRING
+					  DBUS_TYPE_VARIANT_AS_STRING
+					  DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+					  &iter_dict);
+
+	hal_device_property_foreach (device,
+				     foreach_property_append,
+				     &iter_dict);
+
+	dbus_message_iter_close_container (&iter, &iter_dict);
+
+	HAL_DEBUG (("%s about to send message to connection %p", G_STRFUNC, connection));
+	dbus_error_init (&error);
+
+	reply = dbus_connection_send_with_reply_and_block (connection, message, -1 , &error);
+
+	if (reply == NULL) {
+		HAL_ERROR (("Error calling %s on singleton %s: %s",
+		      added ? "DeviceAdded" : "DeviceRemoved",
+		      error.name, error.message));
+		dbus_message_unref (message);
+		return FALSE;
+	}
+
+	//no reply needed, i think
+
+	dbus_message_unref (message);
+	dbus_message_unref (reply);
+
+	return TRUE;
+}
+
+/**
+ * hald_singleton_device_added:
+ * @command_line: command line identifying addon singleton
+ * @device: device being added
+ *
+ * Signal to a singleton addon that a device has been added
+ *
+ * Return: TRUE if successful
+ */
+gboolean
+hald_singleton_device_added (const char * command_line,
+			     HalDevice *device)
+{
+	SingletonInfo *info;
+	gchar *extra_env[2] = {NULL, NULL};
+
+	if (!singletons)
+		singletons = g_hash_table_new_full (
+				g_str_hash, g_str_equal,
+				g_free,
+				(GDestroyNotify) singleton_info_destroy);
+	info = g_hash_table_lookup (singletons, command_line);
+
+	if (!info) {
+		extra_env[0] = g_malloc (strlen (command_line) + 26);
+		g_sprintf (extra_env[0], "SINGLETON_COMMAND_LINE=%s", command_line);
+		if (hald_runner_start_singleton (command_line, extra_env, NULL, NULL, NULL)) {
+			HAL_INFO (("Started singleton addon %s for udi %s",
+				   command_line, hal_device_get_udi(device)));
+		} else {
+			HAL_ERROR (("Cannot start singleton addon %s for udi %s",
+				    command_line, hal_device_get_udi(device)));
+			return FALSE;
+		}
+		g_free (extra_env[0]);
+		info = g_new0 (SingletonInfo, 1);
+		g_hash_table_insert (singletons, g_strdup(command_line), info);
+	}
+
+	info->devices = g_list_prepend (info->devices, device);
+
+	if (info->connection) {
+		singleton_signal_device_changed (info->connection, device, TRUE);
+	} else {
+		HAL_DEBUG (("singleton not initialised yet"));
+	}
+
+        return TRUE;
+}
+
+/**
+ * hald_singleton_device_removed:
+ * @command_line: command line identifying addon singleton
+ * @device: device that is being removed
+ *
+ * Signal to a singleton addon that a device has been removed
+ *
+ * Return: TRUE if successful
+ */
+gboolean
+hald_singleton_device_removed (const char * command_line,
+			       HalDevice *device)
+{
+	SingletonInfo *info;
+	GList *lp;
+
+	if (G_UNLIKELY (!singletons)) {
+		HAL_ERROR (("Singleton table is not initialied"));
+		return FALSE;
+	}
+
+	info = g_hash_table_lookup (singletons, command_line);
+
+	if (G_UNLIKELY (!info)) {
+		HAL_WARNING (("Attempting to remove a device from an unknown singleton %s", command_line));
+		return FALSE;
+	}
+
+	lp = g_list_find (info->devices, device);
+	if (G_UNLIKELY (!lp)) {
+		HAL_WARNING (("Device was not in use by this singleton: %s", command_line));
+		return FALSE;
+	}
+
+	info->devices = g_list_remove_link (info->devices, lp);
+	g_list_free1 (lp);
+
+	if (G_LIKELY (info->connection)) {
+		singleton_signal_device_changed (info->connection, device, FALSE);
+	}
+
+	return TRUE;
+}
+
+static DBusHandlerResult
+singleton_addon_is_ready (DBusConnection * connection, DBusMessage * message, dbus_bool_t local_interface)
+{
+	HalDevice *device;
+	SingletonInfo *info;
+	DBusMessage *reply;
+	DBusError error;
+	const char *command_line;
+	GList *lp;
+
+	HAL_TRACE (("entering"));
+	HAL_DEBUG (("singleton_addon_is_ready"));
+
+	if (!local_interface) {
+		raise_permission_denied (connection, message, "SingletonAddonIsReady: only allowed for helpers");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	dbus_error_init (&error);
+	if (!dbus_message_get_args (message, &error,
+				    DBUS_TYPE_STRING, &command_line,
+				    DBUS_TYPE_INVALID)) {
+		raise_syntax (connection, message, "SingletonAddonIsReady");
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	if (G_UNLIKELY (!singletons)) {
+		HAL_ERROR (("Got SingletonIsReady with no known singletons"));
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	info = g_hash_table_lookup (singletons, command_line);
+
+	if (G_UNLIKELY (!info)) {
+		HAL_ERROR (("Got SingletonIsReady from unknown singleton"));
+		return DBUS_HANDLER_RESULT_HANDLED;
+	}
+
+	HAL_INFO (("SingletonAddonIsReady recieved for '%s'", command_line));
+
+	reply = dbus_message_new_method_return (message);
+	if (reply == NULL)
+		DIE (("No memory"));
+
+	if (!dbus_connection_send (connection, reply, NULL))
+		DIE (("No memory"));
+
+	dbus_message_unref (reply);
+
+	info->connection = connection;
+
+	HAL_DEBUG (("Signalling device added for queued devices"));
+	for (lp = info->devices; lp; lp = lp->next) {
+		device = lp->data;
+
+		HAL_DEBUG (("device added for '%s'", hal_device_get_udi (device)));
+		singleton_signal_device_changed (connection, device, TRUE);
+
+		HAL_DEBUG (("incrementing ready addons for device"));
+		if (hal_device_inc_num_ready_addons (device)) {
+			if (hal_device_are_all_addons_ready (device)) {
+				manager_send_signal_device_added (device);
+			}
+		}
+	}
+
+
+	return DBUS_HANDLER_RESULT_HANDLED;
+}
+
 
 /*
  * Create new device in tdl. Return temporary udi.
@@ -4026,7 +4278,9 @@ do_introspect (DBusConnection  *connection,
 				       "    <method name=\"ReleaseGlobalInterfaceLock\">\n"
 				       "      <arg name=\"interface_name\" direction=\"in\" type=\"s\"/>\n"
 				       "    </method>\n"
-
+				       "    <method name=\"SingletonAddonIsReady\">\n"
+				       "      <arg name=\"command_line\" direction=\"in\" type=\"s\"/>\n"
+				       "    </method>\n"
 				       "    <signal name=\"DeviceAdded\">\n"
 				       "      <arg name=\"udi\" type=\"s\"/>\n"
 				       "    </signal>\n"
@@ -4433,7 +4687,13 @@ hald_dbus_filter_handle_methods (DBusConnection *connection, DBusMessage *messag
 						"ReleaseGlobalInterfaceLock") &&
                    strcmp (dbus_message_get_path (message), "/org/freedesktop/Hal/Manager") == 0) {
 		return device_release_global_interface_lock (connection, message, local_interface);
-                
+	} else if (dbus_message_is_method_call (message,
+						"org.freedesktop.Hal.Manager",
+						"SingletonAddonIsReady") &&
+		   strcmp (dbus_message_get_path (message),
+			    "/org/freedesktop/Hal/Manager") == 0) {
+		return singleton_addon_is_ready (connection, message, local_interface);
+
 	} else if (dbus_message_is_method_call (message,
 						"org.freedesktop.Hal.Device",
 						"AcquireInterfaceLock")) {
@@ -4818,7 +5078,6 @@ out:
 }
 
 
-
 static DBusHandlerResult 
 local_server_message_handler (DBusConnection *connection, 
 			      DBusMessage *message, 
@@ -4864,6 +5123,8 @@ local_server_message_handler (DBusConnection *connection,
 			}
 		}
 
+		g_hash_table_foreach_remove (singletons, (GHRFunc) singleton_remove_by_connection, connection);
+
 		dbus_connection_unref (connection);
 		return DBUS_HANDLER_RESULT_HANDLED;
 	} else if (dbus_message_get_type (message) == DBUS_MESSAGE_TYPE_SIGNAL) {
diff --git a/hald/hald_dbus.h b/hald/hald_dbus.h
index 4ec9239..40187a6 100644
--- a/hald/hald_dbus.h
+++ b/hald/hald_dbus.h
@@ -115,6 +115,9 @@ char *hald_dbus_local_server_addr (void);
 
 gboolean device_is_executing_method (HalDevice *d, const char *interface_name, const char *method_name);
 
+
+gboolean hald_singleton_device_added (const char * commandline, HalDevice *device);
+gboolean hald_singleton_device_removed (const char * commandline, HalDevice *device);
 #ifdef HAVE_CONKIT
 #include "ck-tracker.h"
 
-- 
1.5.2-rc3.GIT


--------------050607030001010405020902
Content-Type: text/x-patch;
 name="0003-libhal-support-for-addon-singletons.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filename="0003-libhal-support-for-addon-singletons.patch"



More information about the hal mailing list