diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2018-07-23 18:57:49 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2018-07-23 19:01:46 (GMT) |
commit | abefe01dd260cddbd253ba0c03d9c903138c71c1 (patch) | |
tree | 834f683e79893534324af94c537984542b7dc00a /src/plugins | |
parent | 50eb8c462e7ad2b4e5b82d27b1af6e86091ea272 (diff) |
Tracked the reference counter for plugins with more care.
Diffstat (limited to 'src/plugins')
-rw-r--r-- | src/plugins/pglist.c | 87 | ||||
-rw-r--r-- | src/plugins/pglist.h | 2 | ||||
-rw-r--r-- | src/plugins/plugin-def.h | 23 | ||||
-rw-r--r-- | src/plugins/plugin.c | 66 |
4 files changed, 167 insertions, 11 deletions
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 <gmodule.h> +#include <stdbool.h> #include <stdint.h> @@ -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)); } |