summaryrefslogtreecommitdiff
path: root/src/plugins/pglist.c
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2017-09-30 11:22:46 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2017-09-30 11:22:46 (GMT)
commitdb702d1243e6fec187137d48cecb89de17fefc3b (patch)
tree13776b4b75377951d9ebf9a57078ae1aed659cba /src/plugins/pglist.c
parent6ba73df8224dc2a88fe5f37a331960936758036e (diff)
Handled dependencies when loading plugins.
Diffstat (limited to 'src/plugins/pglist.c')
-rw-r--r--src/plugins/pglist.c289
1 files changed, 213 insertions, 76 deletions
diff --git a/src/plugins/pglist.c b/src/plugins/pglist.c
index 112a560..54c8784 100644
--- a/src/plugins/pglist.c
+++ b/src/plugins/pglist.c
@@ -32,40 +32,27 @@
#include <config.h>
+#include <i18n.h>
#include "plugin-int.h"
#include "../common/extstr.h"
-/* Représentation dédiée aux listes de greffons */
-typedef struct _pg_array
-{
- PluginAction action; /* Action commune ou PGA_ALL */
-
- GPluginModule **plugins; /* Liste de greffons */
- size_t plugins_count; /* Taille de cette liste */
-
-} pg_array;
-
-/* Propriétés de l'ensemble des greffons */
-typedef struct _plugins_list
-{
- pg_array *all; /* Liste de tous les greffons */
- pg_array sorted[PGA_COUNT]; /* Tri par catégories */
-
-} plugins_list;
-
/* Liste de l'ensemble des greffons */
-static plugins_list _list;
+static GPluginModule **_pg_list = NULL;
+static size_t _pg_count = 0;
+
+/* Accès à cette liste */
+static GRWLock _pg_lock;
/* Filtre les répertoire et les modules de greffons pootentels. */
-int filter_dirs_or_mods(const struct dirent *);
+static int filter_dirs_or_mods(const struct dirent *);
/* Part à la recherche de greffons sous forme de modules. */
-void browse_directory_for_plugins(plugins_list *, const char *);
+static void browse_directory_for_plugins(const char *);
@@ -83,15 +70,11 @@ void browse_directory_for_plugins(plugins_list *, const char *);
bool init_all_plugins(void)
{
- size_t i; /* Boucle de parcours */
+ g_rw_lock_init(&_pg_lock);
- for (i = 0; i < PGA_COUNT; i++)
- _list.sorted[i].action = PGA_EMPTY;
+ browse_directory_for_plugins(PACKAGE_SOURCE_DIR "/plugins");
- _list.sorted[0].action = PGA_ALL;
- _list.all = &_list.sorted[0];
-
- browse_directory_for_plugins(&_list, PACKAGE_SOURCE_DIR "/plugins");
+ load_remaning_plugins();
return true;
@@ -114,11 +97,16 @@ void exit_all_plugins(void)
{
size_t i; /* Boucle de parcours */
- for (i = 0; i < _list.all->plugins_count; i++)
- g_object_unref(_list.all->plugins[i]);
+ if (_pg_list != NULL)
+ {
+ for (i = 0; i < _pg_count; i++)
+ g_object_unref(_pg_list[i]);
+
+ free(_pg_list);
+
+ }
- for (i = 0; i < PGA_COUNT; i++)
- free(_list.sorted[i].plugins);
+ g_rw_lock_clear(&_pg_lock);
}
@@ -135,7 +123,7 @@ void exit_all_plugins(void)
* *
******************************************************************************/
-int filter_dirs_or_mods(const struct dirent *entry)
+static int filter_dirs_or_mods(const struct dirent *entry)
{
int result; /* Conclusion à remonter */
@@ -152,8 +140,7 @@ int filter_dirs_or_mods(const struct dirent *entry)
/******************************************************************************
* *
-* Paramètres : list = liste de greffons à compléter si possible. *
-* dir = répertoire à parcourir en quête de greffons (sans /). *
+* Paramètres : dir = répertoire à parcourir en quête de greffons (sans /). *
* *
* Description : Part à la recherche de greffons sous forme de modules. *
* *
@@ -163,7 +150,7 @@ int filter_dirs_or_mods(const struct dirent *entry)
* *
******************************************************************************/
-void browse_directory_for_plugins(plugins_list *list, const char *dir)
+static void browse_directory_for_plugins(const char *dir)
{
struct dirent **namelist; /* Eléments trouvés */
int ret; /* Bilan du parcours */
@@ -186,14 +173,14 @@ void browse_directory_for_plugins(plugins_list *list, const char *dir)
strcat(filename, namelist[ret]->d_name);
if (namelist[ret]->d_type == DT_DIR)
- browse_directory_for_plugins(list, filename);
+ browse_directory_for_plugins(filename);
else
{
plugin = g_plugin_module_new(filename);
if (plugin != NULL)
- add_plugin_to_main_list(plugin);
+ register_plugin(plugin);
}
@@ -209,34 +196,57 @@ void browse_directory_for_plugins(plugins_list *list, const char *dir)
/******************************************************************************
* *
-* Paramètres : action = fonctionnalité recherchée. *
-* count = nombre de greffons trouvés. [OUT] *
+* Paramètres : plugin = greffon à ajouter aux autres disponibles. *
* *
-* Description : Founit les greffons offrant le service demandé. *
+* Description : Ajoute un greffon à la liste principale de greffons. *
* *
-* Retour : Liste de greffons correspondants issue d'un tri interne. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-const GPluginModule **get_all_plugins_for_action(PluginAction action, size_t *count)
+void _register_plugin(GPluginModule *plugin)
{
- const GPluginModule **result; /* Greffon à retourner */
size_t i; /* Boucle de parcours */
+ const plugin_interface *pg_iface; /* Informations à consulter */
+ const char *name; /* Désignation du greffon */
- result = NULL;
- *count = 0;
+ /**
+ * L'appel sans verrou n'est fourni que pour les greffons
+ * mettant en place des greffons en interne !
+ */
- for (i = 0; i < PGA_COUNT; i++)
- if (_list.sorted[i].action == action)
+ /* Recherche d'un éventuel doublon */
+
+ pg_iface = g_plugin_module_get_interface(plugin);
+
+ name = pg_iface->name;
+
+ for (i = 0; i < _pg_count; i++)
+ {
+ pg_iface = g_plugin_module_get_interface(_pg_list[i]);
+
+ if (strcmp(name, pg_iface->name) == 0)
{
- result = (const GPluginModule **)_list.sorted[i].plugins;
- *count = _list.sorted[i].plugins_count;
+ log_variadic_message(LMT_ERROR,
+ _("Plugin '%s' already registered!"), name);
+
break;
+
}
- return result;
+ }
+
+ /* Ajout du greffon à la liste */
+
+ if (i == _pg_count)
+ {
+ _pg_list = (GPluginModule **)realloc(_pg_list, ++_pg_count * sizeof(GPluginModule));
+
+ _pg_list[_pg_count - 1] = plugin;
+
+ }
}
@@ -253,52 +263,179 @@ const GPluginModule **get_all_plugins_for_action(PluginAction action, size_t *co
* *
******************************************************************************/
-void add_plugin_to_main_list(GPluginModule *plugin)
+void register_plugin(GPluginModule *plugin)
{
- const plugin_interface *interface; /* Informations à consulter */
- size_t i; /* Boucle de parcours #1 */
- size_t j; /* Boucle de parcours #2 */
+ g_rw_lock_writer_lock(&_pg_lock);
+
+ _register_plugin(plugin);
+
+ g_rw_lock_writer_unlock(&_pg_lock);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Charge tous les greffons restant à charger. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
- interface = g_plugin_module_get_interface(plugin);
+void load_remaning_plugins(void)
+{
+ bool changed; /* Variation de dépendances */
+ size_t i; /* Boucle de parcours */
+ PluginStatusFlags flags; /* Fanions de greffon */
+
+ g_rw_lock_reader_lock(&_pg_lock);
- void add_plugin_into_array(pg_array *array, GPluginModule *pg)
+ /* Etablit la liste de toutes les dépendances */
+
+ do
{
- array->plugins = (GPluginModule **)realloc(array->plugins,
- ++array->plugins_count * sizeof(GPluginModule));
+ changed = false;
- array->plugins[array->plugins_count - 1] = pg;
+ for (i = 0; i < _pg_count; i++)
+ changed |= g_plugin_module_resolve_dependencies(_pg_list[i], _pg_list, _pg_count);
}
+ while (changed);
- /* FIXME : lock */
+ /* Effectue les chargements possibles */
- add_plugin_into_array(_list.all, plugin);
+ for (i = 0; i < _pg_count; i++)
+ {
+ flags = g_plugin_module_get_flags(_pg_list[i]);
- for (i = 0; i < interface->actions_count; i++)
+ if ((flags & (BROKEN_PLUGIN_STATUS | PSF_LOADED)) == 0)
+ g_plugin_module_load(_pg_list[i], _pg_list, _pg_count);
+
+ }
+
+ /* Supprime les greffons non chargés */
+
+ for (i = 0; i < _pg_count; i++)
{
- if (interface->actions[i] == PGA_ALL) continue;
+ flags = g_plugin_module_get_flags(_pg_list[i]);
- for (j = 1; j < PGA_COUNT; j++)
+ if ((flags & PSF_LOADED) == 0)
{
- if (_list.sorted[j].action == interface->actions[i])
- {
- add_plugin_into_array(&_list.sorted[j], plugin);
- break;
- }
+ g_object_unref(G_OBJECT(_pg_list[i]));
+
+ memmove(&_pg_list[i], &_pg_list[i + 1], (_pg_count - i - 1) * sizeof(GPluginModule *));
+ _pg_count--;
- else if (_list.sorted[j].action == PGA_EMPTY)
+ }
+
+ }
+
+ g_rw_lock_reader_unlock(&_pg_lock);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : name = désignation du greffon recherché. *
+* index = indice du greffon trouvé. [OUT] *
+* *
+* Description : Founit le greffon répondant à un nom donné. *
+* *
+* Retour : Instance du greffon trouvé ou NULL si aucun. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GPluginModule *get_plugin_by_name(const char *name, size_t *index)
+{
+ GPluginModule *result; /* Greffon trouvé à renvoyer */
+ size_t i; /* Boucle de parcours */
+ const plugin_interface *pg_iface; /* Vitrine d'un greffon */
+
+ result = NULL;
+
+ /**
+ * L'accès à la liste doit être encadré.
+ */
+ assert(g_rw_lock_writer_trylock(&_pg_lock) == FALSE);
+
+ for (i = 0; i < _pg_count && result == NULL; i++)
+ {
+ pg_iface = g_plugin_module_get_interface(_pg_list[i]);
+
+ if (strcmp(pg_iface->name, name) == 0)
+ {
+ result = _pg_list[i];
+
+ if (index != NULL)
+ *index = i;
+
+ }
+
+ }
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : action = fonctionnalité recherchée. *
+* count = nombre de greffons trouvés. [OUT] *
+* *
+* Description : Founit les greffons offrant le service demandé. *
+* *
+* Retour : Liste de greffons correspondants issue d'un tri interne. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GPluginModule **get_all_plugins_for_action(PluginAction action, size_t *count)
+{
+ GPluginModule **result; /* Liste à retourner */
+ const plugin_interface *pg_iface; /* Informations à consulter */
+ size_t i; /* Boucle de parcours #1 */
+ size_t j; /* Boucle de parcours #2 */
+
+ result = NULL;
+ *count = 0;
+
+ g_rw_lock_reader_lock(&_pg_lock);
+
+ for (i = 0; i < _pg_count; i++)
+ {
+ pg_iface = g_plugin_module_get_interface(_pg_list[i]);
+
+ for (j = 0; j < pg_iface->actions_count; j++)
+ {
+ if (pg_iface->actions[j] == action)
{
- add_plugin_into_array(&_list.sorted[j], plugin);
- _list.sorted[j].action = interface->actions[i];
+ result = (GPluginModule **)realloc(result, ++(*count) * sizeof(GPluginModule *));
+
+ result[*count - 1] = _pg_list[i];
+ g_object_ref(G_OBJECT(_pg_list[i]));
+
break;
+
}
}
- assert(j < PGA_COUNT);
-
}
- /* FIXME : lock */
+ g_rw_lock_reader_unlock(&_pg_lock);
+
+ return result;
}