[gnome-software] Fix thread safety issues in the plugins
- From: Giovanni Campagna <gcampagna src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Fix thread safety issues in the plugins
- Date: Sun, 1 Sep 2013 20:22:30 +0000 (UTC)
commit 526284fa0dd21d5c281f98e8452461edd4ac0098
Author: Giovanni Campagna <gcampagna src gnome org>
Date: Sat Aug 31 16:34:01 2013 +0200
Fix thread safety issues in the plugins
The plugins are all run in worker threads, so shared data structures
must be protected with locks, and initialization must be protected
with GOnce.
https://bugzilla.gnome.org/show_bug.cgi?id=707185
src/plugins/gs-plugin-datadir-apps.c | 8 ++++++
src/plugins/gs-plugin-datadir-filename.c | 25 ++++++++++++++----
src/plugins/gs-plugin-desktopdb.c | 32 ++++++++++++++++++-----
src/plugins/gs-plugin-hardcoded-descriptions.c | 8 +++---
src/plugins/gs-plugin-hardcoded-ratings.c | 26 ++++++-------------
src/plugins/gs-plugin-local-ratings.c | 11 +++++---
6 files changed, 71 insertions(+), 39 deletions(-)
---
diff --git a/src/plugins/gs-plugin-datadir-apps.c b/src/plugins/gs-plugin-datadir-apps.c
index 23a1aef..97a968f 100644
--- a/src/plugins/gs-plugin-datadir-apps.c
+++ b/src/plugins/gs-plugin-datadir-apps.c
@@ -25,6 +25,7 @@
#include <gs-plugin.h>
struct GsPluginPrivate {
+ GMutex plugin_mutex;
GHashTable *cache;
};
@@ -70,6 +71,7 @@ gs_plugin_initialize (GsPlugin *plugin)
g_str_equal,
g_free,
(GDestroyNotify) gs_plugin_datadir_apps_cache_item_free);
+ g_mutex_init (&plugin->priv->plugin_mutex);
}
/**
@@ -88,6 +90,7 @@ void
gs_plugin_destroy (GsPlugin *plugin)
{
g_hash_table_unref (plugin->priv->cache);
+ g_mutex_clear (&plugin->priv->plugin_mutex);
}
/**
@@ -130,11 +133,14 @@ gs_plugin_datadir_apps_extract_desktop_data (GsPlugin *plugin,
GsPluginDataDirAppsCacheItem *cache_item;
/* is in cache */
+ g_mutex_lock (&plugin->priv->plugin_mutex);
cache_item = g_hash_table_lookup (plugin->priv->cache, desktop_file);
if (cache_item != NULL) {
gs_plugin_datadir_apps_set_from_cache_item (app, cache_item);
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
goto out;
}
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
/* load desktop file */
key_file = g_key_file_new ();
@@ -203,9 +209,11 @@ gs_plugin_datadir_apps_extract_desktop_data (GsPlugin *plugin,
/* add to cache */
gs_plugin_datadir_apps_set_from_cache_item (app, cache_item);
+ g_mutex_lock (&plugin->priv->plugin_mutex);
g_hash_table_insert (plugin->priv->cache,
g_strdup (desktop_file),
cache_item);
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
out:
if (key_file != NULL)
g_key_file_unref (key_file);
diff --git a/src/plugins/gs-plugin-datadir-filename.c b/src/plugins/gs-plugin-datadir-filename.c
index fd4bca7..882e5b0 100644
--- a/src/plugins/gs-plugin-datadir-filename.c
+++ b/src/plugins/gs-plugin-datadir-filename.c
@@ -24,6 +24,7 @@
#include <gs-plugin.h>
struct GsPluginPrivate {
+ GMutex plugin_mutex;
GHashTable *cache;
};
@@ -48,6 +49,7 @@ gs_plugin_initialize (GsPlugin *plugin)
g_str_equal,
g_free,
g_free);
+ g_mutex_init (&plugin->priv->plugin_mutex);
}
/**
@@ -66,17 +68,18 @@ void
gs_plugin_destroy (GsPlugin *plugin)
{
g_hash_table_unref (plugin->priv->cache);
+ g_mutex_clear (&plugin->priv->plugin_mutex);
}
/**
* gs_plugin_datadir_filename_find:
*/
-static const gchar *
+static gchar *
gs_plugin_datadir_filename_find (GsPlugin *plugin,
GsApp *app)
{
const gchar *id;
- const gchar *path_tmp = NULL;
+ gchar *path_tmp = NULL;
gboolean ret;
gchar *path = NULL;
const char * const *datadirs;
@@ -86,14 +89,19 @@ gs_plugin_datadir_filename_find (GsPlugin *plugin,
id = gs_app_get_id (app);
if (id == NULL)
goto out;
+
+ g_mutex_lock (&plugin->priv->plugin_mutex);
ret = g_hash_table_lookup_extended (plugin->priv->cache,
id,
NULL,
(gpointer *) &path_tmp);
if (ret) {
g_debug ("found existing %s", id);
+ path_tmp = g_strdup (path_tmp);
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
goto out;
}
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
/* find if the file exists */
datadirs = g_get_system_data_dirs ();
@@ -102,18 +110,22 @@ gs_plugin_datadir_filename_find (GsPlugin *plugin,
datadirs[i], gs_app_get_id (app));
if (g_file_test (path, G_FILE_TEST_EXISTS)) {
path_tmp = g_strdup (path);
+ g_mutex_lock (&plugin->priv->plugin_mutex);
g_hash_table_insert (plugin->priv->cache,
g_strdup (id),
- (gpointer) path_tmp);
+ g_strdup (path));
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
break;
}
}
if (path_tmp == NULL) {
/* add an empty key to the cache to avoid stat'ing again */
+ g_mutex_lock (&plugin->priv->plugin_mutex);
g_hash_table_insert (plugin->priv->cache,
g_strdup (id),
NULL);
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
}
out:
g_free (path);
@@ -129,7 +141,7 @@ gs_plugin_refine (GsPlugin *plugin,
GCancellable *cancellable,
GError **error)
{
- const gchar *tmp;
+ gchar *tmp;
GList *l;
GsApp *app;
@@ -137,14 +149,15 @@ gs_plugin_refine (GsPlugin *plugin,
app = GS_APP (l->data);
if (gs_app_get_name (app) != NULL)
continue;
- tmp = gs_app_get_metadata_item (app, "datadir-desktop-filename");
- if (tmp != NULL)
+ if (gs_app_get_metadata_item (app, "datadir-desktop-filename") != NULL)
continue;
+
tmp = gs_plugin_datadir_filename_find (plugin, app);
if (tmp != NULL) {
gs_app_set_metadata (app,
"datadir-desktop-filename",
tmp);
+ g_free (tmp);
}
}
return TRUE;
diff --git a/src/plugins/gs-plugin-desktopdb.c b/src/plugins/gs-plugin-desktopdb.c
index 95b6176..ec80c3c 100644
--- a/src/plugins/gs-plugin-desktopdb.c
+++ b/src/plugins/gs-plugin-desktopdb.c
@@ -21,6 +21,8 @@
#include <config.h>
+#include <string.h>
+
#define I_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE
#include <packagekit-glib2/packagekit.h>
@@ -28,7 +30,8 @@
struct GsPluginPrivate {
PkDesktop *desktop;
- gboolean loaded;
+ gsize loaded;
+ GMutex plugin_mutex;
GHashTable *cache;
};
@@ -54,6 +57,7 @@ gs_plugin_initialize (GsPlugin *plugin)
g_str_equal,
g_free,
g_free);
+ g_mutex_init (&plugin->priv->plugin_mutex);
}
/**
@@ -73,6 +77,7 @@ gs_plugin_destroy (GsPlugin *plugin)
{
g_object_unref (plugin->priv->desktop);
g_hash_table_unref (plugin->priv->cache);
+ g_mutex_clear (&plugin->priv->plugin_mutex);
}
/**
@@ -83,15 +88,18 @@ gs_plugin_desktopdb_set_metadata (GsPlugin *plugin,
GsApp *app,
const gchar *pkg_name)
{
- const gchar *desktop_file;
- gchar *id = NULL;
+ gchar *desktop_file;
+ gchar *id = NULL, *dot;
GError *error = NULL;
GPtrArray *files = NULL;
/* is in cache */
+ g_mutex_lock (&plugin->priv->plugin_mutex);
desktop_file = g_hash_table_lookup (plugin->priv->cache, pkg_name);
- if (desktop_file == NULL) {
+ desktop_file = g_strdup (desktop_file);
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
+ if (desktop_file == NULL) {
/* try to get the list of desktop files for this package */
files = pk_desktop_get_shown_for_package (plugin->priv->desktop,
pkg_name,
@@ -108,24 +116,32 @@ gs_plugin_desktopdb_set_metadata (GsPlugin *plugin,
}
/* add just the first desktop file */
- desktop_file = g_ptr_array_index (files, 0);
+ desktop_file = g_strdup (g_ptr_array_index (files, 0));
/* add to the cache */
+ g_mutex_lock (&plugin->priv->plugin_mutex);
g_hash_table_insert (plugin->priv->cache,
g_strdup (pkg_name),
g_strdup (desktop_file));
+ g_mutex_unlock (&plugin->priv->plugin_mutex);
+
}
/* also set the ID if it's missing */
if (gs_app_get_id (app) == NULL) {
id = g_path_get_basename (desktop_file);
- g_strdelimit (id, ".", '\0');
+ dot = strrchr (id, '.');
+ if (dot)
+ *dot = '\0';
+
gs_app_set_id (app, id);
}
gs_app_set_metadata (app,
"datadir-desktop-filename",
desktop_file);
+ g_free (desktop_file);
+
out:
g_free (id);
if (files != NULL)
@@ -147,8 +163,10 @@ gs_plugin_refine (GsPlugin *plugin,
GsApp *app;
/* not loaded yet */
- if (!plugin->priv->loaded) {
+ if (g_once_init_enter (&plugin->priv->loaded)) {
ret = pk_desktop_open_database (plugin->priv->desktop, error);
+ g_once_init_leave (&plugin->priv->loaded, TRUE);
+
if (!ret)
goto out;
}
diff --git a/src/plugins/gs-plugin-hardcoded-descriptions.c b/src/plugins/gs-plugin-hardcoded-descriptions.c
index 988786d..cd2a1b0 100644
--- a/src/plugins/gs-plugin-hardcoded-descriptions.c
+++ b/src/plugins/gs-plugin-hardcoded-descriptions.c
@@ -25,7 +25,7 @@
struct GsPluginPrivate {
GHashTable *cache;
- gboolean loaded;
+ gsize loaded;
};
/**
@@ -111,7 +111,6 @@ gs_plugin_hardcoded_descriptions_add (GsPlugin *plugin, GError **error)
(gpointer) descriptions[i].desc);
}
- plugin->priv->loaded = TRUE;
return TRUE;
}
@@ -130,9 +129,10 @@ gs_plugin_refine (GsPlugin *plugin,
GList *l;
GsApp *app;
- /* already loaded */
- if (!plugin->priv->loaded) {
+ if (g_once_init_enter (&plugin->priv->loaded)) {
ret = gs_plugin_hardcoded_descriptions_add (plugin, error);
+ g_once_init_leave (&plugin->priv->loaded, TRUE);
+
if (!ret)
goto out;
}
diff --git a/src/plugins/gs-plugin-hardcoded-ratings.c b/src/plugins/gs-plugin-hardcoded-ratings.c
index 0a1ff31..65de8e5 100644
--- a/src/plugins/gs-plugin-hardcoded-ratings.c
+++ b/src/plugins/gs-plugin-hardcoded-ratings.c
@@ -25,8 +25,7 @@
struct GsPluginPrivate {
GHashTable *cache;
- gboolean loaded;
- GMutex mutex;
+ gsize loaded;
};
/**
@@ -51,9 +50,6 @@ gs_plugin_initialize (GsPlugin *plugin)
g_str_equal,
NULL,
NULL);
-
- /* can only load from one thread */
- g_mutex_init (&plugin->priv->mutex);
}
/**
@@ -72,7 +68,6 @@ void
gs_plugin_destroy (GsPlugin *plugin)
{
g_hash_table_unref (plugin->priv->cache);
- g_mutex_clear (&plugin->priv->mutex);
}
/**
@@ -693,12 +688,6 @@ gs_plugin_hardcoded_ratings_setup (GsPlugin *plugin, GError **error)
{ -1 ,NULL}
};
- /* protect */
- g_mutex_lock (&plugin->priv->mutex);
-
- if (plugin->priv->loaded)
- goto out;
-
/* add each one to a hash table */
for (i = 0; ratings[i].id != NULL; i++) {
g_hash_table_insert (plugin->priv->cache,
@@ -706,9 +695,6 @@ gs_plugin_hardcoded_ratings_setup (GsPlugin *plugin, GError **error)
GINT_TO_POINTER (ratings[i].value));
}
- plugin->priv->loaded = TRUE;
-out:
- g_mutex_unlock (&plugin->priv->mutex);
return TRUE;
}
@@ -728,9 +714,13 @@ gs_plugin_refine (GsPlugin *plugin,
GsApp *app;
/* already loaded */
- ret = gs_plugin_hardcoded_ratings_setup (plugin, error);
- if (!ret)
- goto out;
+ if (g_once_init_enter (&plugin->priv->loaded)) {
+ ret = gs_plugin_hardcoded_ratings_setup (plugin, error);
+ g_once_init_leave (&plugin->priv->loaded, TRUE);
+
+ if (!ret)
+ goto out;
+ }
/* add any missing ratings data */
for (l = list; l != NULL; l = l->next) {
diff --git a/src/plugins/gs-plugin-local-ratings.c b/src/plugins/gs-plugin-local-ratings.c
index 2818da0..0b2ca7a 100644
--- a/src/plugins/gs-plugin-local-ratings.c
+++ b/src/plugins/gs-plugin-local-ratings.c
@@ -28,7 +28,7 @@
#include <gs-plugin.h>
struct GsPluginPrivate {
- gboolean loaded;
+ gsize loaded;
gchar *db_path;
sqlite3 *db;
};
@@ -132,7 +132,6 @@ gs_plugin_local_ratings_load_db (GsPlugin *plugin,
}
/* success */
- plugin->priv->loaded = TRUE;
out:
return ret;
}
@@ -182,8 +181,10 @@ gs_plugin_app_set_rating (GsPlugin *plugin,
gint rc;
/* already loaded */
- if (!plugin->priv->loaded) {
+ if (g_once_init_enter (&plugin->priv->loaded)) {
ret = gs_plugin_local_ratings_load_db (plugin, error);
+ g_once_init_leave (&plugin->priv->loaded, TRUE);
+
if (!ret)
goto out;
}
@@ -224,8 +225,10 @@ gs_plugin_refine (GsPlugin *plugin,
GsApp *app;
/* already loaded */
- if (!plugin->priv->loaded) {
+ if (g_once_init_enter (&plugin->priv->loaded)) {
ret = gs_plugin_local_ratings_load_db (plugin, error);
+ g_once_init_leave (&plugin->priv->loaded, TRUE);
+
if (!ret)
goto out;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]