From 1481b7bca3c24149a2970758bc8762e1318f361e Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 21 Jun 2011 18:21:27 -0400 Subject: [PATCH] Add _g_io_module_get_default(), use to simplify other *_get_default()s Add _g_io_module_get_default(), which implements the figure-out-the-best-available-module-that-is-actually-usable logic, and use that to simplify g_proxy_resolver_get_default(), g_settings_backend_get_default(), g_tls_backend_get_default(), and g_vfs_get_default(). https://bugzilla.gnome.org/show_bug.cgi?id=620932 --- gio/giomodule-priv.h | 5 ++ gio/giomodule.c | 127 +++++++++++++++++++++++++++++++++++++++++ gio/gproxyresolver.c | 52 +---------------- gio/gsettingsbackend.c | 63 +++++++------------- gio/gtlsbackend.c | 35 +----------- gio/gvfs.c | 53 +---------------- 6 files changed, 161 insertions(+), 174 deletions(-) diff --git a/gio/giomodule-priv.h b/gio/giomodule-priv.h index a4677b035..b25d30574 100644 --- a/gio/giomodule-priv.h +++ b/gio/giomodule-priv.h @@ -30,6 +30,11 @@ G_BEGIN_DECLS void _g_io_modules_ensure_extension_points_registered (void); void _g_io_modules_ensure_loaded (void); +typedef gboolean (*GIOModuleVerifyFunc) (gpointer); +gpointer _g_io_module_get_default (const gchar *extension_point, + const gchar *envvar, + GIOModuleVerifyFunc verify_func); + G_END_DECLS #endif /* __G_IO_MODULE_PRIV_H__ */ diff --git a/gio/giomodule.c b/gio/giomodule.c index 2763a98a8..61638c08f 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -630,6 +630,133 @@ g_io_modules_load_all_in_directory (const char *dirname) return g_io_modules_load_all_in_directory_with_scope (dirname, NULL); } +G_LOCK_DEFINE_STATIC (default_modules); +GHashTable *default_modules; + +static gpointer +try_implementation (GIOExtension *extension, + GIOModuleVerifyFunc verify_func) +{ + GType type = g_io_extension_get_type (extension); + gpointer impl; + + if (g_type_is_a (type, G_TYPE_INITABLE)) + return g_initable_new (type, NULL, NULL, NULL); + else + { + impl = g_object_new (type, NULL); + if (!verify_func || verify_func (impl)) + return impl; + + g_object_unref (impl); + return NULL; + } +} + +/** + * _g_io_module_get_default: + * @extension_point: the name of an extension point + * @envvar: (allow-none): the name of an environment variable to + * override the default implementation. + * @verify_func: (allow-none): a function to call to verify that + * a given implementation is usable in the current environment. + * + * Retrieves the default object implementing @extension_point. + * + * If @envvar is not %NULL, and the environment variable with that + * name is set, then the implementation it specifies will be tried + * first. After that, or if @envvar is not set, all other + * implementations will be tried in order of decreasing priority. + * + * If an extension point implementation implements #GInitable, then + * that implementation will only be used if it initializes + * successfully. Otherwise, if @verify_func is not %NULL, then it will + * 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 function is thread-safe. + * + * Return value: (transfer none): an object implementing + * @extension_point, or %NULL if there are no usable + * implementations. + */ +gpointer +_g_io_module_get_default (const gchar *extension_point, + const gchar *envvar, + GIOModuleVerifyFunc verify_func) +{ + const char *use_this; + GList *l; + GIOExtensionPoint *ep; + GIOExtension *extension, *preferred; + gpointer impl; + + G_LOCK (default_modules); + if (default_modules) + { + gpointer key; + + if (g_hash_table_lookup_extended (default_modules, extension_point, + &key, &impl)) + { + G_UNLOCK (default_modules); + return impl; + } + } + else + { + default_modules = g_hash_table_new (g_str_hash, g_str_equal); + } + + _g_io_modules_ensure_loaded (); + ep = g_io_extension_point_lookup (extension_point); + + if (!ep) + { + g_warn_if_reached (); + G_UNLOCK (default_modules); + return NULL; + } + + use_this = envvar ? g_getenv (envvar) : NULL; + if (use_this) + { + preferred = g_io_extension_point_get_extension_by_name (ep, use_this); + if (preferred) + { + impl = try_implementation (preferred, verify_func); + if (impl) + goto done; + } + else + g_warning ("Can't find module '%s' specified in %s", use_this, envvar); + } + else + preferred = NULL; + + for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next) + { + extension = l->data; + if (extension == preferred) + continue; + + impl = try_implementation (extension, verify_func); + if (impl) + goto done; + } + + impl = NULL; + + done: + g_hash_table_insert (default_modules, + g_strdup (extension_point), + impl ? g_object_ref (impl) : NULL); + G_UNLOCK (default_modules); + + return impl; +} + G_LOCK_DEFINE_STATIC (registered_extensions); G_LOCK_DEFINE_STATIC (loaded_dirs); diff --git a/gio/gproxyresolver.c b/gio/gproxyresolver.c index 2bc97338a..db2e47556 100644 --- a/gio/gproxyresolver.c +++ b/gio/gproxyresolver.c @@ -50,52 +50,6 @@ g_proxy_resolver_default_init (GProxyResolverInterface *iface) { } -static gpointer -get_default_proxy_resolver (gpointer arg) -{ - const gchar *use_this; - GProxyResolver *resolver; - GList *l; - GIOExtensionPoint *ep; - GIOExtension *extension; - - - use_this = g_getenv ("GIO_USE_PROXY_RESOLVER"); - - /* Ensure proxy-resolver modules loaded */ - _g_io_modules_ensure_loaded (); - - ep = g_io_extension_point_lookup (G_PROXY_RESOLVER_EXTENSION_POINT_NAME); - - if (use_this) - { - extension = g_io_extension_point_get_extension_by_name (ep, use_this); - if (extension) - { - resolver = g_object_new (g_io_extension_get_type (extension), NULL); - - if (g_proxy_resolver_is_supported (resolver)) - return resolver; - - g_object_unref (resolver); - } - } - - for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next) - { - extension = l->data; - - resolver = g_object_new (g_io_extension_get_type (extension), NULL); - - if (g_proxy_resolver_is_supported (resolver)) - return resolver; - - g_object_unref (resolver); - } - - return NULL; -} - /** * g_proxy_resolver_get_default: * @@ -108,9 +62,9 @@ get_default_proxy_resolver (gpointer arg) GProxyResolver * g_proxy_resolver_get_default (void) { - static GOnce once_init = G_ONCE_INIT; - - return g_once (&once_init, get_default_proxy_resolver, NULL); + return _g_io_module_get_default (G_PROXY_RESOLVER_EXTENSION_POINT_NAME, + "GIO_USE_PROXY_RESOLVER", + (GIOModuleVerifyFunc)g_proxy_resolver_is_supported); } /** diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c index f824b93e6..a1702412d 100644 --- a/gio/gsettingsbackend.c +++ b/gio/gsettingsbackend.c @@ -935,6 +935,22 @@ g_settings_backend_create_tree (void) g_free, g_settings_backend_variant_unref0); } +static gboolean +g_settings_backend_verify (gpointer impl) +{ + GSettingsBackend *backend = impl; + + if (strcmp (G_OBJECT_TYPE_NAME (backend), "GMemorySettingsBackend") == 0 && + g_strcmp0 (g_getenv ("GSETTINGS_BACKEND"), "memory") != 0) + { + g_message ("Using the 'memory' GSettings backend. Your settings " + "will not be saved or shared with other applications."); + } + + g_settings_has_backend = TRUE; + return TRUE; +} + /** * g_settings_backend_get_default: * @returns: (transfer full): the default #GSettingsBackend @@ -950,49 +966,12 @@ g_settings_backend_create_tree (void) GSettingsBackend * g_settings_backend_get_default (void) { - static gsize backend; + GSettingsBackend *backend; - if (g_once_init_enter (&backend)) - { - GSettingsBackend *instance; - GIOExtensionPoint *point; - GIOExtension *extension; - GType extension_type; - GList *extensions; - const gchar *env; - - _g_io_modules_ensure_loaded (); - - point = g_io_extension_point_lookup (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME); - extension = NULL; - - if ((env = getenv ("GSETTINGS_BACKEND"))) - { - extension = g_io_extension_point_get_extension_by_name (point, env); - - if (extension == NULL) - g_warning ("Can't find GSettings backend '%s' given in " - "GSETTINGS_BACKEND environment variable", env); - } - - if (extension == NULL) - { - extensions = g_io_extension_point_get_extensions (point); - extension = extensions->data; - - if (strcmp (g_io_extension_get_name (extension), "memory") == 0) - g_message ("Using the 'memory' GSettings backend. Your settings " - "will not be saved or shared with other applications."); - } - - extension_type = g_io_extension_get_type (extension); - instance = g_object_new (extension_type, NULL); - g_settings_has_backend = TRUE; - - g_once_init_leave (&backend, (gsize) instance); - } - - return g_object_ref ((void *) backend); + backend = _g_io_module_get_default (G_SETTINGS_BACKEND_EXTENSION_POINT_NAME, + "GSETTINGS_BACKEND", + g_settings_backend_verify); + return g_object_ref (backend); } /*< private > diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c index 13fff178a..2d6913ab4 100644 --- a/gio/gtlsbackend.c +++ b/gio/gtlsbackend.c @@ -80,36 +80,6 @@ g_tls_backend_default_init (GTlsBackendInterface *iface) { } -static gpointer -get_default_tls_backend (gpointer arg) -{ - const char *use_this; - GList *extensions; - GIOExtensionPoint *ep; - GIOExtension *extension; - - _g_io_modules_ensure_loaded (); - - ep = g_io_extension_point_lookup (G_TLS_BACKEND_EXTENSION_POINT_NAME); - - use_this = g_getenv ("GIO_USE_TLS"); - if (use_this) - { - extension = g_io_extension_point_get_extension_by_name (ep, use_this); - if (extension) - return g_object_new (g_io_extension_get_type (extension), NULL); - } - - extensions = g_io_extension_point_get_extensions (ep); - if (extensions) - { - extension = extensions->data; - return g_object_new (g_io_extension_get_type (extension), NULL); - } - - return NULL; -} - /** * g_tls_backend_get_default: * @@ -122,9 +92,8 @@ get_default_tls_backend (gpointer arg) GTlsBackend * g_tls_backend_get_default (void) { - static GOnce once_init = G_ONCE_INIT; - - return g_once (&once_init, get_default_tls_backend, NULL); + return _g_io_module_get_default (G_TLS_BACKEND_EXTENSION_POINT_NAME, + "GIO_USE_TLS", NULL); } /** diff --git a/gio/gvfs.c b/gio/gvfs.c index 697c69bb5..cbe7f2f33 100644 --- a/gio/gvfs.c +++ b/gio/gvfs.c @@ -170,53 +170,6 @@ g_vfs_parse_name (GVfs *vfs, return (* class->parse_name) (vfs, parse_name); } -static gpointer -get_default_vfs (gpointer arg) -{ - const char *use_this; - GVfs *vfs; - GList *l; - GIOExtensionPoint *ep; - GIOExtension *extension; - - - use_this = g_getenv ("GIO_USE_VFS"); - - /* Ensure vfs in modules loaded */ - _g_io_modules_ensure_loaded (); - - ep = g_io_extension_point_lookup (G_VFS_EXTENSION_POINT_NAME); - - if (use_this) - { - extension = g_io_extension_point_get_extension_by_name (ep, use_this); - if (extension) - { - vfs = g_object_new (g_io_extension_get_type (extension), NULL); - - if (g_vfs_is_active (vfs)) - return vfs; - - g_object_unref (vfs); - } - } - - for (l = g_io_extension_point_get_extensions (ep); l != NULL; l = l->next) - { - extension = l->data; - - vfs = g_object_new (g_io_extension_get_type (extension), NULL); - - if (g_vfs_is_active (vfs)) - return vfs; - - g_object_unref (vfs); - } - - - return NULL; -} - /** * g_vfs_get_default: * @@ -227,9 +180,9 @@ get_default_vfs (gpointer arg) GVfs * g_vfs_get_default (void) { - static GOnce once_init = G_ONCE_INIT; - - return g_once (&once_init, get_default_vfs, NULL); + return _g_io_module_get_default (G_VFS_EXTENSION_POINT_NAME, + "GIO_USE_VFS", + (GIOModuleVerifyFunc)g_vfs_is_active); } /**