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
This commit is contained in:
Stef Walter 2011-08-26 15:27:19 +02:00
parent 78ec02647e
commit d789e78dff
5 changed files with 224 additions and 16 deletions

View File

@ -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

View File

@ -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

View File

@ -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__ */

View File

@ -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 ();

View File

@ -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,