From 286878b36b5cf7a3f44251f62c94a57f0f29d3cf Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Wed, 9 May 2018 12:58:31 +0200
Subject: Handled the global work queue groups in a better way.

---
 src/analysis/loaded.c     |   1 +
 src/core/Makefile.am      |   3 +-
 src/core/core.c           |   7 +--
 src/core/queue.c          | 115 ++++++++++++++++++++++++++++++++++++++++++++++
 src/core/queue.h          |  52 +++++++++++++++++++++
 src/glibext/delayed.c     |  74 +++++++++++++----------------
 src/glibext/delayed.h     |   5 +-
 src/gui/panels/updating.c |   1 +
 src/main.c                |   3 +-
 9 files changed, 211 insertions(+), 50 deletions(-)
 create mode 100644 src/core/queue.c
 create mode 100644 src/core/queue.h

diff --git a/src/analysis/loaded.c b/src/analysis/loaded.c
index 1273ebd..5dd96a8 100644
--- a/src/analysis/loaded.c
+++ b/src/analysis/loaded.c
@@ -29,6 +29,7 @@
 
 #include "loaded-int.h"
 #include "../core/global.h"
+#include "../core/queue.h"
 #include "../glibext/chrysamarshal.h"
 #include "../glibext/gloadedpanel.h"
 
diff --git a/src/core/Makefile.am b/src/core/Makefile.am
index 6e3132d..7acadea 100755
--- a/src/core/Makefile.am
+++ b/src/core/Makefile.am
@@ -9,7 +9,8 @@ libcore_la_SOURCES =					\
 	global.h global.c					\
 	logs.h logs.c						\
 	params.h params.c					\
-	processors.h processors.c
+	processors.h processors.c			\
+	queue.h queue.c
 
 libcore_la_LDFLAGS = $(LIBGTK_LIBS) $(LIBXML_LIBS)
 
diff --git a/src/core/core.c b/src/core/core.c
index 1b6b033..5e3a4d0 100644
--- a/src/core/core.c
+++ b/src/core/core.c
@@ -39,6 +39,7 @@
 #include "global.h"
 #include "params.h"
 #include "processors.h"
+#include "queue.h"
 #include "../analysis/db/keymgn.h"
 #include "../common/io.h"
 #include "../common/xdg.h"
@@ -63,7 +64,6 @@ bool load_all_basic_components(void)
 {
     static bool result = false;             /* Bilan à retourner           */
     char *cfgdir;                           /* Répertoire de configuration */
-    GWorkQueue *queue;                      /* Singleton pour tâches       */
     GContentExplorer *explorer;             /* Explorateur de contenus     */
     GContentResolver *resolver;             /* Résolveur de contenus       */
 
@@ -96,8 +96,7 @@ bool load_all_basic_components(void)
 
         result &= g_generic_config_read(get_main_configuration());
 
-        queue = g_work_queue_new();
-        set_work_queue(queue);
+        result &= init_global_works();
 
         explorer = g_content_explorer_new();
         set_current_content_explorer(explorer);
@@ -142,6 +141,8 @@ void unload_all_basic_components(void)
 
     unload_processors_definitions();
 
+    exit_global_works();
+
     g_generic_config_write(get_main_configuration());
 
     unload_main_config_parameters();
diff --git a/src/core/queue.c b/src/core/queue.c
new file mode 100644
index 0000000..615e351
--- /dev/null
+++ b/src/core/queue.c
@@ -0,0 +1,115 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * queue.c - mise en place des mécanismes de traitements parallèles
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "queue.h"
+
+
+#include <assert.h>
+
+
+#include "global.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Met en place les mécanismes de traitements parallèles.       *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool init_global_works(void)
+{
+    GWorkQueue *queue;                      /* Singleton pour tâches       */
+#ifndef NDEBUG
+    wgroup_id_t expected;                   /* Identifiant gloabl attendu  */
+#endif
+
+    queue = g_work_queue_new();
+    set_work_queue(queue);
+
+#ifndef NDEBUG
+    expected = g_work_queue_define_work_group(queue);
+    assert(expected == DEFAULT_WORK_GROUP);
+#else
+    g_work_queue_define_work_group(queue);
+#endif
+
+    return true;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Supprime les mécanismes de traitements parallèles.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void exit_global_works(void)
+{
+    GWorkQueue *queue;                      /* Singleton pour tâches       */
+
+    queue = get_work_queue();
+
+    g_object_unref(G_OBJECT(queue));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Attend que toutes les tâches de tout groupe soient traitées. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void wait_for_all_global_works(void)
+{
+    GWorkQueue *queue;                      /* Singleton pour tâches       */
+
+    static const wgroup_id_t group_ids[] = {
+        DEFAULT_WORK_GROUP
+    };
+
+    queue = get_work_queue();
+
+    g_work_queue_wait_for_all_completions(queue, group_ids, GLOBAL_WORK_GROUPS_COUNT);
+
+}
diff --git a/src/core/queue.h b/src/core/queue.h
new file mode 100644
index 0000000..1984fff
--- /dev/null
+++ b/src/core/queue.h
@@ -0,0 +1,52 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * queue.h - prototypes pour la mise en place des mécanismes de traitements parallèles
+ *
+ * Copyright (C) 2018 Cyrille Bagard
+ *
+ *  This file is part of Chrysalide.
+ *
+ *  Chrysalide is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  Chrysalide is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _CORE_QUEUE_H
+#define _CORE_QUEUE_H
+
+
+#include <stdbool.h>
+
+
+
+/**
+ * Groupes d'exécution principaux.
+ */
+
+#define DEFAULT_WORK_GROUP 0
+
+#define GLOBAL_WORK_GROUPS_COUNT 1
+
+
+/* Met en place les mécanismes de traitements parallèles. */
+bool init_global_works(void);
+
+/* Supprime les mécanismes de traitements parallèles. */
+void exit_global_works(void);
+
+/* Attend que toutes les tâches de tout groupe soient traitées. */
+void wait_for_all_global_works(void);
+
+
+
+#endif  /* _CORE_QUEUE_H */
diff --git a/src/glibext/delayed.c b/src/glibext/delayed.c
index 9d67a7c..9bac68a 100644
--- a/src/glibext/delayed.c
+++ b/src/glibext/delayed.c
@@ -175,7 +175,7 @@ static void g_work_queue_dispose(GWorkQueue *);
 static void g_work_queue_finalize(GWorkQueue *);
 
 /* Donne l'assurance de l'existence d'un groupe de travail. */
-static GWorkGroup *g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t);
+static bool g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t);
 
 /* Fournit le groupe de travail correspondant à un identifiant. */
 static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *, wgroup_id_t);
@@ -682,13 +682,11 @@ static bool g_work_group_is_empty(GWorkGroup *group)
      * son utilisation par l'appelant.
      *
      * Il doit donc logiquement y avoir un autre verrou en amont et,
-     * comme à priori on ne devrait pas bloquer le groupe principal
-     * pour un traitement particulier, on ajoute ici une simple vérification
-     * de bonne pratique.
+     * comme à priori on ne devrait pas bloquer les groupes principaux
+     * pour un traitement particulier, cette procédure ne devrait concerner
+     * que des groupes dynamiques.
      */
 
-    assert(group->id != DEFAULT_WORK_GROUP);
-
     g_mutex_lock(&group->mutex);
 
     result = dl_list_empty(group->works);
@@ -936,24 +934,26 @@ GWorkQueue *g_work_queue_new(void)
 *                                                                             *
 *  Description : Donne l'assurance de l'existence d'un groupe de travail.     *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : true si un nouveau groupe a été constitué, false sinon.      *
 *                                                                             *
 *  Remarques   : Le verrou d'accès doit être posé par l'appelant.             *
 *                                                                             *
 ******************************************************************************/
 
-static GWorkGroup *g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id)
+static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id)
 {
-    GWorkGroup *result;                     /* Groupe en place à renvoyer  */
     bool found;                             /* Bilan des recherches        */
     size_t i;                               /* Boucle de parcours          */
+    GWorkGroup *group;                      /* Groupe à consulter          */
+
+    assert(!g_mutex_trylock(&queue->mutex));
 
     found = false;
 
     for (i = 0; i < queue->groups_count && !found; i++)
     {
-        result = queue->groups[i];
-        found = (g_work_group_get_id(result) == id);
+        group = queue->groups[i];
+        found = (g_work_group_get_id(group) == id);
     }
 
     if (!found)
@@ -962,12 +962,12 @@ static GWorkGroup *g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id
         queue->groups = (GWorkGroup **)realloc(queue->groups,
                                                queue->groups_count * sizeof(GWorkGroup *));
 
-        result = g_work_group_new(id);
-        queue->groups[queue->groups_count - 1] = result;
+        group = g_work_group_new(id);
+        queue->groups[queue->groups_count - 1] = group;
 
     }
 
-    return result;
+    return !found;
 
 }
 
@@ -987,12 +987,16 @@ static GWorkGroup *g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id
 wgroup_id_t g_work_queue_define_work_group(GWorkQueue *queue)
 {
     wgroup_id_t result;                     /* Valeur à retourner          */
+    bool created;                           /* Bilan d'une tentative       */
 
     g_mutex_lock(&queue->mutex);
 
-    result = ++queue->generator;
-
-    g_work_queue_ensure_group_exists(queue, result);
+    do
+    {
+        result = queue->generator++;
+        created = g_work_queue_ensure_group_exists(queue, result);
+    }
+    while (!created);
 
     g_mutex_unlock(&queue->mutex);
 
@@ -1072,13 +1076,8 @@ void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work, wgroup_id
 {
     GWorkGroup *group;                      /* Groupe de travail à attendre*/
 
-    g_mutex_lock(&queue->mutex);
-
-    group = g_work_queue_ensure_group_exists(queue, id);
-
-    g_object_ref(G_OBJECT(group));
-
-    g_mutex_unlock(&queue->mutex);
+    group = g_work_queue_find_group_for_id(queue, id);
+    assert(group != NULL);
 
     g_work_group_schedule(group, work);
 
@@ -1188,7 +1187,9 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : queue = gestionnaire de l'ensemble des groupes de travail.   *
+*  Paramètres  : queue    = gestionnaire de l'ensemble des groupes de travail.*
+*                gb_ids   = identifiants de groupes globaux.                  *
+*                gb_count = nombre de ces groupes globaux.                    *
 *                                                                             *
 *  Description : Attend que toutes les tâches de tout groupe soient traitées. *
 *                                                                             *
@@ -1198,36 +1199,29 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)
 *                                                                             *
 ******************************************************************************/
 
-void g_work_queue_wait_for_all_completions(GWorkQueue *queue)
+void g_work_queue_wait_for_all_completions(GWorkQueue *queue, const wgroup_id_t *gb_ids, size_t gb_count)
 {
-    GWorkGroup *def_group;                  /* Groupe de travail par défaut*/
+    size_t i;                               /* Boucle de parcours          */
 
     g_mutex_lock(&queue->mutex);
 
-    /**
-     * Récupération du groupe par défaut.
-     */
-
-    def_group = g_work_queue_ensure_group_exists(queue, DEFAULT_WORK_GROUP);
-
-    g_object_ref(G_OBJECT(def_group));
-
  wait_again:
 
     /**
      * Attente d'éventuels groupes isolés.
      */
 
-    while (queue->groups_count > 1)
+    while (queue->groups_count > gb_count)
         g_cond_wait(&queue->wait_all, &queue->mutex);
 
     g_mutex_unlock(&queue->mutex);
 
     /**
-     * Attente du groupe principal.
+     * Attente des groupes principaux.
      */
 
-    g_work_queue_wait_for_completion(queue, DEFAULT_WORK_GROUP);
+    for (i = 0; i < gb_count; i++)
+        g_work_queue_wait_for_completion(queue, gb_ids[i]);
 
     /**
      * Si le groupe par défaut a généré de nouveaux groupes, on recommence !
@@ -1235,13 +1229,11 @@ void g_work_queue_wait_for_all_completions(GWorkQueue *queue)
 
     g_mutex_lock(&queue->mutex);
 
-    if (queue->groups_count > 1)
+    if (queue->groups_count > gb_count)
         goto wait_again;
 
     g_mutex_unlock(&queue->mutex);
 
-    g_object_unref(G_OBJECT(def_group));
-
 }
 
 
diff --git a/src/glibext/delayed.h b/src/glibext/delayed.h
index 340a298..c22cc5a 100644
--- a/src/glibext/delayed.h
+++ b/src/glibext/delayed.h
@@ -82,9 +82,6 @@ typedef struct _GWorkQueueClass GWorkQueueClass;
 /* Identifiant unique pour groupe de travail */
 typedef unsigned long long wgroup_id_t;
 
-/* Groupe d'exécution par défaut */
-#define DEFAULT_WORK_GROUP 0
-
 
 /* Indique le type défini pour le gestionnaire des travaux différés. */
 GType g_work_queue_get_type(void);
@@ -108,7 +105,7 @@ bool g_work_queue_is_empty(GWorkQueue *, wgroup_id_t);
 void g_work_queue_wait_for_completion(GWorkQueue *, wgroup_id_t);
 
 /* Attend que toutes les tâches de tout groupe soient traitées. */
-void g_work_queue_wait_for_all_completions(GWorkQueue *);
+void g_work_queue_wait_for_all_completions(GWorkQueue *, const wgroup_id_t *, size_t);
 
 
 /* Etudie le besoin d'attendre d'avantage de prochaines tâches. */
diff --git a/src/gui/panels/updating.c b/src/gui/panels/updating.c
index 800161c..824898a 100644
--- a/src/gui/panels/updating.c
+++ b/src/gui/panels/updating.c
@@ -29,6 +29,7 @@
 
 #include "updating-int.h"
 #include "../../core/global.h"
+#include "../../core/queue.h"
 #include "../../glibext/delayed-int.h"
 #include "../../glibext/signal.h"
 
diff --git a/src/main.c b/src/main.c
index 018651a..583e00c 100644
--- a/src/main.c
+++ b/src/main.c
@@ -39,6 +39,7 @@
 #include "core/global.h"
 #include "core/logs.h"
 #include "core/params.h"
+#include "core/queue.h"
 #include "glibext/delayed.h"
 #include "gui/editor.h"
 #include "gui/core/core.h"
@@ -343,7 +344,7 @@ int main(int argc, char **argv)
     result = open_binaries(argv + optind, argc - optind);
 
     if (batch_mode)
-        g_work_queue_wait_for_all_completions(get_work_queue());
+        wait_for_all_global_works();
 
     else
         gtk_main();
-- 
cgit v0.11.2-87-g4458