[glib] giomodule: When loading GIO_EXTRA_MODULES skip duplicates



commit d789e78dff26d787b5a55c4b7f5858a7219d5a96
Author: Stef Walter <stefw collabora co uk>
Date:   Fri Aug 26 15:27:19 2011 +0200

    giomodule: When loading GIO_EXTRA_MODULES skip duplicates
    
     * Load modules from paths listed in GIO_EXTRA_MODULES environment
       variable first.
     * Ignore duplicate modules based on module basename.
     * Add the concept of GIOModuleScope which allows other callers to
       skip duplicate loaded modules, or block specific modules based on
       basename.
     * Document behavior.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=656914

 docs/reference/gio/gio-sections.txt |    5 +
 gio/gio.symbols                     |    5 +
 gio/gioenums.h                      |   16 +++
 gio/giomodule.c                     |  202 ++++++++++++++++++++++++++++++++---
 gio/giomodule.h                     |   12 ++
 5 files changed, 224 insertions(+), 16 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 75f3ac8..d0c5e5d 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1427,8 +1427,13 @@ g_desktop_app_info_lookup_get_type
 <TITLE>GIOModule</TITLE>
 GIOModule
 g_io_module_new
+g_io_module_scope_block
+g_io_module_scope_free
+g_io_module_scope_new
 g_io_modules_load_all_in_directory
+g_io_modules_load_all_in_directory_with_scope
 g_io_modules_scan_all_in_directory
+g_io_modules_scan_all_in_directory_with_scope
 g_io_module_load
 g_io_module_unload
 g_io_module_query
diff --git a/gio/gio.symbols b/gio/gio.symbols
index d6d78a5..b8dfb1a 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -503,8 +503,13 @@ g_io_error_from_win32_error
 #endif
 g_io_module_get_type
 g_io_module_new
+g_io_module_scope_block
+g_io_module_scope_free
+g_io_module_scope_new
 g_io_modules_scan_all_in_directory
+g_io_modules_scan_all_in_directory_with_scope
 g_io_modules_load_all_in_directory
+g_io_modules_load_all_in_directory_with_scope
 g_io_extension_point_register
 g_io_extension_point_lookup
 g_io_extension_point_set_required_type
diff --git a/gio/gioenums.h b/gio/gioenums.h
index c0ba757..2a23597 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1498,6 +1498,22 @@ typedef enum {
   G_TLS_DATABASE_LOOKUP_KEYPAIR = 1
 } GTlsDatabaseLookupFlags;
 
+/**
+ * GIOModuleScopeFlags:
+ * @G_IO_MODULES_SCOPE_NONE: No module scan flags
+ * @G_IO_MODULES_SCOPE_BLOCK_DUPLICATES: When using this scope to load or
+ *     scan modules, automatically block a modules which has the same base
+ *     basename as previously loaded module.
+ *
+ * Flags for use with g_io_module_scope_new().
+ *
+ * Since: 2.30
+ */
+typedef enum {
+  G_IO_MODULE_SCOPE_NONE,
+  G_IO_MODULE_SCOPE_BLOCK_DUPLICATES
+} GIOModuleScopeFlags;
+
 G_END_DECLS
 
 #endif /* __GIO_ENUMS_H__ */
diff --git a/gio/giomodule.c b/gio/giomodule.c
index 4b77e3d..2b7e652 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -108,7 +108,103 @@
  *  see <link linkend="gio-querymodules">gio-querymodules</link>.
  *  You are expected to run this command after installing a
  *  GIO module.
+ *
+ *  The <envar>GIO_EXTRA_MODULES</envar> environment variable can be
+ *  used to specify additional directories to automatically load modules
+ *  from. This environment variable has the same syntax as the
+ *  <envar>PATH</envar>. If two modules have the same base name in different
+ *  directories, then the latter one will be ignored. If additional
+ *  directories are specified GIO will load modules from the built-in
+ *  directory last.
+ */
+
+/**
+ * GIOModuleScope:
+ *
+ * Represents a scope for loading IO modules. A scope can be used for blocking
+ * duplicate modules, or blocking a module you don't want to load.
+ *
+ * The scope can be used with g_io_modules_load_all_in_directory_with_scope()
+ * or g_io_modules_scan_all_in_directory_with_scope().
+ *
+ * Since: 2.30
+ */
+struct _GIOModuleScope {
+  GIOModuleScopeFlags flags;
+  GHashTable *basenames;
+};
+
+/**
+ * g_io_module_scope_new:
+ * @flags: flags for the new scope
+ *
+ * Create a new scope for loading of IO modules. A scope can be used for
+ * blocking duplicate modules, or blocking a module you don't want to load.
+ *
+ * Specify the %G_IO_MODULES_SCOPE_BLOCK_DUPLICATES flag to block modules
+ * which have the same base name as a module that has already been seen
+ * in this scope.
+ *
+ * Returns: (transfer full): the new module scope
+ *
+ * Since: 2.30
+ */
+GIOModuleScope *
+g_io_module_scope_new (GIOModuleScopeFlags flags)
+{
+  GIOModuleScope *scope = g_new0 (GIOModuleScope, 1);
+  scope->flags = flags;
+  scope->basenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+  return scope;
+}
+
+/**
+ * g_io_module_scope_free:
+ * @scope: a module loading scope
+ *
+ * Free a module scope.
+ *
+ * Since: 2.30
+ */
+void
+g_io_module_scope_free (GIOModuleScope *scope)
+{
+  if (!scope)
+    return;
+  g_hash_table_destroy (scope->basenames);
+  g_free (scope);
+}
+
+/**
+ * g_io_module_scope_block:
+ * @scope: a module loading scope
+ *
+ * Block modules with the given base name from being loaded when this scope
+ * is used with g_io_modules_scan_all_in_directory_with_scope() or
+ * g_io_modules_load_all_in_directory_with_scope().
+ *
+ * Since: 2.30
  */
+void
+g_io_module_scope_block (GIOModuleScope *scope,
+                         const gchar    *basename)
+{
+  gchar *key;
+
+  g_return_if_fail (scope != NULL);
+  g_return_if_fail (basename != NULL);
+
+  key = g_strdup (basename);
+  g_hash_table_insert (scope->basenames, key, key);
+}
+
+static gboolean
+_g_io_module_scope_contains (GIOModuleScope *scope,
+                             const gchar    *basename)
+{
+  return g_hash_table_lookup (scope->basenames, basename) ? TRUE : FALSE;
+}
+
 struct _GIOModule {
   GTypeModule parent_instance;
 
@@ -253,20 +349,36 @@ g_io_module_new (const gchar *filename)
 }
 
 static gboolean
-is_valid_module_name (const gchar *basename)
+is_valid_module_name (const gchar        *basename,
+                      GIOModuleScope     *scope)
 {
+  gboolean result;
+
 #if !defined(G_OS_WIN32) && !defined(G_WITH_CYGWIN)
-  return
-    g_str_has_prefix (basename, "lib") &&
-    g_str_has_suffix (basename, ".so");
+  if (!g_str_has_prefix (basename, "lib") ||
+      !g_str_has_suffix (basename, ".so"))
+    return FALSE;
 #else
-  return g_str_has_suffix (basename, ".dll");
+  if (!g_str_has_suffix (basename, ".dll"))
+    return FALSE;
 #endif
+
+  result = TRUE;
+  if (scope)
+    {
+      result = _g_io_module_scope_contains (scope, basename) ? FALSE : TRUE;
+      if (result && (scope->flags & G_IO_MODULE_SCOPE_BLOCK_DUPLICATES))
+        g_io_module_scope_block (scope, basename);
+    }
+
+  return result;
 }
 
+
 /**
- * g_io_modules_scan_all_in_directory:
+ * g_io_modules_scan_all_in_directory_with_scope:
  * @dirname: pathname for a directory containing modules to scan.
+ * @scope: a scope to use when scanning the modules
  *
  * Scans all the modules in the specified directory, ensuring that
  * any extension point implemented by a module is registered.
@@ -280,10 +392,11 @@ is_valid_module_name (const gchar *basename)
  * If you need to guarantee that all types are loaded in all the modules,
  * use g_io_modules_load_all_in_directory().
  *
- * Since: 2.24
+ * Since: 2.30
  **/
 void
-g_io_modules_scan_all_in_directory (const char *dirname)
+g_io_modules_scan_all_in_directory_with_scope (const char     *dirname,
+                                               GIOModuleScope *scope)
 {
   const gchar *name;
   char *filename;
@@ -353,7 +466,7 @@ g_io_modules_scan_all_in_directory (const char *dirname)
 
   while ((name = g_dir_read_name (dir)))
     {
-      if (is_valid_module_name (name))
+      if (is_valid_module_name (name, scope))
 	{
 	  GIOExtensionPoint *extension_point;
 	  GIOModule *module;
@@ -404,10 +517,34 @@ g_io_modules_scan_all_in_directory (const char *dirname)
   g_free (filename);
 }
 
+/**
+ * g_io_modules_scan_all_in_directory:
+ * @dirname: pathname for a directory containing modules to scan.
+ *
+ * Scans all the modules in the specified directory, ensuring that
+ * any extension point implemented by a module is registered.
+ *
+ * This may not actually load and initialize all the types in each
+ * module, some modules may be lazily loaded and initialized when
+ * an extension point it implementes is used with e.g.
+ * g_io_extension_point_get_extensions() or
+ * g_io_extension_point_get_extension_by_name().
+ *
+ * If you need to guarantee that all types are loaded in all the modules,
+ * use g_io_modules_load_all_in_directory().
+ *
+ * Since: 2.24
+ **/
+void
+g_io_modules_scan_all_in_directory (const char *dirname)
+{
+  g_io_modules_scan_all_in_directory_with_scope (dirname, NULL);
+}
 
 /**
- * g_io_modules_load_all_in_directory:
+ * g_io_modules_load_all_in_directory_with_scope:
  * @dirname: pathname for a directory containing modules to load.
+ * @scope: a scope to use when scanning the modules.
  *
  * Loads all the modules in the specified directory.
  *
@@ -421,9 +558,12 @@ g_io_modules_scan_all_in_directory (const char *dirname)
  *      unload them (enabling on-demand loading) you must call
  *      g_type_module_unuse() on all the modules. Free the list
  *      with g_list_free().
+ *
+ * Since: 2.30
  **/
 GList *
-g_io_modules_load_all_in_directory (const char *dirname)
+g_io_modules_load_all_in_directory_with_scope (const char     *dirname,
+                                               GIOModuleScope *scope)
 {
   const gchar *name;
   GDir        *dir;
@@ -439,7 +579,7 @@ g_io_modules_load_all_in_directory (const char *dirname)
   modules = NULL;
   while ((name = g_dir_read_name (dir)))
     {
-      if (is_valid_module_name (name))
+      if (is_valid_module_name (name, scope))
         {
           GIOModule *module;
           gchar     *path;
@@ -466,6 +606,29 @@ g_io_modules_load_all_in_directory (const char *dirname)
   return modules;
 }
 
+/**
+ * g_io_modules_load_all_in_directory:
+ * @dirname: pathname for a directory containing modules to load.
+ *
+ * Loads all the modules in the specified directory.
+ *
+ * If don't require all modules to be initialized (and thus registering
+ * all gtypes) then you can use g_io_modules_scan_all_in_directory()
+ * which allows delayed/lazy loading of modules.
+ *
+ * Returns: (element-type GIOModule) (transfer full): a list of #GIOModules loaded
+ *      from the directory,
+ *      All the modules are loaded into memory, if you want to
+ *      unload them (enabling on-demand loading) you must call
+ *      g_type_module_unuse() on all the modules. Free the list
+ *      with g_list_free().
+ **/
+GList *
+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 (registered_extensions);
 G_LOCK_DEFINE_STATIC (loaded_dirs);
 
@@ -571,6 +734,7 @@ _g_io_modules_ensure_loaded (void)
 {
   static gboolean loaded_dirs = FALSE;
   const char *module_path;
+  GIOModuleScope *scope;
 
   _g_io_modules_ensure_extension_points_registered ();
   
@@ -579,11 +743,10 @@ _g_io_modules_ensure_loaded (void)
   if (!loaded_dirs)
     {
       loaded_dirs = TRUE;
+      scope = g_io_module_scope_new (G_IO_MODULE_SCOPE_BLOCK_DUPLICATES);
 
-      g_io_modules_scan_all_in_directory (GIO_MODULE_DIR);
-
+      /* First load any overrides, extras */
       module_path = g_getenv ("GIO_EXTRA_MODULES");
-
       if (module_path)
 	{
 	  gchar **paths;
@@ -592,11 +755,18 @@ _g_io_modules_ensure_loaded (void)
 	  paths = g_strsplit (module_path, ":", 0);
 
 	  for (i = 0; paths[i] != NULL; i++)
-	    g_io_modules_scan_all_in_directory (paths[i]);
+	    {
+	      g_io_modules_scan_all_in_directory_with_scope (paths[i], scope);
+	    }
 
 	  g_strfreev (paths);
 	}
 
+      /* Then load the compiled in path */
+      g_io_modules_scan_all_in_directory_with_scope (GIO_MODULE_DIR, scope);
+
+      g_io_module_scope_free (scope);
+
       /* Initialize types from built-in "modules" */
       g_null_settings_backend_get_type ();
       g_memory_settings_backend_get_type ();
diff --git a/gio/giomodule.h b/gio/giomodule.h
index 89619c8..5f04acb 100644
--- a/gio/giomodule.h
+++ b/gio/giomodule.h
@@ -32,6 +32,13 @@
 
 G_BEGIN_DECLS
 
+typedef struct _GIOModuleScope GIOModuleScope;
+
+GIOModuleScope *   g_io_module_scope_new     (GIOModuleScopeFlags  flags);
+void               g_io_module_scope_free    (GIOModuleScope      *scope);
+void               g_io_module_scope_block   (GIOModuleScope      *scope,
+                                              const gchar         *basename);
+
 #define G_IO_TYPE_MODULE         (g_io_module_get_type ())
 #define G_IO_MODULE(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_IO_TYPE_MODULE, GIOModule))
 #define G_IO_MODULE_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_IO_TYPE_MODULE, GIOModuleClass))
@@ -52,6 +59,11 @@ GIOModule         *g_io_module_new                            (const gchar
 void               g_io_modules_scan_all_in_directory         (const char        *dirname);
 GList             *g_io_modules_load_all_in_directory         (const gchar       *dirname);
 
+void               g_io_modules_scan_all_in_directory_with_scope   (const gchar       *dirname,
+                                                                    GIOModuleScope    *scope);
+GList             *g_io_modules_load_all_in_directory_with_scope   (const gchar       *dirname,
+                                                                    GIOModuleScope    *scope);
+
 GIOExtensionPoint *g_io_extension_point_register              (const char        *name);
 GIOExtensionPoint *g_io_extension_point_lookup                (const char        *name);
 void               g_io_extension_point_set_required_type     (GIOExtensionPoint *extension_point,



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