diff options
author | Aleksander Morgado <aleksander@gnu.org> | 2011-09-06 00:12:57 +0200 |
---|---|---|
committer | Aleksander Morgado <aleksander@lanedo.com> | 2012-03-15 14:14:19 +0100 |
commit | 1e3213970714e5d5144ba0a00ea47d0c9681cce4 (patch) | |
tree | 3193f0e37afbcb514620d76a0c0e4bce0b27603a | |
parent | 7007825781122c1f1942a4135f39088ab75782f3 (diff) |
plugin-manager: new method to look for best plugin supporting a given port
The new `mm_plugin_manager_find_port_support()' method requests the Plugin
Manager to iterate over the list of plugins internally handled, launching
supports task for the given port in each of them.
The method is fully asynchronous, and the result can be retrieved with
`mm_plugin_manager_find_port_support_finish()' once the operation is ready.
-rw-r--r-- | src/mm-plugin-manager.c | 203 | ||||
-rw-r--r-- | src/mm-plugin-manager.h | 16 |
2 files changed, 219 insertions, 0 deletions
diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c index d9050624..aaaab048 100644 --- a/src/mm-plugin-manager.c +++ b/src/mm-plugin-manager.c @@ -26,6 +26,9 @@ #include "mm-errors.h" #include "mm-log.h" +/* Default time to defer probing checks */ +#define SUPPORTS_DEFER_TIMEOUT_SECS 3 + static void initable_iface_init (GInitableIface *iface); G_DEFINE_TYPE_EXTENDED (MMPluginManager, mm_plugin_manager, G_TYPE_OBJECT, 0, @@ -38,6 +41,206 @@ struct _MMPluginManagerPrivate { GSList *plugins; }; +/* Context of the task looking for best port support */ +typedef struct { + MMPluginManager *self; + GSimpleAsyncResult *result; + /* Input context */ + gchar *subsys; + gchar *name; + gchar *physdev_path; + MMModem *existing; + /* Current context */ + GSList *current; + guint source_id; + /* Output context */ + guint best_level; + MMPlugin *best_plugin; +} SupportsInfo; + +static gboolean find_port_support_idle (SupportsInfo *info); + +static void +supports_info_free (SupportsInfo *info) +{ + if (!info) + return; + + /* There shouldn't be any ongoing supports operation */ + g_assert (info->current == NULL); + + /* There shouldn't be any scheduled source */ + g_assert (info->source_id == 0); + + if (info->existing) + g_object_unref (info->existing); + + g_object_unref (info->result); + g_free (info->subsys); + g_free (info->name); + g_free (info->physdev_path); + g_free (info); +} + +static void +supports_port_ready_cb (MMPlugin *plugin, + GAsyncResult *result, + SupportsInfo *info) +{ + MMPluginSupportsResult support_result; + GError *error = NULL; + guint level = 0; + + /* Get supports check results */ + support_result = mm_plugin_supports_port_finish (plugin, + result, + &level, + &error); + if (error) { + mm_warn ("(%s): (%s) error when checking support: '%s'", + mm_plugin_get_name (plugin), + info->name, + error->message); + g_error_free (error); + } + + switch (support_result) { + case MM_PLUGIN_SUPPORTS_PORT_SUPPORTED: + /* Is this plugin's result better than any one we've tried before? */ + if (level > info->best_level) { + info->best_level = level; + info->best_plugin = plugin; + } + + /* Go on to the next plugin */ + info->current = g_slist_next (info->current); + + /* Don't bother with Generic if some other plugin already supports + * this port */ + if (info->best_plugin && + info->current && + !strcmp (mm_plugin_get_name (MM_PLUGIN (info->current->data)), + MM_PLUGIN_GENERIC_NAME)) { + mm_dbg ("(%s): (%s) found best plugin for port", + mm_plugin_get_name (info->best_plugin), + info->name); + info->current = NULL; + } + + /* Schedule checking support with next plugin */ + info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, + info); + break; + + case MM_PLUGIN_SUPPORTS_PORT_UNSUPPORTED: + /* If the plugin knows it doesn't support the modem, just keep on + * checking the next plugin. + */ + info->current = g_slist_next (info->current); + info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, + info); + break; + + case MM_PLUGIN_SUPPORTS_PORT_DEFER: + mm_dbg ("(%s): (%s) deferring support check", + mm_plugin_get_name (MM_PLUGIN (info->current->data)), + info->name); + /* Schedule checking support with the same plugin */ + info->source_id = g_timeout_add_seconds (SUPPORTS_DEFER_TIMEOUT_SECS, + (GSourceFunc)find_port_support_idle, + info); + break; + + case MM_PLUGIN_SUPPORTS_PORT_IN_PROGRESS: + /* We have full asynchronous support, now, so we shouldn't get an + * intermediate state here. */ + g_assert_not_reached (); + } +} + +static gboolean +find_port_support_idle (SupportsInfo *info) +{ + info->source_id = 0; + + /* Already checked all plugins? */ + if (!info->current) { + /* Report best plugin in asynchronous result (could be none) + * Note: plugins are not expected to be removed while these + * operations are ongoing, so no issue if we don't ref/unref + * them. */ + g_simple_async_result_set_op_res_gpointer ( + info->result, + info->best_plugin, + NULL); + + /* The asynchronous operation is always completed here */ + g_simple_async_result_complete (info->result); + supports_info_free (info); + return FALSE; + } + + /* Ask the current plugin to check support of this port */ + mm_plugin_supports_port (MM_PLUGIN (info->current->data), + info->subsys, + info->name, + info->physdev_path, + info->existing, + (GAsyncReadyCallback)supports_port_ready_cb, + info); + return FALSE; +} + +MMPlugin * +mm_plugin_manager_find_port_support_finish (MMPluginManager *self, + GAsyncResult *result, + GError **error) +{ + g_return_val_if_fail (MM_IS_PLUGIN_MANAGER (self), NULL); + g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL); + + /* Propagate error, if any */ + if (g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result), error)) + return NULL; + + /* Return the plugin found, if any */ + return g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (result)); +} + +void +mm_plugin_manager_find_port_support (MMPluginManager *self, + const gchar *subsys, + const gchar *name, + const gchar *physdev_path, + MMModem *existing, + GAsyncReadyCallback callback, + gpointer user_data) +{ + SupportsInfo *info; + + g_return_if_fail (MM_IS_PLUGIN_MANAGER (self)); + + /* Setup supports info */ + info = g_malloc0 (sizeof (SupportsInfo)); + info->self = self; /* SupportsInfo lives as long as self lives */ + info->subsys = g_strdup (subsys); + info->name = g_strdup (name); + info->physdev_path = g_strdup (physdev_path); + if (existing) + info->existing = g_object_ref (existing); + info->result = g_simple_async_result_new (G_OBJECT (self), + callback, + user_data, + NULL); + + /* Set first plugin to check */ + info->current = self->priv->plugins; + + /* Schedule the processing of the supports task in an idle */ + info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle, + info); +} + static MMPlugin * load_plugin (const gchar *path) { diff --git a/src/mm-plugin-manager.h b/src/mm-plugin-manager.h index 001fd34b..673ec932 100644 --- a/src/mm-plugin-manager.h +++ b/src/mm-plugin-manager.h @@ -20,6 +20,9 @@ #include <glib-object.h> +#include "mm-plugin.h" +#include "mm-modem.h" + #define MM_TYPE_PLUGIN_MANAGER (mm_plugin_manager_get_type ()) #define MM_PLUGIN_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MM_TYPE_PLUGIN_MANAGER, MMPluginManager)) #define MM_PLUGIN_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MM_TYPE_PLUGIN_MANAGER, MMPluginManagerClass)) @@ -42,4 +45,17 @@ GType mm_plugin_manager_get_type (void); MMPluginManager *mm_plugin_manager_new (GError **error); +/* Asynchronous operation to find the best plugin giving support to a + * given port. */ +void mm_plugin_manager_find_port_support (MMPluginManager *self, + const gchar *subsys, + const gchar *name, + const gchar *physdev_path, + MMModem *existing, + GAsyncReadyCallback callback, + gpointer user_data); +MMPlugin *mm_plugin_manager_find_port_support_finish (MMPluginManager *self, + GAsyncResult *result, + GError **error); + #endif /* MM_PLUGIN_MANAGER_H */ |