[libpeas] Add nonglobal plugin loader support
- From: Garrett Regier <gregier src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [libpeas] Add nonglobal plugin loader support
- Date: Tue, 18 Nov 2014 18:38:48 +0000 (UTC)
commit cbd4ecf6f2026f9be895efa49ad5dbbb7a1c806c
Author: Garrett Regier <garrett regier riftio com>
Date: Sun Nov 16 12:22:33 2014 -0800
Add nonglobal plugin loader support
This allows multiple threads to each have a PeasEngine
and be used without internal locking. It also allows using
lua5.1 plugins from multiple threads.
https://bugzilla.gnome.org/show_bug.cgi?id=739831
libpeas/peas-engine.c | 136 ++++++++++++++++++++++-------
libpeas/peas-engine.h | 2 +
libpeas/peas-plugin-loader.c | 15 +++
libpeas/peas-plugin-loader.h | 2 +
loaders/lua5.1/peas-plugin-loader-lua.c | 7 ++
tests/libpeas/testing/testing-extension.c | 50 ++++++++---
tests/libpeas/testing/testing.c | 4 +-
tests/libpeas/testing/testing.h | 8 +-
tests/testing-util/testing-util.c | 8 ++-
tests/testing-util/testing-util.h | 17 ++--
10 files changed, 190 insertions(+), 59 deletions(-)
---
diff --git a/libpeas/peas-engine.c b/libpeas/peas-engine.c
index 520d8ee..8ffd39e 100644
--- a/libpeas/peas-engine.c
+++ b/libpeas/peas-engine.c
@@ -4,6 +4,7 @@
*
* Copyright (C) 2002-2005 Paolo Maggi
* Copyright (C) 2009 Steve Frécinaux
+ * Copyright (C) 2010-2014 Garrett Regier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
@@ -71,12 +72,21 @@ enum {
PROP_0,
PROP_PLUGIN_LIST,
PROP_LOADED_PLUGINS,
+ PROP_NONGLOBAL_LOADERS,
N_PROPERTIES
};
static guint signals[LAST_SIGNAL];
static GParamSpec *properties[N_PROPERTIES] = { NULL };
+typedef struct _GlobalLoaderInfo {
+ PeasPluginLoader *loader;
+ PeasObjectModule *module;
+
+ guint enabled : 1;
+ guint failed : 1;
+} GlobalLoaderInfo;
+
typedef struct _LoaderInfo {
PeasPluginLoader *loader;
@@ -96,13 +106,14 @@ struct _PeasEnginePrivate {
GList *plugin_list;
guint in_dispose : 1;
+ guint use_nonglobal_loaders : 1;
};
static gboolean shutdown = FALSE;
static PeasEngine *default_engine = NULL;
static GMutex loaders_lock;
-static LoaderInfo loaders[PEAS_UTILS_N_LOADERS];
+static GlobalLoaderInfo loaders[PEAS_UTILS_N_LOADERS];
static void peas_engine_load_plugin_real (PeasEngine *engine,
PeasPluginInfo *info);
@@ -396,6 +407,9 @@ peas_engine_set_property (GObject *object,
peas_engine_set_loaded_plugins (engine,
(const gchar **) g_value_get_boxed (value));
break;
+ case PROP_NONGLOBAL_LOADERS:
+ engine->priv->use_nonglobal_loaders = g_value_get_boolean (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -420,6 +434,9 @@ peas_engine_get_property (GObject *object,
g_value_take_boxed (value,
(gconstpointer) peas_engine_get_loaded_plugins (engine));
break;
+ case PROP_NONGLOBAL_LOADERS:
+ g_value_set_boolean (value, engine->priv->use_nonglobal_loaders);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -542,6 +559,22 @@ peas_engine_class_init (PeasEngineClass *klass)
G_PARAM_STATIC_STRINGS);
/**
+ * PeasEngine:nonglobal-loaders:
+ *
+ * If non-global plugin loaders should be used.
+ *
+ * See peas_engine_new_with_nonglobal_loaders() for more information.
+ */
+ properties[PROP_NONGLOBAL_LOADERS] =
+ g_param_spec_boolean ("nonglobal-loaders",
+ "Non-global Loaders",
+ "Use non-global plugin loaders",
+ FALSE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS);
+
+ /**
* PeasEngine::load-plugin:
* @engine: A #PeasEngine.
* @info: A #PeasPluginInfo.
@@ -618,11 +651,14 @@ load_module (const gchar *module_name,
static PeasObjectModule *
get_plugin_loader_module (gint loader_id)
{
+ GlobalLoaderInfo *global_loader_info = &loaders[loader_id];
gint i, j;
- PeasObjectModule *module;
const gchar *loader_name;
gchar *module_name, *module_dir;
+ if (global_loader_info->module != NULL)
+ return global_loader_info->module;
+
loader_name = peas_utils_get_loader_from_id (loader_id);
module_name = g_strconcat (loader_name, "loader", NULL);
module_dir = peas_dirs_get_plugin_loaders_dir ();
@@ -636,14 +672,14 @@ get_plugin_loader_module (gint loader_id)
module_name[j] = '\0';
- module = load_module (module_name, module_dir);
+ global_loader_info->module = load_module (module_name, module_dir);
- if (module == NULL)
+ if (global_loader_info->module == NULL)
{
gchar *tmp = module_dir;
module_dir = g_build_filename (module_dir, loader_name, NULL);
- module = load_module (module_name, module_dir);
+ global_loader_info->module = load_module (module_name, module_dir);
g_free (tmp);
}
@@ -651,26 +687,34 @@ get_plugin_loader_module (gint loader_id)
g_free (module_dir);
g_free (module_name);
- if (module == NULL)
+ if (global_loader_info->module == NULL)
g_warning ("Could not load plugin loader '%s'", loader_name);
- return module;
+ return global_loader_info->module;
}
static PeasPluginLoader *
create_plugin_loader (gint loader_id)
{
- PeasObjectModule *module;
PeasPluginLoader *loader;
- module = get_plugin_loader_module (loader_id);
- if (module == NULL)
- return NULL;
+ if (peas_utils_get_loader_id ("C") == loader_id)
+ {
+ loader = peas_plugin_loader_c_new ();
+ }
+ else
+ {
+ PeasObjectModule *module;
+
+ module = get_plugin_loader_module (loader_id);
+ if (module == NULL)
+ return NULL;
- loader = PEAS_PLUGIN_LOADER (
- peas_object_module_create_object (module,
- PEAS_TYPE_PLUGIN_LOADER,
- 0, NULL));
+ loader = PEAS_PLUGIN_LOADER (
+ peas_object_module_create_object (module,
+ PEAS_TYPE_PLUGIN_LOADER,
+ 0, NULL));
+ }
if (loader == NULL || !peas_plugin_loader_initialize (loader))
{
@@ -679,38 +723,41 @@ create_plugin_loader (gint loader_id)
g_clear_object (&loader);
}
- /* Don't bother unloading the
- * module as it is always resident
- */
return loader;
}
static PeasPluginLoader *
-get_local_plugin_loader (gint loader_id)
+get_local_plugin_loader (PeasEngine *engine,
+ gint loader_id)
{
- LoaderInfo *global_loader_info = &loaders[loader_id];
+ GlobalLoaderInfo *global_loader_info = &loaders[loader_id];
+ PeasPluginLoader *loader;
if (global_loader_info->failed)
return NULL;
- if (global_loader_info->loader != NULL)
- return g_object_ref (global_loader_info->loader);
-
- if (peas_utils_get_loader_id ("C") == loader_id)
+ if (global_loader_info->loader != NULL &&
+ (!engine->priv->use_nonglobal_loaders ||
+ peas_plugin_loader_is_global (global_loader_info->loader)))
{
- global_loader_info->loader = peas_plugin_loader_c_new ();
return g_object_ref (global_loader_info->loader);
}
- global_loader_info->loader = create_plugin_loader (loader_id);
+ loader = create_plugin_loader (loader_id);
- if (global_loader_info->loader == NULL)
+ if (loader == NULL)
{
global_loader_info->failed = TRUE;
return NULL;
}
- return g_object_ref (global_loader_info->loader);
+ if (!engine->priv->use_nonglobal_loaders ||
+ peas_plugin_loader_is_global (loader))
+ {
+ global_loader_info->loader = g_object_ref (loader);
+ }
+
+ return loader;
}
static PeasPluginLoader *
@@ -718,7 +765,7 @@ get_plugin_loader (PeasEngine *engine,
gint loader_id)
{
LoaderInfo *loader_info = &engine->priv->loaders[loader_id];
- LoaderInfo *global_loader_info = &loaders[loader_id];
+ GlobalLoaderInfo *global_loader_info = &loaders[loader_id];
if (loader_info->loader != NULL || loader_info->failed)
return loader_info->loader;
@@ -749,7 +796,7 @@ get_plugin_loader (PeasEngine *engine,
return get_plugin_loader (engine, loader_id);
}
- loader_info->loader = get_local_plugin_loader (loader_id);
+ loader_info->loader = get_local_plugin_loader (engine, loader_id);
if (loader_info->loader == NULL)
loader_info->failed = TRUE;
@@ -775,7 +822,8 @@ get_plugin_loader (PeasEngine *engine,
*
* Unlike the C, python and python3 plugin loaders the lua5.1 plugin
* loader can only be used from a single thread. Should this happen
- * a deadlock will occur.
+ * a deadlock will occur. This can be be avoided by using
+ * peas_engine_new_with_nonglobal_loaders().
*
* Note: plugin loaders used to be shared across #PeasEngines so enabling
* a loader on one #PeasEngine would enable it on all #PeasEngines.
@@ -1371,6 +1419,27 @@ peas_engine_new (void)
}
/**
+ * peas_engine_new_with_nonglobal_loaders:
+ *
+ * Return a new instance of #PeasEngine which will use non-global
+ * plugin loaders instead of the default global ones. This allows
+ * multiple threads to each have a #PeasEngine and be used without
+ * internal locking.
+ *
+ * Note: due to CPython's GIL the python and python3
+ * plugin loaders are always global.
+ *
+ * Returns: a new instance of #PeasEngine that uses nonglobal loaders.
+ */
+PeasEngine *
+peas_engine_new_with_nonglobal_loaders (void)
+{
+ return PEAS_ENGINE (g_object_new (PEAS_TYPE_ENGINE,
+ "nonglobal-loaders", TRUE,
+ NULL));
+}
+
+/**
* peas_engine_get_default:
*
* Return the existing instance of #PeasEngine or a subclass of it.
@@ -1423,7 +1492,7 @@ peas_engine_shutdown (void)
for (i = 0; i < G_N_ELEMENTS (loaders); ++i)
{
- LoaderInfo *loader_info = &loaders[i];
+ GlobalLoaderInfo *loader_info = &loaders[i];
if (loader_info->loader != NULL)
{
@@ -1434,6 +1503,9 @@ peas_engine_shutdown (void)
g_assert (loader_info->loader == NULL);
}
+ /* Don't bother unloading the
+ * module as it is always resident
+ */
loader_info->failed = TRUE;
}
diff --git a/libpeas/peas-engine.h b/libpeas/peas-engine.h
index 8d23347..3618f7e 100644
--- a/libpeas/peas-engine.h
+++ b/libpeas/peas-engine.h
@@ -75,6 +75,8 @@ struct _PeasEngineClass {
GType peas_engine_get_type (void) G_GNUC_CONST;
PeasEngine *peas_engine_new (void);
+PeasEngine *peas_engine_new_with_nonglobal_loaders
+ (void);
PeasEngine *peas_engine_get_default (void);
void peas_engine_add_search_path (PeasEngine *engine,
diff --git a/libpeas/peas-plugin-loader.c b/libpeas/peas-plugin-loader.c
index ccd9078..4258bab 100644
--- a/libpeas/peas-plugin-loader.c
+++ b/libpeas/peas-plugin-loader.c
@@ -70,6 +70,21 @@ peas_plugin_loader_initialize (PeasPluginLoader *loader)
}
gboolean
+peas_plugin_loader_is_global (PeasPluginLoader *loader)
+{
+ PeasPluginLoaderClass *klass;
+
+ g_return_val_if_fail (PEAS_IS_PLUGIN_LOADER (loader), FALSE);
+
+ klass = PEAS_PLUGIN_LOADER_GET_CLASS (loader);
+
+ if (klass->is_global != NULL)
+ return klass->is_global (loader);
+
+ return TRUE;
+}
+
+gboolean
peas_plugin_loader_load (PeasPluginLoader *loader,
PeasPluginInfo *info)
{
diff --git a/libpeas/peas-plugin-loader.h b/libpeas/peas-plugin-loader.h
index 30f6a88..5bf8357 100644
--- a/libpeas/peas-plugin-loader.h
+++ b/libpeas/peas-plugin-loader.h
@@ -47,6 +47,7 @@ struct _PeasPluginLoaderClass {
GObjectClass parent;
gboolean (*initialize) (PeasPluginLoader *loader);
+ gboolean (*is_global) (PeasPluginLoader *loader);
gboolean (*load) (PeasPluginLoader *loader,
PeasPluginInfo *info);
@@ -67,6 +68,7 @@ struct _PeasPluginLoaderClass {
GType peas_plugin_loader_get_type (void) G_GNUC_CONST;
gboolean peas_plugin_loader_initialize (PeasPluginLoader *loader);
+gboolean peas_plugin_loader_is_global (PeasPluginLoader *loader);
gboolean peas_plugin_loader_load (PeasPluginLoader *loader,
PeasPluginInfo *info);
diff --git a/loaders/lua5.1/peas-plugin-loader-lua.c b/loaders/lua5.1/peas-plugin-loader-lua.c
index 879e82a..fdb4a3f 100644
--- a/loaders/lua5.1/peas-plugin-loader-lua.c
+++ b/loaders/lua5.1/peas-plugin-loader-lua.c
@@ -370,6 +370,12 @@ peas_plugin_loader_lua_initialize (PeasPluginLoader *loader)
return TRUE;
}
+static gboolean
+peas_plugin_loader_lua_is_global (PeasPluginLoader *loader)
+{
+ return FALSE;
+}
+
static void
peas_plugin_loader_lua_init (PeasPluginLoaderLua *lua_loader)
{
@@ -397,6 +403,7 @@ peas_plugin_loader_lua_class_init (PeasPluginLoaderLuaClass *klass)
object_class->finalize = peas_plugin_loader_lua_finalize;
loader_class->initialize = peas_plugin_loader_lua_initialize;
+ loader_class->is_global = peas_plugin_loader_lua_is_global;
loader_class->load = peas_plugin_loader_lua_load;
loader_class->unload = peas_plugin_loader_lua_unload;
loader_class->create_extension = peas_plugin_loader_lua_create_extension;
diff --git a/tests/libpeas/testing/testing-extension.c b/tests/libpeas/testing/testing-extension.c
index 97e7dfc..d5dba02 100644
--- a/tests/libpeas/testing/testing-extension.c
+++ b/tests/libpeas/testing/testing-extension.c
@@ -1,8 +1,8 @@
/*
- * testing-extensin.c
+ * testing-extension.c
* This file is part of libpeas
*
- * Copyright (C) 2011 - Garrett Regier
+ * Copyright (C) 2011-2014 - Garrett Regier
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Library General Public License as published by
@@ -270,25 +270,25 @@ test_extension_get_settings (PeasEngine *engine,
}
static void
-multiple_threads_in_thread (guint nth_thread)
+multiple_threads_in_thread (guint nth_thread,
+ gboolean use_nonglobal_loaders)
{
gint i, j;
PeasEngine *engine;
PeasPluginInfo *info;
GObject *extension;
- const gboolean is_slow = strstr (loader, "python") != NULL;
- engine = testing_engine_new ();
+ engine = testing_engine_new_full (use_nonglobal_loaders);
peas_engine_enable_loader (engine, loader);
info = peas_engine_get_plugin_info (engine, extension_plugin);
g_assert (info != NULL);
- for (i = 0; i < (is_slow ? 5 : 20); ++i)
+ for (i = 0; i < 10; ++i)
{
g_assert (peas_engine_load_plugin (engine, info));
- for (j = 0; j < 5; ++j)
+ for (j = 0; j < 50; ++j)
{
extension = peas_engine_create_extension (engine, info,
INTROSPECTION_TYPE_BASE,
@@ -306,18 +306,22 @@ multiple_threads_in_thread (guint nth_thread)
static void
test_extension_multiple_threads (PeasEngine *engine,
- PeasPluginInfo *info)
+ PeasPluginInfo *info,
+ gboolean use_nonglobal_loaders)
{
- gint i;
+ gint i, n_threads;
GThreadPool *pool;
GError *error = NULL;
- const gboolean is_slow = strstr (loader, "python") != NULL;
+
+ /* Avoid too many threads, but try to get some good contention */
+ n_threads = g_get_num_processors () + 2;
pool = g_thread_pool_new ((GFunc) multiple_threads_in_thread,
- NULL, g_get_num_processors (), TRUE, &error);
+ GINT_TO_POINTER (use_nonglobal_loaders),
+ n_threads, TRUE, &error);
g_assert_no_error (error);
- for (i = 0; i < (is_slow ? 20 : 100); ++i)
+ for (i = 0; i < g_thread_pool_get_max_threads (pool); ++i)
{
/* Cannot supply NULL as the data... */
g_thread_pool_push (pool, GUINT_TO_POINTER (i + 1), &error);
@@ -328,6 +332,20 @@ test_extension_multiple_threads (PeasEngine *engine,
}
static void
+test_extension_multiple_threads_global_loaders (PeasEngine *engine,
+ PeasPluginInfo *info)
+{
+ test_extension_multiple_threads (engine, info, FALSE);
+}
+
+static void
+test_extension_multiple_threads_nonglobal_loaders (PeasEngine *engine,
+ PeasPluginInfo *info)
+{
+ test_extension_multiple_threads (engine, info, TRUE);
+}
+
+static void
test_extension_call_no_args (PeasEngine *engine,
PeasPluginInfo *info)
{
@@ -489,7 +507,13 @@ testing_extension_basic (const gchar *loader_)
/* See peas_engine_enable_loader() */
if (g_strcmp0 (loader, "lua5.1") != 0)
- _EXTENSION_TEST (loader, "multiple-threads", multiple_threads);
+ {
+ _EXTENSION_TEST (loader, "multiple-threads/global-loaders",
+ multiple_threads_global_loaders);
+ }
+
+ _EXTENSION_TEST (loader, "multiple-threads/nonglobal-loaders",
+ multiple_threads_nonglobal_loaders);
}
void
diff --git a/tests/libpeas/testing/testing.c b/tests/libpeas/testing/testing.c
index aeb387e..741e313 100644
--- a/tests/libpeas/testing/testing.c
+++ b/tests/libpeas/testing/testing.c
@@ -55,7 +55,7 @@ testing_init (gint *argc,
}
PeasEngine *
-testing_engine_new (void)
+testing_engine_new_full (gboolean nonglobal_loaders)
{
PeasEngine *engine;
@@ -75,7 +75,7 @@ testing_engine_new (void)
testing_util_push_log_hook ("*Error loading *unkown-loader.plugin*");
/* Must be after pushing log hooks */
- engine = testing_util_engine_new ();
+ engine = testing_util_engine_new_full (nonglobal_loaders);
peas_engine_add_search_path (engine, BUILDDIR "/tests/libpeas/plugins",
SRCDIR "/tests/libpeas/plugins");
diff --git a/tests/libpeas/testing/testing.h b/tests/libpeas/testing/testing.h
index f638268..23a8932 100644
--- a/tests/libpeas/testing/testing.h
+++ b/tests/libpeas/testing/testing.h
@@ -27,10 +27,12 @@
G_BEGIN_DECLS
-void testing_init (gint *argc,
- gchar ***argv);
+void testing_init (gint *argc,
+ gchar ***argv);
-PeasEngine *testing_engine_new (void);
+PeasEngine *testing_engine_new_full (gboolean nonglobal_loaders);
+
+#define testing_engine_new() (testing_engine_new_full (FALSE))
/* libtesting-util functions which do not need to be overridden */
#define testing_engine_free testing_util_engine_free
diff --git a/tests/testing-util/testing-util.c b/tests/testing-util/testing-util.c
index bd0f839..3b98fe9 100644
--- a/tests/testing-util/testing-util.c
+++ b/tests/testing-util/testing-util.c
@@ -203,7 +203,7 @@ engine_weak_notify (gpointer unused,
}
PeasEngine *
-testing_util_engine_new (void)
+testing_util_engine_new_full (gboolean nonglobal_loaders)
{
PeasEngine *engine;
@@ -215,7 +215,11 @@ testing_util_engine_new (void)
g_assert (g_private_get (&engine_key) == NULL);
/* Must be after requiring typelibs */
- engine = peas_engine_new ();
+ if (!nonglobal_loaders)
+ engine = peas_engine_new ();
+ else
+ engine = peas_engine_new_with_nonglobal_loaders ();
+
g_private_set (&engine_key, engine);
g_object_weak_ref (G_OBJECT (engine),
diff --git a/tests/testing-util/testing-util.h b/tests/testing-util/testing-util.h
index 3832794..726120f 100644
--- a/tests/testing-util/testing-util.h
+++ b/tests/testing-util/testing-util.h
@@ -26,16 +26,19 @@
G_BEGIN_DECLS
-void testing_util_init (void);
+void testing_util_init (void);
-PeasEngine *testing_util_engine_new (void);
-void testing_util_engine_free (PeasEngine *engine);
+PeasEngine *testing_util_engine_new_full (gboolean nonglobal_loaders);
+void testing_util_engine_free (PeasEngine *engine);
-int testing_util_run_tests (void);
+int testing_util_run_tests (void);
-void testing_util_push_log_hook (const gchar *pattern);
-void testing_util_pop_log_hook (void);
-void testing_util_pop_log_hooks (void);
+void testing_util_push_log_hook (const gchar *pattern);
+void testing_util_pop_log_hook (void);
+void testing_util_pop_log_hooks (void);
+
+
+#define testing_util_engine_new() (testing_util_engine_new_full (FALSE))
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]