[glib: 1/5] giomodule: Don’t mandatorily cache GIOModule implementations




commit 22b924b64acaefed51a103f2f4a5ad09048183ed
Author: Philip Withnall <withnall endlessm com>
Date:   Wed Jan 23 16:07:51 2019 +0000

    giomodule: Don’t mandatorily cache GIOModule implementations
    
    While all of the current callers of _g_io_module_get_default() want to
    cache the returned GObject for the lifetime of the process, that doesn’t
    necessarily have to be the case, so let callers make that decision on a
    case-by-case basis.
    
    Signed-off-by: Philip Withnall <withnall endlessm com>

 gio/giomodule.c        | 55 ++++++++++++++++++++++++++++++++++++--------------
 gio/gnetworkmonitor.c  | 16 ++++++++++++---
 gio/gproxyresolver.c   | 17 +++++++++++++---
 gio/gsettingsbackend.c | 22 +++++++++++++++-----
 gio/gtlsbackend.c      | 16 +++++++++++++--
 gio/gvfs.c             | 18 ++++++++++++++---
 glib.supp              |  8 ++++++++
 7 files changed, 121 insertions(+), 31 deletions(-)
---
diff --git a/gio/giomodule.c b/gio/giomodule.c
index e27f1ab76..2652f66c3 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -884,6 +884,13 @@ try_implementation (const char           *extension_point,
     }
 }
 
+static void
+weak_ref_free (GWeakRef *weak_ref)
+{
+  g_weak_ref_clear (weak_ref);
+  g_free (weak_ref);
+}
+
 /**
  * _g_io_module_get_default:
  * @extension_point: the name of an extension point
@@ -905,10 +912,11 @@ try_implementation (const char           *extension_point,
  * be called on each candidate implementation after construction, to
  * check if it is actually usable or not.
  *
- * The result is cached after it is generated the first time, and
+ * The result is cached after it is generated the first time (but the cache does
+ * not keep a strong reference to the object), and
  * the function is thread-safe.
  *
- * Returns: (transfer none): an object implementing
+ * Returns: (transfer full) (nullable): an object implementing
  *     @extension_point, or %NULL if there are no usable
  *     implementations.
  */
@@ -923,25 +931,33 @@ _g_io_module_get_default (const gchar         *extension_point,
   GList *l;
   GIOExtensionPoint *ep;
   GIOExtension *extension = NULL, *preferred;
-  gpointer impl;
+  gpointer impl, value;
+  GWeakRef *impl_weak_ref = NULL;
 
   g_rec_mutex_lock (&default_modules_lock);
   if (default_modules)
     {
-      gpointer key;
-
       if (g_hash_table_lookup_extended (default_modules, extension_point,
-                                       &key, &impl))
-       {
+                                        NULL, &value))
+        {
           /* Don’t debug here, since we’re returning a cached object which was
            * already printed earlier. */
-         g_rec_mutex_unlock (&default_modules_lock);
-         return impl;
-       }
+          impl_weak_ref = value;
+          impl = g_weak_ref_get (impl_weak_ref);
+
+          /* If the object has been finalised (impl == NULL), fall through and
+           * instantiate a new one. */
+          if (impl != NULL)
+            {
+              g_rec_mutex_unlock (&default_modules_lock);
+              return g_steal_pointer (&impl);
+            }
+        }
     }
   else
     {
-      default_modules = g_hash_table_new (g_str_hash, g_str_equal);
+      default_modules = g_hash_table_new_full (g_str_hash, g_str_equal,
+                                               g_free, (GDestroyNotify) weak_ref_free);
     }
 
   _g_io_modules_ensure_loaded ();
@@ -993,9 +1009,18 @@ _g_io_module_get_default (const gchar         *extension_point,
   impl = NULL;
 
  done:
-  g_hash_table_insert (default_modules,
-                      g_strdup (extension_point),
-                      impl ? g_object_ref (impl) : NULL);
+  if (impl_weak_ref == NULL)
+    {
+      impl_weak_ref = g_new0 (GWeakRef, 1);
+      g_weak_ref_init (impl_weak_ref, impl);
+      g_hash_table_insert (default_modules, g_strdup (extension_point),
+                           g_steal_pointer (&impl_weak_ref));
+    }
+  else
+    {
+      g_weak_ref_set (impl_weak_ref, impl);
+    }
+
   g_rec_mutex_unlock (&default_modules_lock);
 
   if (impl != NULL)
@@ -1009,7 +1034,7 @@ _g_io_module_get_default (const gchar         *extension_point,
     g_debug ("%s: Failed to find default implementation for ‘%s’",
              G_STRFUNC, extension_point);
 
-  return impl;
+  return g_steal_pointer (&impl);
 }
 
 G_LOCK_DEFINE_STATIC (registered_extensions);
diff --git a/gio/gnetworkmonitor.c b/gio/gnetworkmonitor.c
index 8027e4663..d32c60154 100644
--- a/gio/gnetworkmonitor.c
+++ b/gio/gnetworkmonitor.c
@@ -77,6 +77,7 @@ enum {
 };
 
 static guint signals[LAST_SIGNAL] = { 0 };
+static GNetworkMonitor *network_monitor_default_singleton = NULL;  /* (owned) (atomic) */
 
 /**
  * g_network_monitor_get_default:
@@ -91,9 +92,18 @@ static guint signals[LAST_SIGNAL] = { 0 };
 GNetworkMonitor *
 g_network_monitor_get_default (void)
 {
-  return _g_io_module_get_default (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
-                                   "GIO_USE_NETWORK_MONITOR",
-                                   NULL);
+  if (g_once_init_enter (&network_monitor_default_singleton))
+    {
+      GNetworkMonitor *singleton;
+
+      singleton = _g_io_module_get_default (G_NETWORK_MONITOR_EXTENSION_POINT_NAME,
+                                            "GIO_USE_NETWORK_MONITOR",
+                                            NULL);
+
+      g_once_init_leave (&network_monitor_default_singleton, singleton);
+    }
+
+  return network_monitor_default_singleton;
 }
 
 /**
diff --git a/gio/gproxyresolver.c b/gio/gproxyresolver.c
index c83347b52..0df51eb60 100644
--- a/gio/gproxyresolver.c
+++ b/gio/gproxyresolver.c
@@ -67,6 +67,8 @@ g_proxy_resolver_default_init (GProxyResolverInterface *iface)
 {
 }
 
+static GProxyResolver *proxy_resolver_default_singleton = NULL;  /* (owned) (atomic) */
+
 /**
  * g_proxy_resolver_get_default:
  *
@@ -80,9 +82,18 @@ g_proxy_resolver_default_init (GProxyResolverInterface *iface)
 GProxyResolver *
 g_proxy_resolver_get_default (void)
 {
-  return _g_io_module_get_default (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
-                                  "GIO_USE_PROXY_RESOLVER",
-                                  (GIOModuleVerifyFunc)g_proxy_resolver_is_supported);
+  if (g_once_init_enter (&proxy_resolver_default_singleton))
+    {
+      GProxyResolver *singleton;
+
+      singleton = _g_io_module_get_default (G_PROXY_RESOLVER_EXTENSION_POINT_NAME,
+                                            "GIO_USE_PROXY_RESOLVER",
+                                            (GIOModuleVerifyFunc) g_proxy_resolver_is_supported);
+
+      g_once_init_leave (&proxy_resolver_default_singleton, singleton);
+    }
+
+  return proxy_resolver_default_singleton;
 }
 
 /**
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index dcc7c3714..b124bc7ec 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -992,6 +992,12 @@ g_settings_backend_verify (gpointer impl)
   return TRUE;
 }
 
+/* We need to cache the default #GSettingsBackend for the entire process
+ * lifetime, especially if the backend is #GMemorySettingsBackend: it needs to
+ * keep the in-memory settings around even while there are no #GSettings
+ * instances alive. */
+static GSettingsBackend *settings_backend_default_singleton = NULL;  /* (owned) (atomic) */
+
 /**
  * g_settings_backend_get_default:
  *
@@ -1010,12 +1016,18 @@ g_settings_backend_verify (gpointer impl)
 GSettingsBackend *
 g_settings_backend_get_default (void)
 {
-  GSettingsBackend *backend;
+  if (g_once_init_enter (&settings_backend_default_singleton))
+    {
+      GSettingsBackend *singleton;
+
+      singleton = _g_io_module_get_default (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
+                                            "GSETTINGS_BACKEND",
+                                            g_settings_backend_verify);
+
+      g_once_init_leave (&settings_backend_default_singleton, singleton);
+    }
 
-  backend = _g_io_module_get_default (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME,
-                                     "GSETTINGS_BACKEND",
-                                     g_settings_backend_verify);
-  return g_object_ref (backend);
+  return g_object_ref (settings_backend_default_singleton);
 }
 
 /*< private >
diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c
index 6d948adf1..25569aad7 100644
--- a/gio/gtlsbackend.c
+++ b/gio/gtlsbackend.c
@@ -93,6 +93,8 @@ g_tls_backend_default_init (GTlsBackendInterface *iface)
 {
 }
 
+static GTlsBackend *tls_backend_default_singleton = NULL;  /* (owned) (atomic) */
+
 /**
  * g_tls_backend_get_default:
  *
@@ -106,8 +108,18 @@ g_tls_backend_default_init (GTlsBackendInterface *iface)
 GTlsBackend *
 g_tls_backend_get_default (void)
 {
-  return _g_io_module_get_default (G_TLS_BACKEND_EXTENSION_POINT_NAME,
-                                  "GIO_USE_TLS", NULL);
+  if (g_once_init_enter (&tls_backend_default_singleton))
+    {
+      GTlsBackend *singleton;
+
+      singleton = _g_io_module_get_default (G_TLS_BACKEND_EXTENSION_POINT_NAME,
+                                            "GIO_USE_TLS",
+                                            NULL);
+
+      g_once_init_leave (&tls_backend_default_singleton, singleton);
+    }
+
+  return tls_backend_default_singleton;
 }
 
 /**
diff --git a/gio/gvfs.c b/gio/gvfs.c
index f178d7a41..6e2dcf060 100644
--- a/gio/gvfs.c
+++ b/gio/gvfs.c
@@ -337,6 +337,8 @@ g_vfs_parse_name (GVfs       *vfs,
   return (* class->parse_name) (vfs, parse_name);
 }
 
+static GVfs *vfs_default_singleton = NULL;  /* (owned) (atomic) */
+
 /**
  * g_vfs_get_default:
  *
@@ -350,9 +352,19 @@ g_vfs_get_default (void)
 {
   if (GLIB_PRIVATE_CALL (g_check_setuid) ())
     return g_vfs_get_local ();
-  return _g_io_module_get_default (G_VFS_EXTENSION_POINT_NAME,
-                                   "GIO_USE_VFS",
-                                   (GIOModuleVerifyFunc)g_vfs_is_active);
+
+  if (g_once_init_enter (&vfs_default_singleton))
+    {
+      GVfs *singleton;
+
+      singleton = _g_io_module_get_default (G_VFS_EXTENSION_POINT_NAME,
+                                            "GIO_USE_VFS",
+                                            (GIOModuleVerifyFunc) g_vfs_is_active);
+
+      g_once_init_leave (&vfs_default_singleton, singleton);
+    }
+
+  return vfs_default_singleton;
 }
 
 /**
diff --git a/glib.supp b/glib.supp
index 06c5f542f..c33de33bb 100644
--- a/glib.supp
+++ b/glib.supp
@@ -421,6 +421,14 @@
        fun:_g_io_module_get_default*
 }
 
+{
+       g-io-module-default-singleton-weak-ref
+       Memcheck:Leak
+       fun:calloc
+       ...
+       fun:_g_io_module_get_default
+}
+
 {
        g-get-language-names-malloc
        Memcheck:Leak


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