[gnome-software/1196-race-condition-under-gs_plugin_icons_load_cached] GsApp: Add thread safety around remote icons download




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

    GsApp: Add thread safety around remote icons download
    
    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                   | 52 ++++++++++++++++++++++++++++++++++++++++++
 lib/gs-app.h                   |  5 ++++
 plugins/core/gs-plugin-icons.c | 24 +------------------
 3 files changed, 58 insertions(+), 23 deletions(-)
---
diff --git a/lib/gs-app.c b/lib/gs-app.c
index 12ee9a292..e44d3d49d 100644
--- a/lib/gs-app.c
+++ b/lib/gs-app.c
@@ -48,6 +48,7 @@
 #include "gs-key-colors.h"
 #include "gs-os-release.h"
 #include "gs-plugin.h"
+#include "gs-remote-icon.h"
 #include "gs-utils.h"
 
 typedef struct
@@ -5357,3 +5358,54 @@ gs_app_set_version_history (GsApp *app, GPtrArray *version_history)
        locker = g_mutex_locker_new (&priv->mutex);
        _g_set_ptr_array (&priv->version_history, version_history);
 }
+
+/**
+ * gs_app_ensure_icons_downloaded:
+ * @app: a #GsApp
+ * @soup_session: a #SoupSession
+ * @maximum_icon_size: maximum icon size
+ * @cancellable: optional #GCancellable object
+ *
+ * Ensure all remote icons in the @app's icons are locally cached.
+ *
+ * Since: 41
+ **/
+void
+gs_app_ensure_icons_downloaded (GsApp *app,
+                               SoupSession *soup_session,
+                               guint maximum_icon_size,
+                               GCancellable *cancellable)
+{
+       GsAppPrivate *priv;
+       g_autoptr(GMutexLocker) locker = NULL;
+       GPtrArray *icons;
+       guint i;
+
+       g_return_if_fail (GS_IS_APP (app));
+
+       priv = gs_app_get_instance_private (app);
+       locker = g_mutex_locker_new (&priv->mutex);
+
+       /* process all icons */
+       icons = priv->icons;
+
+       for (i = 0; icons != NULL && i < icons->len; i++) {
+               GIcon *icon = g_ptr_array_index (icons, i);
+               g_autoptr(GError) error_local = NULL;
+
+               /* Only remote icons need to be cached. */
+               if (!GS_IS_REMOTE_ICON (icon))
+                       continue;
+
+               if (!gs_remote_icon_ensure_cached (GS_REMOTE_ICON (icon),
+                                                  soup_session,
+                                                  maximum_icon_size,
+                                                  cancellable,
+                                                  &error_local)) {
+                       /* we failed, but keep going */
+                       g_debug ("failed to cache icon for %s: %s",
+                                gs_app_get_id (app),
+                                error_local->message);
+               }
+       }
+}
diff --git a/lib/gs-app.h b/lib/gs-app.h
index 3136b639f..2961da4b4 100644
--- a/lib/gs-app.h
+++ b/lib/gs-app.h
@@ -12,6 +12,7 @@
 #include <glib-object.h>
 #include <gdk/gdk.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
+#include <libsoup/soup.h>
 #include <appstream.h>
 
 G_BEGIN_DECLS
@@ -471,5 +472,9 @@ 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_ensure_icons_downloaded  (GsApp          *app,
+                                                SoupSession    *soup_session,
+                                                guint           maximum_icon_size,
+                                                GCancellable   *cancellable);
 
 G_END_DECLS
diff --git a/plugins/core/gs-plugin-icons.c b/plugins/core/gs-plugin-icons.c
index 34bf52442..918c7d1e9 100644
--- a/plugins/core/gs-plugin-icons.c
+++ b/plugins/core/gs-plugin-icons.c
@@ -45,8 +45,6 @@ refine_app (GsPlugin             *plugin,
            GCancellable         *cancellable,
            GError              **error)
 {
-       GPtrArray *icons;
-       guint i;
        SoupSession *soup_session;
        guint maximum_icon_size;
 
@@ -59,27 +57,7 @@ refine_app (GsPlugin             *plugin,
        /* Currently a 160px icon is needed for #GsFeatureTile, at most. */
        maximum_icon_size = 160 * gs_plugin_get_scale (plugin);
 
-       /* process all icons */
-       icons = gs_app_get_icons (app);
-       for (i = 0; icons != NULL && i < icons->len; i++) {
-               GIcon *icon = g_ptr_array_index (icons, i);
-               g_autoptr(GError) error_local = NULL;
-
-               /* Only remote icons need to be cached. */
-               if (!GS_IS_REMOTE_ICON (icon))
-                       continue;
-
-               if (!gs_remote_icon_ensure_cached (GS_REMOTE_ICON (icon),
-                                                  soup_session,
-                                                  maximum_icon_size,
-                                                  cancellable,
-                                                  &error_local)) {
-                       /* we failed, but keep going */
-                       g_debug ("failed to cache icon for %s: %s",
-                                gs_app_get_id (app),
-                                error_local->message);
-               }
-       }
+       gs_app_ensure_icons_downloaded (app, soup_session, maximum_icon_size, cancellable);
 
        return TRUE;
 }


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