[gnome-software/gnome-3-22] Add some thread locking in GsApp



commit 6963ee3e21f3edceb789c1eb9b8f942156e89bde
Author: Richard Hughes <richard hughsie com>
Date:   Thu Dec 1 21:30:16 2016 +0000

    Add some thread locking in GsApp
    
    This should fix some hard-to-debug fairly common threading issues reported in
    the Fedora retrace server.

 src/gs-app.c       |   34 ++++++++++++++++++++++++++++++++++
 src/gs-self-test.c |   30 ++++++++++++++++++++++++++++++
 2 files changed, 64 insertions(+), 0 deletions(-)
---
diff --git a/src/gs-app.c b/src/gs-app.c
index cee6452..cf6a637 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -58,6 +58,7 @@ struct _GsApp
 {
        GObject                  parent_instance;
 
+       GMutex                   mutex;
        gchar                   *id;
        gchar                   *unique_id;
        gboolean                 unique_id_valid;
@@ -529,6 +530,7 @@ gs_app_get_id (GsApp *app)
 void
 gs_app_set_id (GsApp *app, const gchar *id)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
 
        /* check for old-style prefix */
@@ -960,6 +962,7 @@ gs_app_set_kind (GsApp *app, AsAppKind kind)
 const gchar *
 gs_app_get_unique_id (GsApp *app)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_val_if_fail (GS_IS_APP (app), NULL);
 
        /* invalid */
@@ -993,6 +996,7 @@ gs_app_get_unique_id (GsApp *app)
 void
 gs_app_set_unique_id (GsApp *app, const gchar *unique_id)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
 
        /* check for sanity */
@@ -1034,6 +1038,7 @@ gs_app_get_name (GsApp *app)
 void
 gs_app_set_name (GsApp *app, GsAppQuality quality, const gchar *name)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
 
        /* only save this if the data is sufficiently high quality */
@@ -1074,6 +1079,7 @@ gs_app_get_branch (GsApp *app)
 void
 gs_app_set_branch (GsApp *app, const gchar *branch)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_free (app->branch);
        app->branch = g_strdup (branch);
@@ -1159,6 +1165,7 @@ gs_app_get_sources (GsApp *app)
 void
 gs_app_set_sources (GsApp *app, GPtrArray *sources)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        if (app->sources != NULL)
                g_ptr_array_unref (app->sources);
@@ -1212,6 +1219,7 @@ gs_app_get_source_ids (GsApp *app)
 void
 gs_app_clear_source_ids (GsApp *app)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_ptr_array_set_size (app->source_ids, 0);
 }
@@ -1229,6 +1237,7 @@ gs_app_clear_source_ids (GsApp *app)
 void
 gs_app_set_source_ids (GsApp *app, GPtrArray *source_ids)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        if (app->source_ids != NULL)
                g_ptr_array_unref (app->source_ids);
@@ -1292,6 +1301,7 @@ gs_app_get_project_group (GsApp *app)
 void
 gs_app_set_project_group (GsApp *app, const gchar *project_group)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_free (app->project_group);
        app->project_group = g_strdup (project_group);
@@ -1344,6 +1354,7 @@ gs_app_get_icons (GsApp *app)
 void
 gs_app_add_icon (GsApp *app, AsIcon *icon)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        if (icon == NULL) {
                g_ptr_array_set_size (app->icons, 0);
@@ -1383,6 +1394,7 @@ gs_app_get_local_file (GsApp *app)
 void
 gs_app_set_local_file (GsApp *app, GFile *local_file)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_set_object (&app->local_file, local_file);
 }
@@ -1416,6 +1428,7 @@ gs_app_get_runtime (GsApp *app)
 void
 gs_app_set_runtime (GsApp *app, GsApp *runtime)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_set_object (&app->runtime, runtime);
 }
@@ -1432,6 +1445,7 @@ gs_app_set_runtime (GsApp *app, GsApp *runtime)
 void
 gs_app_set_pixbuf (GsApp *app, GdkPixbuf *pixbuf)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_set_object (&app->pixbuf, pixbuf);
 }
@@ -1591,6 +1605,7 @@ gs_app_get_version_ui (GsApp *app)
 void
 gs_app_set_version (GsApp *app, const gchar *version)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_free (app->version);
        app->version = g_strdup (version);
@@ -1628,6 +1643,7 @@ gs_app_get_summary (GsApp *app)
 void
 gs_app_set_summary (GsApp *app, GsAppQuality quality, const gchar *summary)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
 
        /* only save this if the data is sufficiently high quality */
@@ -1669,6 +1685,7 @@ gs_app_get_description (GsApp *app)
 void
 gs_app_set_description (GsApp *app, GsAppQuality quality, const gchar *description)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
 
        /* only save this if the data is sufficiently high quality */
@@ -1711,6 +1728,7 @@ gs_app_get_url (GsApp *app, AsUrlKind kind)
 void
 gs_app_set_url (GsApp *app, AsUrlKind kind, const gchar *url)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_hash_table_insert (app->urls,
                             g_strdup (as_url_kind_to_string (kind)),
@@ -1781,6 +1799,7 @@ gs_app_get_license_token_is_nonfree (const gchar *token)
 void
 gs_app_set_license (GsApp *app, GsAppQuality quality, const gchar *license)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        guint i;
        g_auto(GStrv) tokens = NULL;
 
@@ -1841,6 +1860,7 @@ gs_app_get_summary_missing (GsApp *app)
 void
 gs_app_set_summary_missing (GsApp *app, const gchar *summary_missing)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_free (app->summary_missing);
        app->summary_missing = g_strdup (summary_missing);
@@ -1878,6 +1898,7 @@ gs_app_get_menu_path (GsApp *app)
 void
 gs_app_set_menu_path (GsApp *app, gchar **menu_path)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_strfreev (app->menu_path);
        app->menu_path = g_strdupv (menu_path);
@@ -1912,6 +1933,7 @@ gs_app_get_origin (GsApp *app)
 void
 gs_app_set_origin (GsApp *app, const gchar *origin)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        if (origin == app->origin)
                return;
@@ -1962,6 +1984,7 @@ gs_app_get_origin_ui (GsApp *app)
 void
 gs_app_set_origin_ui (GsApp *app, const gchar *origin_ui)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        if (origin_ui == app->origin_ui)
                return;
@@ -2004,6 +2027,7 @@ gs_app_get_origin_hostname (GsApp *app)
 void
 gs_app_set_origin_hostname (GsApp *app, const gchar *origin_hostname)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_autoptr(SoupURI) uri = NULL;
        guint i;
        const gchar *prefixes[] = { "download.", "mirrors.", NULL };
@@ -2124,6 +2148,7 @@ gs_app_set_update_version_internal (GsApp *app, const gchar *update_version)
 void
 gs_app_set_update_version (GsApp *app, const gchar *update_version)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        gs_app_set_update_version_internal (app, update_version);
        gs_app_queue_notify (app, "version");
@@ -2158,6 +2183,7 @@ gs_app_get_update_details (GsApp *app)
 void
 gs_app_set_update_details (GsApp *app, const gchar *update_details)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_free (app->update_details);
        app->update_details = g_strdup (update_details);
@@ -2235,6 +2261,7 @@ gs_app_get_management_plugin (GsApp *app)
 void
 gs_app_set_management_plugin (GsApp *app, const gchar *management_plugin)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
 
        /* plugins cannot adopt wildcard packages */
@@ -2327,6 +2354,7 @@ gs_app_get_review_ratings (GsApp *app)
 void
 gs_app_set_review_ratings (GsApp *app, GArray *review_ratings)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        if (app->review_ratings != NULL)
                g_array_unref (app->review_ratings);
@@ -2550,6 +2578,7 @@ gs_app_get_metadata_item (GsApp *app, const gchar *key)
 void
 gs_app_set_metadata (GsApp *app, const gchar *key, const gchar *value)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        const gchar *found;
        GString *str;
 
@@ -2836,6 +2865,7 @@ gs_app_has_category (GsApp *app, const gchar *category)
 void
 gs_app_set_categories (GsApp *app, GPtrArray *categories)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (categories != NULL);
        if (app->categories != NULL)
@@ -2891,6 +2921,7 @@ gs_app_get_key_colors (GsApp *app)
 void
 gs_app_set_key_colors (GsApp *app, GPtrArray *key_colors)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (key_colors != NULL);
        if (app->key_colors != NULL)
@@ -2944,6 +2975,7 @@ gs_app_get_keywords (GsApp *app)
 void
 gs_app_set_keywords (GsApp *app, GPtrArray *keywords)
 {
+       g_autoptr(GMutexLocker) locker = g_mutex_locker_new (&app->mutex);
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (keywords != NULL);
        if (app->keywords != NULL)
@@ -3379,6 +3411,7 @@ gs_app_finalize (GObject *object)
 {
        GsApp *app = GS_APP (object);
 
+       g_mutex_clear (&app->mutex);
        g_free (app->id);
        g_free (app->unique_id);
        g_free (app->branch);
@@ -3551,6 +3584,7 @@ gs_app_init (GsApp *app)
                                            g_str_equal,
                                            g_free,
                                            g_free);
+       g_mutex_init (&app->mutex);
 }
 
 /**
diff --git a/src/gs-self-test.c b/src/gs-self-test.c
index 5ca9017..fd76b63 100644
--- a/src/gs-self-test.c
+++ b/src/gs-self-test.c
@@ -275,6 +275,35 @@ gs_plugin_func (void)
        g_object_unref (list);
 }
 
+static gpointer
+gs_app_thread_cb (gpointer data)
+{
+       GsApp *app = GS_APP (data);
+       for (guint i = 0; i < 10000; i++) {
+               g_assert_cmpstr (gs_app_get_unique_id (app), !=, NULL);
+               gs_app_set_branch (app, "master");
+               g_assert_cmpstr (gs_app_get_unique_id (app), !=, NULL);
+               gs_app_set_branch (app, "stable");
+       }
+       return NULL;
+}
+
+static void
+gs_app_thread_func (void)
+{
+       g_autoptr(GsApp) app = gs_app_new ("gimp.desktop");
+       g_autoptr(GThread) thread1 = NULL;
+       g_autoptr(GThread) thread2 = NULL;
+
+       /* try really hard to cause a threading problem */
+       g_setenv ("G_MESSAGES_DEBUG", "", TRUE);
+       thread1 = g_thread_new ("thread1", gs_app_thread_cb, app);
+       thread2 = g_thread_new ("thread2", gs_app_thread_cb, app);
+       g_thread_join (thread1);
+       g_thread_join (thread2);
+       g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+}
+
 static void
 gs_app_unique_id_func (void)
 {
@@ -1378,6 +1407,7 @@ main (int argc, char **argv)
        g_test_add_func ("/gnome-software/os-release", gs_os_release_func);
        g_test_add_func ("/gnome-software/app", gs_app_func);
        g_test_add_func ("/gnome-software/app{unique-id}", gs_app_unique_id_func);
+       g_test_add_func ("/gnome-software/app{thread}", gs_app_thread_func);
        g_test_add_func ("/gnome-software/plugin", gs_plugin_func);
        g_test_add_func ("/gnome-software/plugin{error}", gs_plugin_error_func);
        g_test_add_func ("/gnome-software/plugin{global-cache}", gs_plugin_global_cache_func);


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]