aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-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 aaaab048..80f05533 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);