[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