[gnome-software/1196-race-condition-under-gs_plugin_icons_load_cached] gs-plugin-icons: Lock GsApp to prevent thread race condition



commit bfc9e8a67ce12ac7a44883a677ff948aec67211b
Author: Milan Crha <mcrha redhat com>
Date:   Fri Mar 26 11:45:58 2021 +0100

    gs-plugin-icons: Lock GsApp to prevent thread race condition
    
    Hold a GsApp lock when ensuring remote application icons are cached
    locally, to avoid race condition when it's done from multiple threads
    for the same application.
    
    Closes https://gitlab.gnome.org/GNOME/gnome-software/-/issues/1196

 lib/gs-app.c                   | 292 +++++++++++++++++++++++------------------
 lib/gs-app.h                   |   2 +
 plugins/core/gs-plugin-icons.c |   4 +
 3 files changed, 169 insertions(+), 129 deletions(-)
---
diff --git a/lib/gs-app.c b/lib/gs-app.c
index 12ee9a292..8f3dc665e 100644
--- a/lib/gs-app.c
+++ b/lib/gs-app.c
@@ -54,7 +54,7 @@ typedef struct
 {
        GObject                  parent_instance;
 
-       GMutex                   mutex;
+       GRecMutex                mutex;
        gchar                   *id;
        gchar                   *unique_id;
        gboolean                 unique_id_valid;
@@ -782,9 +782,9 @@ void
 gs_app_set_id (GsApp *app, const gchar *id)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (_g_set_str (&priv->id, id))
                priv->unique_id_valid = FALSE;
 }
@@ -1151,9 +1151,9 @@ void
 gs_app_set_progress (GsApp *app, guint percentage)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (priv->progress == percentage)
                return;
        if (percentage != GS_APP_PROGRESS_UNKNOWN && percentage > 100) {
@@ -1180,9 +1180,9 @@ void
 gs_app_set_allow_cancel (GsApp *app, gboolean allow_cancel)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (priv->allow_cancel == allow_cancel)
                return;
        priv->allow_cancel = allow_cancel;
@@ -1229,10 +1229,10 @@ void
 gs_app_set_state (GsApp *app, GsAppState state)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (gs_app_set_state_internal (app, state)) {
                /* since the state changed, and the pending-action refers to
@@ -1287,11 +1287,11 @@ gs_app_set_kind (GsApp *app, AsComponentKind kind)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
        gboolean state_change_ok = FALSE;
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* same */
        if (priv->kind == kind)
@@ -1356,9 +1356,9 @@ const gchar *
 gs_app_get_unique_id (GsApp *app)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_val_if_fail (GS_IS_APP (app), NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        return gs_app_get_unique_id_unlocked (app);
 }
 
@@ -1375,10 +1375,10 @@ void
 gs_app_set_unique_id (GsApp *app, const gchar *unique_id)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* check for sanity */
        if (!as_utils_data_id_valid (unique_id))
@@ -1421,10 +1421,10 @@ void
 gs_app_set_name (GsApp *app, GsAppQuality quality, const gchar *name)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* only save this if the data is sufficiently high quality */
        if (quality < priv->name_quality)
@@ -1466,9 +1466,9 @@ void
 gs_app_set_renamed_from (GsApp *app, const gchar *renamed_from)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_str (&priv->renamed_from, renamed_from);
 }
 
@@ -1503,9 +1503,9 @@ void
 gs_app_set_branch (GsApp *app, const gchar *branch)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (_g_set_str (&priv->branch, branch))
                priv->unique_id_valid = FALSE;
 }
@@ -1545,12 +1545,12 @@ gs_app_add_source (GsApp *app, const gchar *source)
        GsAppPrivate *priv = gs_app_get_instance_private (app);
        const gchar *tmp;
        guint i;
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (source != NULL);
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* check source doesn't already exist */
        for (i = 0; i < priv->sources->len; i++) {
@@ -1594,9 +1594,9 @@ void
 gs_app_set_sources (GsApp *app, GPtrArray *sources)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_ptr_array (&priv->sources, sources);
 }
 
@@ -1650,9 +1650,9 @@ void
 gs_app_clear_source_ids (GsApp *app)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_ptr_array_set_size (priv->source_ids, 0);
 }
 
@@ -1670,9 +1670,9 @@ void
 gs_app_set_source_ids (GsApp *app, GPtrArray *source_ids)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_ptr_array (&priv->source_ids, source_ids);
 }
 
@@ -1755,9 +1755,9 @@ void
 gs_app_set_project_group (GsApp *app, const gchar *project_group)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_str (&priv->project_group, project_group);
 }
 
@@ -1774,9 +1774,9 @@ void
 gs_app_set_developer_name (GsApp *app, const gchar *developer_name)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_str (&priv->developer_name, developer_name);
 }
 
@@ -1946,11 +1946,11 @@ void
 gs_app_add_icon (GsApp *app, GIcon *icon)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (G_IS_ICON (icon));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (priv->icons == NULL)
                priv->icons = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
@@ -1973,9 +1973,9 @@ void
 gs_app_remove_all_icons (GsApp *app)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (priv->icons != NULL)
                g_ptr_array_set_size (priv->icons, 0);
@@ -2053,9 +2053,9 @@ void
 gs_app_set_agreement (GsApp *app, const gchar *agreement)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_str (&priv->agreement, agreement);
 }
 
@@ -2092,9 +2092,9 @@ void
 gs_app_set_local_file (GsApp *app, GFile *local_file)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_set_object (&priv->local_file, local_file);
 }
 
@@ -2129,9 +2129,9 @@ void
 gs_app_set_content_rating (GsApp *app, AsContentRating *content_rating)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_set_object (&priv->content_rating, content_rating);
 }
 
@@ -2166,11 +2166,11 @@ void
 gs_app_set_runtime (GsApp *app, GsApp *runtime)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (GS_IS_APP (runtime));
        g_return_if_fail (app != runtime);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_set_object (&priv->runtime, runtime);
 }
 
@@ -2187,9 +2187,9 @@ void
 gs_app_set_action_screenshot (GsApp *app, AsScreenshot *action_screenshot)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_set_object (&priv->action_screenshot, action_screenshot);
 }
 
@@ -2353,10 +2353,10 @@ void
 gs_app_set_version (GsApp *app, const gchar *version)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (_g_set_str (&priv->version, version)) {
                gs_app_ui_versions_invalidate (app);
@@ -2396,10 +2396,10 @@ void
 gs_app_set_summary (GsApp *app, GsAppQuality quality, const gchar *summary)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* only save this if the data is sufficiently high quality */
        if (quality < priv->summary_quality)
@@ -2441,10 +2441,10 @@ void
 gs_app_set_description (GsApp *app, GsAppQuality quality, const gchar *description)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* only save this if the data is sufficiently high quality */
        if (quality < priv->description_quality)
@@ -2468,9 +2468,9 @@ const gchar *
 gs_app_get_url (GsApp *app, AsUrlKind kind)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_val_if_fail (GS_IS_APP (app), NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        return g_hash_table_lookup (priv->urls, as_url_kind_to_string (kind));
 }
 
@@ -2488,9 +2488,9 @@ void
 gs_app_set_url (GsApp *app, AsUrlKind kind, const gchar *url)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_hash_table_insert (priv->urls,
                             g_strdup (as_url_kind_to_string (kind)),
                             g_strdup (url));
@@ -2511,9 +2511,9 @@ const gchar *
 gs_app_get_url_missing (GsApp *app)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_val_if_fail (GS_IS_APP (app), NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        return priv->url_missing;
 }
 
@@ -2531,9 +2531,9 @@ void
 gs_app_set_url_missing (GsApp *app, const gchar *url)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (g_strcmp0 (priv->url_missing, url) == 0)
                return;
@@ -2576,9 +2576,9 @@ void
 gs_app_set_launchable (GsApp *app, AsLaunchableKind kind, const gchar *launchable)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_hash_table_insert (priv->launchables,
                             g_strdup (as_launchable_kind_to_string (kind)),
                             g_strdup (launchable));
@@ -2634,11 +2634,11 @@ void
 gs_app_set_license (GsApp *app, GsAppQuality quality, const gchar *license)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* only save this if the data is sufficiently high quality */
        if (quality <= priv->license_quality)
@@ -2683,9 +2683,9 @@ void
 gs_app_set_summary_missing (GsApp *app, const gchar *summary_missing)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_str (&priv->summary_missing, summary_missing);
 }
 
@@ -2772,9 +2772,9 @@ void
 gs_app_set_menu_path (GsApp *app, gchar **menu_path)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_strv (&priv->menu_path, menu_path);
 }
 
@@ -2809,10 +2809,10 @@ void
 gs_app_set_origin (GsApp *app, const gchar *origin)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* same */
        if (g_strcmp0 (origin, priv->origin) == 0)
@@ -2865,10 +2865,10 @@ void
 gs_app_set_origin_appstream (GsApp *app, const gchar *origin_appstream)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* same */
        if (g_strcmp0 (origin_appstream, priv->origin_appstream) == 0)
@@ -2915,14 +2915,14 @@ void
 gs_app_set_origin_hostname (GsApp *app, const gchar *origin_hostname)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_autoptr(SoupURI) uri = NULL;
        guint i;
        const gchar *prefixes[] = { "download.", "mirrors.", NULL };
 
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* same */
        if (g_strcmp0 (origin_hostname, priv->origin_hostname) == 0)
@@ -2961,12 +2961,12 @@ void
 gs_app_add_screenshot (GsApp *app, AsScreenshot *screenshot)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (AS_IS_SCREENSHOT (screenshot));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_ptr_array_add (priv->screenshots, g_object_ref (screenshot));
 }
 
@@ -3052,9 +3052,9 @@ void
 gs_app_set_update_version (GsApp *app, const gchar *update_version)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        gs_app_set_update_version_internal (app, update_version);
        gs_app_queue_notify (app, obj_props[PROP_VERSION]);
 }
@@ -3090,9 +3090,9 @@ void
 gs_app_set_update_details (GsApp *app, const gchar *update_details)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_str (&priv->update_details, update_details);
 }
 
@@ -3174,10 +3174,10 @@ void
 gs_app_set_management_plugin (GsApp *app, const gchar *management_plugin)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* plugins cannot adopt wildcard packages */
        if (gs_app_has_quirk (app, GS_APP_QUIRK_IS_WILDCARD)) {
@@ -3237,9 +3237,9 @@ void
 gs_app_set_rating (GsApp *app, gint rating)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (rating == priv->rating)
                return;
        priv->rating = rating;
@@ -3277,9 +3277,9 @@ void
 gs_app_set_review_ratings (GsApp *app, GArray *review_ratings)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_array (&priv->review_ratings, review_ratings);
 }
 
@@ -3314,10 +3314,10 @@ void
 gs_app_add_review (GsApp *app, AsReview *review)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (AS_IS_REVIEW (review));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_ptr_array_add (priv->reviews, g_object_ref (review));
 }
 
@@ -3334,9 +3334,9 @@ void
 gs_app_remove_review (GsApp *app, AsReview *review)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        g_ptr_array_remove (priv->reviews, review);
 }
 
@@ -3399,13 +3399,13 @@ gs_app_add_provided_item (GsApp *app, AsProvidedKind kind, const gchar *item)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
        AsProvided *prov;
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (item != NULL);
        g_return_if_fail (kind != AS_PROVIDED_KIND_UNKNOWN && kind < AS_PROVIDED_KIND_LAST);
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        prov = gs_app_get_provided_for_kind (app, kind);
        if (prov == NULL) {
                prov = as_provided_new ();
@@ -3608,12 +3608,12 @@ void
 gs_app_set_metadata_variant (GsApp *app, const gchar *key, GVariant *value)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        GVariant *found;
 
        g_return_if_fail (GS_IS_APP (app));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* if no value, then remove the key */
        if (value == NULL) {
@@ -3674,12 +3674,12 @@ void
 gs_app_add_addon (GsApp *app, GsApp *addon)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (GS_IS_APP (addon));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        gs_app_list_add (priv->addons, addon);
 }
 
@@ -3696,10 +3696,10 @@ void
 gs_app_remove_addon (GsApp *app, GsApp *addon)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (GS_IS_APP (addon));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        gs_app_list_remove (priv->addons, addon);
 }
 
@@ -3735,12 +3735,12 @@ gs_app_add_related (GsApp *app, GsApp *app2)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
        GsAppPrivate *priv2 = gs_app_get_instance_private (app2);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (GS_IS_APP (app2));
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        /* if the app is updatable-live and any related app is not then
         * degrade to the offline state */
@@ -3782,10 +3782,10 @@ void
 gs_app_add_history (GsApp *app, GsApp *app2)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (GS_IS_APP (app2));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        gs_app_list_add (priv->history, app2);
 }
 
@@ -3967,10 +3967,10 @@ void
 gs_app_set_categories (GsApp *app, GPtrArray *categories)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (categories != NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_ptr_array (&priv->categories, categories);
 }
 
@@ -3987,10 +3987,10 @@ void
 gs_app_add_category (GsApp *app, const gchar *category)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (category != NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (gs_app_has_category (app, category))
                return;
        g_ptr_array_add (priv->categories, g_strdup (category));
@@ -4013,11 +4013,11 @@ gs_app_remove_category (GsApp *app, const gchar *category)
        GsAppPrivate *priv = gs_app_get_instance_private (app);
        const gchar *tmp;
        guint i;
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_val_if_fail (GS_IS_APP (app), FALSE);
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        for (i = 0; i < priv->categories->len; i++) {
                tmp = g_ptr_array_index (priv->categories, i);
@@ -4207,10 +4207,10 @@ void
 gs_app_set_key_colors (GsApp *app, GArray *key_colors)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (key_colors != NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        if (_g_set_array (&priv->key_colors, key_colors))
                gs_app_queue_notify (app, obj_props[PROP_KEY_COLORS]);
 }
@@ -4440,14 +4440,14 @@ void
 gs_app_add_quirk (GsApp *app, GsAppQuirk quirk)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
        /* same */
        if ((priv->quirk & quirk) > 0)
                return;
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        priv->quirk |= quirk;
        gs_app_queue_notify (app, obj_props[PROP_QUIRK]);
 }
@@ -4465,14 +4465,14 @@ void
 gs_app_remove_quirk (GsApp *app, GsAppQuirk quirk)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
 
        /* same */
        if ((priv->quirk & quirk) == 0)
                return;
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        priv->quirk &= ~quirk;
        gs_app_queue_notify (app, obj_props[PROP_QUIRK]);
 }
@@ -4574,11 +4574,11 @@ gs_app_get_cancellable (GsApp *app)
 {
        g_autoptr(GCancellable) cancellable = NULL;
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_val_if_fail (GS_IS_APP (app), NULL);
 
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (priv->cancellable == NULL || g_cancellable_is_cancelled (priv->cancellable)) {
                cancellable = g_cancellable_new ();
@@ -4599,9 +4599,9 @@ GsPluginAction
 gs_app_get_pending_action (GsApp *app)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_val_if_fail (GS_IS_APP (app), GS_PLUGIN_ACTION_UNKNOWN);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        return priv->pending_action;
 }
 
@@ -4617,9 +4617,9 @@ gs_app_set_pending_action (GsApp *app,
                           GsPluginAction action)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        gs_app_set_pending_action_internal (app, action);
 }
 
@@ -4791,7 +4791,7 @@ gs_app_finalize (GObject *object)
        GsApp *app = GS_APP (object);
        GsAppPrivate *priv = gs_app_get_instance_private (app);
 
-       g_mutex_clear (&priv->mutex);
+       g_rec_mutex_clear (&priv->mutex);
        g_free (priv->id);
        g_free (priv->unique_id);
        g_free (priv->branch);
@@ -5023,7 +5023,7 @@ gs_app_init (GsApp *app)
                                                   g_free,
                                                   g_free);
        priv->allow_cancel = TRUE;
-       g_mutex_init (&priv->mutex);
+       g_rec_mutex_init (&priv->mutex);
 }
 
 /**
@@ -5135,7 +5135,7 @@ gchar *
 gs_app_get_origin_ui (GsApp *app)
 {
        GsAppPrivate *priv;
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_autoptr(GsOsRelease) os_release = NULL;
        g_autofree gchar *packaging_format = NULL;
        const gchar *origin_str = NULL;
@@ -5150,7 +5150,7 @@ gs_app_get_origin_ui (GsApp *app)
        }
 
        priv = gs_app_get_instance_private (app);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (!origin_str) {
                origin_str = priv->origin_ui;
@@ -5185,12 +5185,12 @@ gs_app_set_origin_ui (GsApp *app,
                      const gchar *origin_ui)
 {
        GsAppPrivate *priv;
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
 
        g_return_if_fail (GS_IS_APP (app));
 
        priv = gs_app_get_instance_private (app);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
 
        if (origin_ui && !*origin_ui)
                origin_ui = NULL;
@@ -5351,9 +5351,43 @@ void
 gs_app_set_version_history (GsApp *app, GPtrArray *version_history)
 {
        GsAppPrivate *priv = gs_app_get_instance_private (app);
-       g_autoptr(GMutexLocker) locker = NULL;
+       g_autoptr(GRecMutexLocker) locker = NULL;
        g_return_if_fail (GS_IS_APP (app));
        g_return_if_fail (version_history != NULL);
-       locker = g_mutex_locker_new (&priv->mutex);
+       locker = g_rec_mutex_locker_new (&priv->mutex);
        _g_set_ptr_array (&priv->version_history, version_history);
 }
+
+/**
+ * gs_app_lock:
+ * @app: a #GsApp
+ *
+ * Acquire the @app property lock. Release the lock with gs_app_unlock().
+ *
+ * Since: 41
+ **/
+void
+gs_app_lock (GsApp *app)
+{
+       GsAppPrivate *priv;
+       g_return_if_fail (GS_IS_APP (app));
+       priv = gs_app_get_instance_private (app);
+       g_rec_mutex_lock (&priv->mutex);
+}
+
+/**
+ * gs_app_unlock:
+ * @app: a #GsApp
+ *
+ * Release the @app property lock, previously acquired with gs_app_lock().
+ *
+ * Since: 41
+ **/
+void
+gs_app_unlock (GsApp *app)
+{
+       GsAppPrivate *priv;
+       g_return_if_fail (GS_IS_APP (app));
+       priv = gs_app_get_instance_private (app);
+       g_rec_mutex_unlock (&priv->mutex);
+}
diff --git a/lib/gs-app.h b/lib/gs-app.h
index 3136b639f..eb1544f7c 100644
--- a/lib/gs-app.h
+++ b/lib/gs-app.h
@@ -471,5 +471,7 @@ void                 gs_app_set_update_permissions  (GsApp          *app,
 GPtrArray      *gs_app_get_version_history     (GsApp          *app);
 void            gs_app_set_version_history     (GsApp          *app,
                                                 GPtrArray      *version_history);
+void           gs_app_lock                     (GsApp *app);
+void           gs_app_unlock                   (GsApp *app);
 
 G_END_DECLS
diff --git a/plugins/core/gs-plugin-icons.c b/plugins/core/gs-plugin-icons.c
index 34bf52442..a5f594c2b 100644
--- a/plugins/core/gs-plugin-icons.c
+++ b/plugins/core/gs-plugin-icons.c
@@ -59,6 +59,8 @@ refine_app (GsPlugin             *plugin,
        /* Currently a 160px icon is needed for #GsFeatureTile, at most. */
        maximum_icon_size = 160 * gs_plugin_get_scale (plugin);
 
+       gs_app_lock (app);
+
        /* process all icons */
        icons = gs_app_get_icons (app);
        for (i = 0; icons != NULL && i < icons->len; i++) {
@@ -81,6 +83,8 @@ refine_app (GsPlugin             *plugin,
                }
        }
 
+       gs_app_unlock (app);
+
        return TRUE;
 }
 


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