summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2015-11-11 21:00:05 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2015-11-11 21:00:05 (GMT)
commit0727204e36e919f06e80181482981c3f19669d76 (patch)
treeada49befbc7d91d21623f5221a2f7001d4b741a2 /src
parentdc49b249f21c1c8582b9ca8debdd5fbdd15eadae (diff)
Prepared the next generation of parallel processings.
git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@606 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a
Diffstat (limited to 'src')
-rw-r--r--src/analysis/disass/disassembler.c8
-rw-r--r--src/analysis/project.c8
-rw-r--r--src/glibext/configuration.c2
-rw-r--r--src/glibext/delayed-int.h4
-rw-r--r--src/glibext/delayed.c499
-rw-r--r--src/glibext/delayed.h18
-rw-r--r--src/glibext/gcodebuffer.c8
-rw-r--r--src/gtkext/gtkextstatusbar.c2
8 files changed, 453 insertions, 96 deletions
diff --git a/src/analysis/disass/disassembler.c b/src/analysis/disass/disassembler.c
index 990ab0f..2f9d293 100644
--- a/src/analysis/disass/disassembler.c
+++ b/src/analysis/disass/disassembler.c
@@ -116,6 +116,11 @@ G_DEFINE_TYPE(GDelayedDisassembly, g_delayed_disassembly, G_TYPE_DELAYED_WORK);
static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *klass)
{
+ GDelayedWorkClass *work; /* Version en classe parente */
+
+ work = G_DELAYED_WORK_CLASS(klass);
+
+ work->run = (run_task_fc)g_delayed_disassembly_process;
}
@@ -134,7 +139,6 @@ static void g_delayed_disassembly_class_init(GDelayedDisassemblyClass *klass)
static void g_delayed_disassembly_init(GDelayedDisassembly *disass)
{
- G_DELAYED_WORK(disass)->run = (run_task_fc)g_delayed_disassembly_process;
}
@@ -711,6 +715,6 @@ void disassemble_binary(GLoadedBinary *binary, GArchInstruction **instrs, GCodeB
g_signal_connect(disass, "work-completed", G_CALLBACK(ack), binary);
queue = get_work_queue();
- g_work_queue_schedule_work(queue, G_DELAYED_WORK(disass));
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(disass), DEFAULT_WORK_GROUP);
}
diff --git a/src/analysis/project.c b/src/analysis/project.c
index 8fef602..ed60929 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -971,12 +971,16 @@ G_DEFINE_TYPE(GDelayedStudy, g_delayed_study, G_TYPE_DELAYED_WORK);
static void g_delayed_study_class_init(GDelayedStudyClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
+ GDelayedWorkClass *work; /* Version en classe parente */
object = G_OBJECT_CLASS(klass);
+ work = G_DELAYED_WORK_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_study_dispose;
object->finalize = (GObjectFinalizeFunc)g_delayed_study_finalize;
+ work->run = (run_task_fc)g_delayed_study_process;
+
}
@@ -994,8 +998,6 @@ static void g_delayed_study_class_init(GDelayedStudyClass *klass)
static void g_delayed_study_init(GDelayedStudy *dstudy)
{
- G_DELAYED_WORK(dstudy)->run = (run_task_fc)g_delayed_study_process;
-
dstudy->only_preload = false;
}
@@ -1210,6 +1212,6 @@ void study_new_content(GDelayedStudy *dstudy)
GWorkQueue *queue; /* Gestionnaire de différés */
queue = get_work_queue();
- g_work_queue_schedule_work(queue, G_DELAYED_WORK(dstudy));
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(dstudy), DEFAULT_WORK_GROUP);
}
diff --git a/src/glibext/configuration.c b/src/glibext/configuration.c
index 3becaaa..8717fb4 100644
--- a/src/glibext/configuration.c
+++ b/src/glibext/configuration.c
@@ -80,7 +80,7 @@ struct _GCfgParamClass
/* Signaux */
- void (*modified) (GCfgParam *);
+ void (* modified) (GCfgParam *);
};
diff --git a/src/glibext/delayed-int.h b/src/glibext/delayed-int.h
index acef7d7..ecd9b4e 100644
--- a/src/glibext/delayed-int.h
+++ b/src/glibext/delayed-int.h
@@ -43,8 +43,6 @@ struct _GDelayedWork
DL_LIST_ITEM(link); /* Lien vers les maillons */
- run_task_fc run; /* Traitement externalisé */
-
bool completed; /* Fin de la tâche ? */
GMutex mutex; /* Accès à la variable */
GCond cond; /* Attente de changement */
@@ -56,6 +54,8 @@ struct _GDelayedWorkClass
{
GObjectClass parent; /* A laisser en premier */
+ run_task_fc run; /* Traitement externalisé */
+
/* Signaux */
void (* work_completed) (GDelayedWork *);
diff --git a/src/glibext/delayed.c b/src/glibext/delayed.c
index 32a3d16..967865b 100644
--- a/src/glibext/delayed.c
+++ b/src/glibext/delayed.c
@@ -24,7 +24,10 @@
#include "delayed.h"
+#include <assert.h>
#include <malloc.h>
+#include <stdio.h>
+#include <string.h>
#include "delayed-int.h"
@@ -54,62 +57,71 @@ static void g_delayed_work_process(GDelayedWork *, GtkExtStatusBar *);
/* -------------------------- THREAD DE TRAITEMENTS DEDIES -------------------------- */
-#define G_TYPE_TYPED_QUEUE g_typed_queue_get_type()
-#define G_TYPED_QUEUE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_typed_queue_get_type(), GTypedQueue))
-#define G_IS_TYPED_QUEUE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_typed_queue_get_type()))
-#define G_TYPED_QUEUE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_TYPED_QUEUE, GTypedQueueClass))
-#define G_IS_TYPED_QUEUE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_TYPED_QUEUE))
-#define G_TYPED_QUEUE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_TYPED_QUEUE, GTypedQueueClass))
+#define G_TYPE_WORK_GROUP g_work_group_get_type()
+#define G_WORK_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), g_work_group_get_type(), GWorkGroup))
+#define G_IS_WORK_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), g_work_group_get_type()))
+#define G_WORK_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_WORK_GROUP, GWorkGroupClass))
+#define G_IS_WORK_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_WORK_GROUP))
+#define G_WORK_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_WORK_GROUP, GWorkGroupClass))
/* File de traitement pour un type donné (instance) */
-typedef struct _GTypedQueue
+typedef struct _GWorkGroup
{
GObject parent; /* A laisser en premier */
- GType type; /* Type de travaux menés */
+ wgroup_id_t id; /* Identifiant de travaux menés*/
GtkExtStatusBar *statusbar; /* Barre de statut principale */
GDelayedWork *works; /* Tâches à mener à bien */
GMutex mutex; /* Verrou pour l'accès */
GCond cond; /* Réveil pour un traitement */
+ GCond wait_cond; /* Réveil d'attente de fin */
- GThread *thread; /* Procédure de traitement */
+ GThread **threads; /* Procédure de traitement */
+ guint threads_count; /* Nombre de procédures */
+ bool force_exit; /* Procédure d'arrêt */
-} GTypedQueue;
+} GWorkGroup;
/* File de traitement pour un type donné (classe) */
-typedef struct _GTypedQueueClass
+typedef struct _GWorkGroupClass
{
GObjectClass parent; /* A laisser en premier */
-} GTypedQueueClass;
+} GWorkGroupClass;
-/* Indique le type défini pour les travaux typés. */
-static GType g_typed_queue_get_type(void);
+/* Indique le type défini pour les groupes de travail. */
+static GType g_work_group_get_type(void);
-/* Initialise la classe des travaux typés. */
-static void g_typed_queue_class_init(GTypedQueueClass *);
+/* Initialise la classe des groupes de travail. */
+static void g_work_group_class_init(GWorkGroupClass *);
-/* Initialise une instance de gestionnaire de travaux typés. */
-static void g_typed_queue_init(GTypedQueue *);
+/* Initialise une instance de groupe de travail. */
+static void g_work_group_init(GWorkGroup *);
/* Supprime toutes les références externes. */
-static void g_typed_queue_dispose(GTypedQueue *);
+static void g_work_group_dispose(GWorkGroup *);
/* Procède à la libération totale de la mémoire. */
-static void g_typed_queue_finalize(GTypedQueue *);
+static void g_work_group_finalize(GWorkGroup *);
/* Crée un nouveau thread dédié à un type de travaux donné. */
-static GTypedQueue *g_typed_queue_new(GType, GtkExtStatusBar *);
+static GWorkGroup *g_work_group_new(wgroup_id_t, GtkExtStatusBar *);
+
+/* Fournit l'identifiant associé à un groupe de travail. */
+static wgroup_id_t g_work_group_get_id(const GWorkGroup *);
/* Place une nouvelle tâche en attente dans une file dédiée. */
-static void g_typed_queue_schedule(GTypedQueue *, GDelayedWork *);
+static void g_work_group_schedule(GWorkGroup *, GDelayedWork *);
/* Assure le traitement en différé. */
-static void *g_typed_queue_process(GTypedQueue *);
+static void *g_work_group_process(GWorkGroup *);
+
+/* Attend que toutes les tâches d'un groupe soient traitées. */
+static void g_work_group_wait_for_completion(GWorkGroup *);
@@ -123,8 +135,11 @@ struct _GWorkQueue
GtkExtStatusBar *statusbar; /* Barre de statut principale */
- GTypedQueue **threads; /* Files de traitement */
- size_t threads_count; /* Nombre de files internes */
+ wgroup_id_t generator; /* Générateur d'identifiants */
+
+ GWorkGroup **groups; /* Files de traitement */
+ size_t groups_count; /* Nombre de files internes */
+ GMutex mutex; /* Verrou pour l'accès */
};
@@ -142,6 +157,15 @@ static void g_work_queue_class_init(GWorkQueueClass *);
/* Initialise une instance de gestionnaire de travaux différés. */
static void g_work_queue_init(GWorkQueue *);
+/* Supprime toutes les références externes. */
+static void g_work_queue_dispose(GWorkQueue *);
+
+/* Procède à la libération totale de la mémoire. */
+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);
+
/* ---------------------------------------------------------------------------------- */
@@ -262,7 +286,7 @@ static void g_delayed_work_finalize(GDelayedWork *work)
static void g_delayed_work_process(GDelayedWork *work, GtkExtStatusBar *statusbar)
{
- work->run(work, statusbar);
+ G_DELAYED_WORK_GET_CLASS(work)->run(work, statusbar);
g_mutex_lock(&work->mutex);
@@ -302,19 +326,19 @@ void g_delayed_work_wait_for_completion(GDelayedWork *work)
/* ---------------------------------------------------------------------------------- */
-/* THREAD DE TRAITEMENTS DEDIES */
+/* THREADS DES TRAITEMENTS DEDIES */
/* ---------------------------------------------------------------------------------- */
-/* Indique le type défini pour les travaux typés. */
-G_DEFINE_TYPE(GTypedQueue, g_typed_queue, G_TYPE_OBJECT);
+/* Indique le type défini pour les groupes de travail. */
+G_DEFINE_TYPE(GWorkGroup, g_work_group, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
-* Description : Initialise la classe des travaux typés. *
+* Description : Initialise la classe des groupes de travail. *
* *
* Retour : - *
* *
@@ -322,23 +346,23 @@ G_DEFINE_TYPE(GTypedQueue, g_typed_queue, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_typed_queue_class_init(GTypedQueueClass *klass)
+static void g_work_group_class_init(GWorkGroupClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_typed_queue_dispose;
- object->finalize = (GObjectFinalizeFunc)g_typed_queue_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_work_group_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_work_group_finalize;
}
/******************************************************************************
* *
-* Paramètres : queue = instance à initialiser. *
+* Paramètres : group = instance à initialiser. *
* *
-* Description : Initialise une instance de gestionnaire de travaux typés. *
+* Description : Initialise une instance de groupe de travail. *
* *
* Retour : - *
* *
@@ -346,18 +370,36 @@ static void g_typed_queue_class_init(GTypedQueueClass *klass)
* *
******************************************************************************/
-static void g_typed_queue_init(GTypedQueue *queue)
+static void g_work_group_init(GWorkGroup *group)
{
- g_mutex_init(&queue->mutex);
- g_cond_init(&queue->cond);
+ guint i; /* Boucle de parcours */
+ char name[16]; /* Désignation humaine */
+
+ g_mutex_init(&group->mutex);
+ g_cond_init(&group->cond);
+ g_cond_init(&group->wait_cond);
+
+ group->threads_count = g_get_num_processors();
+
+ group->threads = (GThread **)calloc(group->threads_count, sizeof(GThread *));
- queue->thread = g_thread_new("chrysalide_queue", (GThreadFunc)g_typed_queue_process, queue);
- if (!queue->thread)
- goto gtqi_error;
+ for (i = 0; i < group->threads_count; i++)
+ {
+ snprintf(name, sizeof(name), "work_group_%u", i);
+
+ group->threads[i] = g_thread_new(name, (GThreadFunc)g_work_group_process, group);
+ if (!group->threads[i])
+ goto gwgi_error;
+
+ }
- gtqi_error:
+ gwgi_error:
- /* TODO */ return;
+ group->threads_count = i;
+
+ assert(i > 0);
+
+ group->force_exit = false;
}
@@ -374,19 +416,41 @@ static void g_typed_queue_init(GTypedQueue *queue)
* *
******************************************************************************/
-static void g_typed_queue_dispose(GTypedQueue *queue)
+static void g_work_group_dispose(GWorkGroup *group)
{
- g_mutex_clear(&queue->mutex);
- g_cond_clear(&queue->cond);
+ guint i; /* Boucle de parcours */
+ GDelayedWork *work; /* Travail à oublier */
+
+ group->force_exit = true;
+
+ g_cond_broadcast(&group->cond);
+
+ for (i = 0; i < group->threads_count; i++)
+ g_thread_join(group->threads[i]);
+
+ g_object_unref(group->statusbar);
+
+ while (!dl_list_empty(group->works))
+ {
+ work = group->works;
+ delayed_work_list_del(work, &group->works);
+
+ g_object_unref(G_OBJECT(work));
- G_OBJECT_CLASS(g_typed_queue_parent_class)->dispose(G_OBJECT(queue));
+ }
+
+ g_mutex_clear(&group->mutex);
+ g_cond_clear(&group->cond);
+ g_cond_clear(&group->wait_cond);
+
+ G_OBJECT_CLASS(g_work_group_parent_class)->dispose(G_OBJECT(group));
}
/******************************************************************************
* *
-* Paramètres : queue = instance d'objet GLib à traiter. *
+* Paramètres : group = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
@@ -396,9 +460,12 @@ static void g_typed_queue_dispose(GTypedQueue *queue)
* *
******************************************************************************/
-static void g_typed_queue_finalize(GTypedQueue *queue)
+static void g_work_group_finalize(GWorkGroup *group)
{
- G_OBJECT_CLASS(g_typed_queue_parent_class)->finalize(G_OBJECT(queue));
+ if (group->threads != NULL)
+ free(group->threads);
+
+ G_OBJECT_CLASS(g_work_group_parent_class)->finalize(G_OBJECT(group));
}
@@ -416,13 +483,13 @@ static void g_typed_queue_finalize(GTypedQueue *queue)
* *
******************************************************************************/
-static GTypedQueue *g_typed_queue_new(GType type, GtkExtStatusBar *statusbar)
+static GWorkGroup *g_work_group_new(wgroup_id_t id, GtkExtStatusBar *statusbar)
{
- GTypedQueue *result; /* Traiteur à retourner */
+ GWorkGroup *result; /* Traiteur à retourner */
- result = g_object_new(G_TYPE_TYPED_QUEUE, NULL);
+ result = g_object_new(G_TYPE_WORK_GROUP, NULL);
- result->type = type;
+ result->id = id;
result->statusbar = statusbar;
g_object_ref(statusbar);
@@ -434,7 +501,26 @@ static GTypedQueue *g_typed_queue_new(GType type, GtkExtStatusBar *statusbar)
/******************************************************************************
* *
-* Paramètres : queue = gestionnaire des actions à mener. *
+* Paramètres : group = gestionnaire des actions à mener. *
+* *
+* Description : Fournit l'identifiant associé à un groupe de travail. *
+* *
+* Retour : Identifiant unique attribué au groupe de travail. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static wgroup_id_t g_work_group_get_id(const GWorkGroup *group)
+{
+ return group->id;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : group = gestionnaire des actions à mener. *
* work = nouvelle tâche à programmer, puis effectuer. *
* *
* Description : Place une nouvelle tâche en attente dans une file dédiée. *
@@ -445,22 +531,22 @@ static GTypedQueue *g_typed_queue_new(GType type, GtkExtStatusBar *statusbar)
* *
******************************************************************************/
-static void g_typed_queue_schedule(GTypedQueue *queue, GDelayedWork *work)
+static void g_work_group_schedule(GWorkGroup *group, GDelayedWork *work)
{
- g_mutex_lock(&queue->mutex);
+ g_mutex_lock(&group->mutex);
- delayed_work_list_add_tail(work, &queue->works);
+ delayed_work_list_add_tail(work, &group->works);
- g_cond_signal(&queue->cond);
+ g_cond_signal(&group->cond);
- g_mutex_unlock(&queue->mutex);
+ g_mutex_unlock(&group->mutex);
}
/******************************************************************************
* *
-* Paramètres : queue = gestionnaire des actions à mener. *
+* Paramètres : group = gestionnaire des actions à mener. *
* *
* Description : Assure le traitement en différé. *
* *
@@ -470,25 +556,30 @@ static void g_typed_queue_schedule(GTypedQueue *queue, GDelayedWork *work)
* *
******************************************************************************/
-static void *g_typed_queue_process(GTypedQueue *queue)
+static void *g_work_group_process(GWorkGroup *group)
{
GDelayedWork *work; /* Traitement à mener */
while (1)
{
- g_mutex_lock(&queue->mutex);
+ g_mutex_lock(&group->mutex);
+
+ while (dl_list_empty(group->works) && !group->force_exit)
+ g_cond_wait(&group->cond, &group->mutex);
+
+ if (group->force_exit)
+ break;
- if (dl_list_empty(queue->works))
- g_cond_wait(&queue->cond, &queue->mutex);
+ work = group->works;
+ delayed_work_list_del(work, &group->works);
- work = queue->works;
- delayed_work_list_del(work, &queue->works);
+ g_mutex_unlock(&group->mutex);
- g_mutex_unlock(&queue->mutex);
+ g_delayed_work_process(work, group->statusbar);
- g_delayed_work_process(work, queue->statusbar);
+ g_object_unref(G_OBJECT(work));
- /* TODO : delete work */
+ g_cond_broadcast(&group->wait_cond);
}
@@ -497,6 +588,31 @@ static void *g_typed_queue_process(GTypedQueue *queue)
}
+/******************************************************************************
+* *
+* Paramètres : group = groupe dont les conclusions sont attendues. *
+* *
+* Description : Attend que toutes les tâches d'un groupe soient traitées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_work_group_wait_for_completion(GWorkGroup *group)
+{
+ g_mutex_lock(&group->mutex);
+
+ while (dl_list_empty(group->works) && !group->force_exit)
+ g_cond_wait(&group->wait_cond, &group->mutex);
+
+ g_mutex_unlock(&group->mutex);
+
+}
+
+
+
/* ---------------------------------------------------------------------------------- */
/* TRAITEMENT DE TACHES DIFFEREES */
@@ -521,6 +637,12 @@ G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT);
static void g_work_queue_class_init(GWorkQueueClass *klass)
{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_work_queue_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_work_queue_finalize;
}
@@ -539,6 +661,65 @@ static void g_work_queue_class_init(GWorkQueueClass *klass)
static void g_work_queue_init(GWorkQueue *queue)
{
+ queue->generator = 0;
+
+ queue->groups = NULL;
+ queue->groups_count = 0;
+ g_mutex_init(&queue->mutex);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : queue = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_work_queue_dispose(GWorkQueue *queue)
+{
+ size_t i; /* Boucle de parcours */
+
+ g_object_unref(G_OBJECT(queue->statusbar));
+
+ g_mutex_lock(&queue->mutex);
+
+ for (i = 0; i < queue->groups_count; i++)
+ g_object_unref(G_OBJECT(queue->groups[i]));
+
+ g_mutex_unlock(&queue->mutex);
+
+ g_mutex_clear(&queue->mutex);
+
+ G_OBJECT_CLASS(g_work_queue_parent_class)->dispose(G_OBJECT(queue));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : queue = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_work_queue_finalize(GWorkQueue *queue)
+{
+ if (queue->groups != NULL)
+ free(queue->groups);
+
+ G_OBJECT_CLASS(g_work_queue_parent_class)->finalize(G_OBJECT(queue));
}
@@ -562,7 +743,10 @@ bool init_work_queue(GObject *ref)
queue = g_object_new(G_TYPE_WORK_QUEUE, NULL);
if (ref != NULL)
+ {
queue->statusbar = g_object_get_data(ref, "statusbar");
+ g_object_ref(G_OBJECT(queue->statusbar));
+ }
else
queue->statusbar = NULL;
@@ -600,8 +784,121 @@ GWorkQueue *_get_work_queue(GWorkQueue *queue)
/******************************************************************************
* *
+* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
+* id = identifiant d'un groupe de travail. *
+* *
+* Description : Donne l'assurance de l'existence d'un groupe de travail. *
+* *
+* Retour : - *
+* *
+* 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)
+{
+ GWorkGroup *result; /* Groupe en place à renvoyer */
+ bool found; /* Bilan des recherches */
+ size_t i; /* Boucle de parcours */
+
+ found = false;
+
+ for (i = 0; i < queue->groups_count && !found; i++)
+ {
+ result = queue->groups[i];
+ found = (g_work_group_get_id(result) == id);
+ }
+
+ if (!found)
+ {
+ queue->groups_count++;
+ queue->groups = (GWorkGroup **)realloc(queue->groups,
+ queue->groups_count * sizeof(GWorkGroup *));
+
+ result = g_work_group_new(id, queue->statusbar);
+ queue->groups[i] = result;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
+* *
+* Description : Constitue un nouveau groupe de travail. *
+* *
+* Retour : Nouvel identifiant unique d'un nouveau groupe de travail. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+wgroup_id_t g_work_queue_define_work_group(GWorkQueue *queue)
+{
+ wgroup_id_t result; /* Valeur à retourner */
+
+ g_mutex_lock(&queue->mutex);
+
+ result = queue->generator++;
+
+ g_work_queue_ensure_group_exists(queue, result);
+
+ g_mutex_unlock(&queue->mutex);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
+* id = identifiant d'un groupe de travail. *
+* *
+* Description : Dissout un groupe de travail existant. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_work_queue_delete_work_group(GWorkQueue *queue, wgroup_id_t id)
+{
+ size_t i; /* Boucle de parcours */
+
+ g_mutex_lock(&queue->mutex);
+
+ for (i = 0; i < queue->groups_count; i++)
+ if (g_work_group_get_id(queue->groups[i]) == id)
+ {
+ memmove(&queue->groups[i], &queue->groups[i + 1],
+ (queue->groups_count - i - 1) * sizeof(GWorkGroup *));
+
+ queue->groups_count--;
+ queue->groups = (GWorkGroup **)realloc(queue->groups,
+ queue->groups_count * sizeof(GWorkGroup *));
+
+ break;
+
+ }
+
+ assert(i < queue->groups_count);
+
+ g_mutex_unlock(&queue->mutex);
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : queue = gestionnaire des actions à mener. *
* work = nouvelle tâche à programmer, puis effectuer. *
+* id = identifiant du groupe de travail d'affectation. *
* *
* Description : Place une nouvelle tâche en attente. *
* *
@@ -611,26 +908,60 @@ GWorkQueue *_get_work_queue(GWorkQueue *queue)
* *
******************************************************************************/
-void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work)
+void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work, wgroup_id_t id)
{
- GType target; /* Type de travail à ajouter */
- size_t i; /* Boucle de traitement */
+ GWorkGroup *group; /* Groupe de travail à attendre*/
- target = G_TYPE_FROM_INSTANCE(work);
+ g_mutex_lock(&queue->mutex);
- for (i = 0; i < queue->threads_count; i++)
- if (queue->threads[i]->type == target) break;
+ group = g_work_queue_ensure_group_exists(queue, id);
- if (i == queue->threads_count)
- {
- queue->threads_count++;
- queue->threads = (GTypedQueue **)realloc(queue->threads,
- queue->threads_count * sizeof(GTypedQueue *));
+ g_object_ref(G_OBJECT(group));
+
+ g_mutex_unlock(&queue->mutex);
- queue->threads[i] = g_typed_queue_new(target, queue->statusbar);
+ g_work_group_schedule(group, work);
+
+ g_object_unref(G_OBJECT(group));
+
+}
- }
- g_typed_queue_schedule(queue->threads[i], work);
+/******************************************************************************
+* *
+* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
+* id = identifiant d'un groupe de travail. *
+* *
+* Description : Attend que toutes les tâches d'un groupe soient traitées. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)
+{
+ size_t i; /* Boucle de parcours */
+ GWorkGroup *group; /* Groupe de travail à attendre*/
+
+ group = NULL;
+
+ g_mutex_lock(&queue->mutex);
+
+ for (i = 0; i < queue->groups_count; i++)
+ if (g_work_group_get_id(queue->groups[i]) == id)
+ {
+ group = queue->groups[i];
+ g_object_ref(G_OBJECT(group));
+ }
+
+ g_mutex_unlock(&queue->mutex);
+
+ if (group != NULL)
+ {
+ g_work_group_wait_for_completion(group);
+ g_object_unref(G_OBJECT(group));
+ }
}
diff --git a/src/glibext/delayed.h b/src/glibext/delayed.h
index 03aa873..0a27c93 100644
--- a/src/glibext/delayed.h
+++ b/src/glibext/delayed.h
@@ -74,6 +74,13 @@ typedef struct _GWorkQueue GWorkQueue;
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
+
+
#define get_work_queue() _get_work_queue(NULL)
@@ -86,8 +93,17 @@ bool init_work_queue(GObject *);
/* Fournit le gestionnaire de traitements parallèles courant. */
GWorkQueue *_get_work_queue(GWorkQueue *);
+/* Constitue un nouveau groupe de travail. */
+wgroup_id_t g_work_queue_define_work_group(GWorkQueue *);
+
+/* Dissout un groupe de travail existant. */
+void g_work_queue_delete_work_group(GWorkQueue *, wgroup_id_t);
+
/* Place une nouvelle tâche en attente. */
-void g_work_queue_schedule_work(GWorkQueue *, GDelayedWork *);
+void g_work_queue_schedule_work(GWorkQueue *, GDelayedWork *, wgroup_id_t);
+
+/* Attend que toutes les tâches d'un groupe soient traitées. */
+void g_work_queue_wait_for_completion(GWorkQueue *, wgroup_id_t);
diff --git a/src/glibext/gcodebuffer.c b/src/glibext/gcodebuffer.c
index a27b202..c676b7c 100644
--- a/src/glibext/gcodebuffer.c
+++ b/src/glibext/gcodebuffer.c
@@ -222,6 +222,11 @@ G_DEFINE_TYPE(GBufferScan, g_buffer_scan, G_TYPE_DELAYED_WORK);
static void g_buffer_scan_class_init(GBufferScanClass *klass)
{
+ GDelayedWorkClass *work; /* Version en classe parente */
+
+ work = G_DELAYED_WORK_CLASS(klass);
+
+ work->run = (run_task_fc)g_buffer_scan_process;
}
@@ -240,7 +245,6 @@ static void g_buffer_scan_class_init(GBufferScanClass *klass)
static void g_buffer_scan_init(GBufferScan *disass)
{
- G_DELAYED_WORK(disass)->run = (run_task_fc)g_buffer_scan_process;
}
@@ -887,7 +891,7 @@ void g_buffer_code_scan(GCodeBuffer *buffer, vmpa_t start, vmpa_t end, const cha
scan = g_buffer_scan_new(buffer, start, end, message, process, data);
queue = get_work_queue();
- g_work_queue_schedule_work(queue, G_DELAYED_WORK(scan));
+ g_work_queue_schedule_work(queue, G_DELAYED_WORK(scan), DEFAULT_WORK_GROUP);
}
diff --git a/src/gtkext/gtkextstatusbar.c b/src/gtkext/gtkextstatusbar.c
index 8051d41..62d4950 100644
--- a/src/gtkext/gtkextstatusbar.c
+++ b/src/gtkext/gtkextstatusbar.c
@@ -57,7 +57,7 @@ struct _GtkExtStatusBar
bar_item *stack; /* Pile de statut de la barre */
size_t stack_size; /* Taille de la pile */
- GMutex stack_access; /* Accès en à la pile */
+ GMutex stack_access; /* Accès à la pile */
};