mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-26 22:16:16 +01:00
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:
parent
78ec02647e
commit
d789e78dff
@ -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
|
||||
|
@ -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
|
||||
|
@ -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__ */
|
||||
|
202
gio/giomodule.c
202
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 ();
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user