summaryrefslogtreecommitdiff
path: root/src/mm-plugin-manager.c
diff options
context:
space:
mode:
authorAleksander Morgado <aleksander@gnu.org>2011-09-06 00:47:02 +0200
committerAleksander Morgado <aleksander@lanedo.com>2012-03-15 14:14:19 +0100
commit0626de08796d4411c6c0e38e002b0ec3919893fd (patch)
tree2e9fdab349a706621295ebb0b7299c6a6b1c37f1 /src/mm-plugin-manager.c
parent1e3213970714e5d5144ba0a00ea47d0c9681cce4 (diff)
downloadModemManager-0626de08796d4411c6c0e38e002b0ec3919893fd.tar.gz
plugin-manager: keep track of all launched support checks
We will keep a reference to each of the support checks currently in progress, grouped by physical device path. The stored SupportsInfo structs as well as the support check operations, are guaranteed to be kept valid as long as the Plugin Manager exists. Or in other words, the Plugin Manager cannot be disposed if there is still an ongoing supports check operation.
Diffstat (limited to 'src/mm-plugin-manager.c')
-rw-r--r--src/mm-plugin-manager.c86
1 files changed, 86 insertions, 0 deletions
diff --git a/src/mm-plugin-manager.c b/src/mm-plugin-manager.c
index aaaab0488..80f055332 100644
--- a/src/mm-plugin-manager.c
+++ b/src/mm-plugin-manager.c
@@ -39,8 +39,21 @@ struct _MMPluginManagerPrivate {
/* The list of plugins. It is loaded once when the program starts, and the
* list is NOT expected to change after that. */
GSList *plugins;
+
+ /* Hash table to keep track of support tasks, using physical path of the
+ * device as key (which means that more than one tasks may be associated
+ * to the same key if the modem happens to show more than one port).
+ * The data in each HT item will be SupportsInfoList (not a GSList directly,
+ * as we want to be able to modify the list without replacing items with
+ * the HT API, which also replaces keys). */
+ GHashTable *supports;
};
+/* List of support infos associated to the same physical device */
+typedef struct {
+ GSList *info_list;
+} SupportsInfoList;
+
/* Context of the task looking for best port support */
typedef struct {
MMPluginManager *self;
@@ -83,6 +96,56 @@ supports_info_free (SupportsInfo *info)
}
static void
+supports_info_list_free (SupportsInfoList *list)
+{
+ g_slist_foreach (list->info_list,
+ (GFunc)supports_info_free,
+ NULL);
+ g_slist_free (list->info_list);
+ g_free (list);
+}
+
+static void
+add_supports_info (MMPluginManager *self,
+ SupportsInfo *info)
+{
+ SupportsInfoList *list;
+
+ list = g_hash_table_lookup (self->priv->supports,
+ info->physdev_path);
+ if (!list) {
+ list = g_malloc0 (sizeof (SupportsInfoList));
+ g_hash_table_insert (self->priv->supports,
+ g_strdup (info->physdev_path),
+ list);
+ }
+
+ list->info_list = g_slist_append (list->info_list, info);
+}
+
+static void
+remove_supports_info (MMPluginManager *self,
+ SupportsInfo *info)
+{
+ SupportsInfoList *list;
+
+ list = g_hash_table_lookup (self->priv->supports,
+ info->physdev_path);
+ g_assert (list != NULL);
+ g_assert (list->info_list != NULL);
+
+ list->info_list = g_slist_remove (list->info_list, info);
+
+ /* If it was the last info for the given physical path,
+ * also remove it */
+ if (!list->info_list)
+ g_hash_table_remove (self->priv->supports,
+ info->physdev_path);
+
+ /* Note that we just remove it from the list, we don't free it */
+}
+
+static void
supports_port_ready_cb (MMPlugin *plugin,
GAsyncResult *result,
SupportsInfo *info)
@@ -174,8 +237,14 @@ find_port_support_idle (SupportsInfo *info)
info->best_plugin,
NULL);
+ /* We are only giving the plugin as result, so we can now safely remove
+ * the supports info from the manager. Always untrack the supports info
+ * before completing the operation. */
+ remove_supports_info (info->self, info);
+
/* The asynchronous operation is always completed here */
g_simple_async_result_complete (info->result);
+
supports_info_free (info);
return FALSE;
}
@@ -236,6 +305,10 @@ mm_plugin_manager_find_port_support (MMPluginManager *self,
/* Set first plugin to check */
info->current = self->priv->plugins;
+ /* We will keep track of the supports info internally.
+ * Ownership of the supports info will belong to the manager now. */
+ add_supports_info (self, info);
+
/* Schedule the processing of the supports task in an idle */
info->source_id = g_idle_add ((GSourceFunc)find_port_support_idle,
info);
@@ -429,6 +502,12 @@ mm_plugin_manager_init (MMPluginManager *manager)
manager->priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
MM_TYPE_PLUGIN_MANAGER,
MMPluginManagerPrivate);
+
+ manager->priv->supports = g_hash_table_new_full (
+ g_str_hash,
+ g_str_equal,
+ g_free,
+ (GDestroyNotify)supports_info_list_free);
}
static gboolean
@@ -445,6 +524,13 @@ finalize (GObject *object)
{
MMPluginManager *self = MM_PLUGIN_MANAGER (object);
+ /* The Plugin Manager will only be finalized when all support tasks have
+ * been finished (as the GSimpleAsyncResult takes a reference to the object.
+ * Therefore, the hash table of support tasks should always be empty.
+ */
+ g_assert (g_hash_table_size (self->priv->supports) == 0);
+ g_hash_table_destroy (self->priv->supports);
+
/* Cleanup list of plugins */
g_slist_foreach (self->priv->plugins, (GFunc)g_object_unref, NULL);
g_slist_free (self->priv->plugins);