From abefe01dd260cddbd253ba0c03d9c903138c71c1 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Mon, 23 Jul 2018 20:57:49 +0200 Subject: Tracked the reference counter for plugins with more care. --- plugins/arm/core.c | 2 +- plugins/dalvik/core.c | 2 +- plugins/pychrysalide/plugin.c | 22 ++++++++++- plugins/pychrysalide/pychrysa.c | 13 +++++- src/plugins/pglist.c | 87 +++++++++++++++++++++++++++++++++++++++++ src/plugins/pglist.h | 2 +- src/plugins/plugin-def.h | 23 +++++++++++ src/plugins/plugin.c | 66 ++++++++++++++++++++++++++----- 8 files changed, 202 insertions(+), 15 deletions(-) diff --git a/plugins/arm/core.c b/plugins/arm/core.c index 6a512b2..d2dd805 100644 --- a/plugins/arm/core.c +++ b/plugins/arm/core.c @@ -33,7 +33,7 @@ DEFINE_CHRYSALIDE_PLUGIN("arm", "Add support for the ARM architecture", "0.1.0", - RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); + RL("PyChrysalide"), AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT)); diff --git a/plugins/dalvik/core.c b/plugins/dalvik/core.c index 524e3c9..2e936b9 100644 --- a/plugins/dalvik/core.c +++ b/plugins/dalvik/core.c @@ -36,7 +36,7 @@ DEFINE_CHRYSALIDE_PLUGIN("dalvik", "Add support for the Dalvik architecture", "0.1.0", - RL("PyChrysalide"), AL(PGA_PLUGIN_INIT)); + RL("PyChrysalide"), AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT)); diff --git a/plugins/pychrysalide/plugin.c b/plugins/pychrysalide/plugin.c index b57794c..a916668 100644 --- a/plugins/pychrysalide/plugin.c +++ b/plugins/pychrysalide/plugin.c @@ -25,6 +25,8 @@ #include "plugin.h" +#include +#include #include #include @@ -166,6 +168,8 @@ static void g_python_plugin_init(GPythonPlugin *plugin) static void g_python_plugin_dispose(GPythonPlugin *plugin) { + Py_DECREF(plugin->instance); + G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); } @@ -185,9 +189,21 @@ static void g_python_plugin_dispose(GPythonPlugin *plugin) static void g_python_plugin_finalize(GPythonPlugin *plugin) { - Py_DECREF(plugin->instance); + plugin_interface *final; /* Interface finale conservée */ + Py_DECREF(plugin->module); + final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; + + if (final != NULL) + { + assert(final->required_count == 1); + + free(final->required); + free(final); + + } + G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); } @@ -519,6 +535,10 @@ static bool g_python_plugin_read_interface(GPythonPlugin *plugin) memcpy(final, &interface, sizeof(interface)); + final->required = (const char **)malloc(sizeof(char *)); + final->required[0] = "PyChrysalide"; + final->required_count = 1; + G_PLUGIN_MODULE(plugin)->interface = final; } diff --git a/plugins/pychrysalide/pychrysa.c b/plugins/pychrysalide/pychrysa.c index 4e522e5..c1fdd6f 100644 --- a/plugins/pychrysalide/pychrysa.c +++ b/plugins/pychrysalide/pychrysa.c @@ -59,7 +59,8 @@ -DEFINE_CHRYSALIDE_ACTIVE_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", PGA_PLUGIN_INIT); +DEFINE_CHRYSALIDE_CONTAINER_PLUGIN("PyChrysalide", "Provides bindings to Python", "0.1.0", + EMPTY_PG_LIST(.required), AL(PGA_PLUGIN_INIT, PGA_PLUGIN_EXIT)); /* Note la nature du chargement */ @@ -402,6 +403,8 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) load_remaning_plugins(); + g_object_unref(G_OBJECT(self)); + } return result; @@ -488,7 +491,15 @@ static bool load_python_plugins(GPluginModule *plugin) g_plugin_module_log_variadic_message(plugin, LMT_PROCESS, _("Loaded the Python plugin found in the '%s' directory"), filename); + + /** + * Comme le greffon n'est pas passé par la résolution des dépendances, + * on simule l'effet attendu. + */ + g_object_ref(G_OBJECT(plugin)); + _register_plugin(pyplugin); + } free(filename); diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c index 1f608b4..57f7538 100644 --- a/src/plugins/pglist.c +++ b/src/plugins/pglist.c @@ -54,6 +54,9 @@ static int filter_dirs_or_mods(const struct dirent *); /* Part à la recherche de greffons sous forme de modules. */ static void browse_directory_for_plugins(const char *); +/* Suivit les variations du compteur de références d'un greffon. */ +static void on_plugin_ref_toggle(gpointer, GPluginModule *, gboolean); + /****************************************************************************** @@ -97,16 +100,55 @@ bool init_all_plugins(bool load) void exit_all_plugins(void) { size_t i; /* Boucle de parcours */ + const plugin_interface *pg_iface; /* Définition du greffon */ + + lock_plugin_list_for_reading(); if (_pg_list != NULL) { for (i = 0; i < _pg_count; i++) + { + assert(_pg_list[i] != NULL); + + /** + * Si le greffon a conduit à la mise en place d'autres greffons, le + * système de dépendances ne suffit pas pour le décompte des références : + * le greffon voit à un instant T son compteur décroître ici ; à un + * instant T+1, un greffon fils décrémente à son tour le compteur vers + * le greffon principal. + * + * Le compteur du conteneur tombe alors à 0, et le code correspondant + * est retiré. Lorsque que le flot d'exécution revient à la procédure + * de sortie du second greffon, son code n'est plus en mémoire. + * + * On s'assure donc que les greffons qui génèrent d'autres greffons + * sont bien traités en dernier. + */ + + pg_iface = g_plugin_module_get_interface(_pg_list[i]); + + if (pg_iface != NULL && pg_iface->container) + g_object_ref(_pg_list[i]); + + g_object_unref(_pg_list[i]); + + } + + for (i = 0; i < _pg_count; i++) + { + if (_pg_list[i] == NULL) + continue; + g_object_unref(_pg_list[i]); + } + free(_pg_list); } + unlock_plugin_list_for_reading(); + g_rw_lock_clear(&_pg_lock); } @@ -269,6 +311,48 @@ void _register_plugin(GPluginModule *plugin) _pg_list[_pg_count - 1] = plugin; + g_object_add_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : unused = adresse non utilisée ici. * +* plugin = greffon àà venir effacer de la liste au besoin. * +* last = indication sur la valeur du compteur de références. * +* * +* Description : Suivit les variations du compteur de références d'un greffon.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void on_plugin_ref_toggle(gpointer unused, GPluginModule *plugin, gboolean last) +{ + const plugin_interface *pg_iface; /* Vitrine d'un greffon */ + size_t index; /* Indice du greffon */ + GPluginModule *same; /* Juste pour la récupération */ + + if (last) + { + assert(g_rw_lock_writer_trylock(&_pg_lock) == FALSE); + + pg_iface = g_plugin_module_get_interface(plugin); + + same = get_plugin_by_name(pg_iface->name, &index); + assert(same != NULL); + + _pg_list[index] = NULL; + + g_object_remove_toggle_ref(G_OBJECT(plugin), (GToggleNotify)on_plugin_ref_toggle, NULL); + + g_object_unref(G_OBJECT(same)); + } } @@ -406,6 +490,9 @@ GPluginModule *get_plugin_by_name(const char *name, size_t *index) for (i = 0; i < _pg_count && result == NULL; i++) { + /* Si on est en train de procéder à un nettoyage... */ + if (_pg_list[i] == NULL) continue; + pg_iface = g_plugin_module_get_interface(_pg_list[i]); if (strcmp(pg_iface->name, name) == 0) diff --git a/src/plugins/pglist.h b/src/plugins/pglist.h index c602839..b2635eb 100644 --- a/src/plugins/pglist.h +++ b/src/plugins/pglist.h @@ -77,7 +77,7 @@ GPluginModule **get_all_plugins_for_action(PluginAction, size_t *); for (__i = 0; __i < __count; __i++) \ { \ f(__list[__i], a, __VA_ARGS__); \ - g_object_ref(G_OBJECT(__list[__i])); \ + g_object_unref(G_OBJECT(__list[__i])); \ } \ if (__list != NULL) \ free(__list); \ diff --git a/src/plugins/plugin-def.h b/src/plugins/plugin-def.h index a497517..6bc2086 100644 --- a/src/plugins/plugin-def.h +++ b/src/plugins/plugin-def.h @@ -27,6 +27,7 @@ #include +#include #include @@ -295,6 +296,8 @@ typedef struct _plugin_interface const char *desc; /* Description plus loquace */ const char *version; /* Version du greffon */ + bool container; /* Mise en place de greffons ? */ + const char **required; /* Pré-chargements requis */ size_t required_count; /* Quantité de ces dépendances */ @@ -329,6 +332,26 @@ G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = { \ .desc = d, \ .version = v, \ \ + .container = false, \ + \ + r, \ + \ + a, \ + \ +} + +#define DEFINE_CHRYSALIDE_CONTAINER_PLUGIN(n, d, v, r, a) \ +G_MODULE_EXPORT const plugin_interface _chrysalide_plugin = { \ + \ + .magic = CHRYSALIDE_PLUGIN_MAGIC, \ + .abi_version = CURRENT_ABI_VERSION, \ + \ + .name = n, \ + .desc = d, \ + .version = v, \ + \ + .container = true, \ + \ r, \ \ a, \ diff --git a/src/plugins/plugin.c b/src/plugins/plugin.c index 58671b6..de9c953 100644 --- a/src/plugins/plugin.c +++ b/src/plugins/plugin.c @@ -117,6 +117,33 @@ static void g_plugin_module_init(GPluginModule *plugin) static void g_plugin_module_dispose(GPluginModule *plugin) { + const plugin_interface *pg_iface; /* Définition du greffon */ + size_t i; /* Boucle de parcours */ + GPluginModule *dependency; /* Module nécessaire */ + + pg_iface = g_plugin_module_get_interface(plugin); + + if (pg_iface != NULL) + { + lock_plugin_list_for_reading(); + + for (i = 0; i < pg_iface->required_count; i++) + { + dependency = get_plugin_by_name(pg_iface->required[i], NULL); + assert(dependency != NULL); + + /* Un coup pour l'appel à get_plugin_by_name(). */ + g_object_unref(G_OBJECT(dependency)); + + /* Un coup pour la dépendance */ + g_object_unref(G_OBJECT(dependency)); + + } + + unlock_plugin_list_for_reading(); + + } + if (plugin->exit != NULL) plugin->exit(plugin); @@ -235,16 +262,30 @@ GPluginModule *g_plugin_module_new(const gchar *filename) case DPS_NONE: break; - case PGA_PLUGIN_INIT: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_init", &result->init)) - goto bad_plugin; - break; + case DPS_PG_MANAGEMENT: + + switch (action) + { + case PGA_PLUGIN_INIT: + if (!load_plugin_symbol(result->module, + "chrysalide_plugin_init", &result->init)) + goto bad_plugin; + break; + + case PGA_PLUGIN_EXIT: + if (!load_plugin_symbol(result->module, + "chrysalide_plugin_exit", &result->exit)) + goto bad_plugin; + break; + + default: + log_variadic_message(LMT_WARNING, + _("Unknown action '0x%02x' in plugin '%s'..."), + result->interface->actions[i], filename); + break; + + } - case PGA_PLUGIN_EXIT: - if (!load_plugin_symbol(result->module, - "chrysalide_plugin_exit", &result->exit)) - goto bad_plugin; break; default: @@ -494,7 +535,12 @@ bool g_plugin_module_resolve_dependencies(GPluginModule *plugin, GPluginModule * set_in_bit_field(new, index, 1); or_bit_field(new, dependency->dependencies); - g_object_unref(G_OBJECT(dependency)); + /** + * Si la référence pour dépendance a déjà été prise. + */ + + if (test_in_bit_field(plugin->dependencies, index)) + g_object_unref(G_OBJECT(dependency)); } -- cgit v0.11.2-87-g4458