From 0727204e36e919f06e80181482981c3f19669d76 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Wed, 11 Nov 2015 21:00:05 +0000 Subject: Prepared the next generation of parallel processings. git-svn-id: svn://svn.gna.org/svn/chrysalide/trunk@606 abbe820e-26c8-41b2-8c08-b7b2b41f8b0a --- ChangeLog | 20 ++ src/analysis/disass/disassembler.c | 8 +- src/analysis/project.c | 8 +- src/glibext/configuration.c | 2 +- src/glibext/delayed-int.h | 4 +- src/glibext/delayed.c | 499 ++++++++++++++++++++++++++++++------- src/glibext/delayed.h | 18 +- src/glibext/gcodebuffer.c | 8 +- src/gtkext/gtkextstatusbar.c | 2 +- 9 files changed, 473 insertions(+), 96 deletions(-) diff --git a/ChangeLog b/ChangeLog index d9fe98b..8ff7f0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +15-11-11 Cyrille Bagard + + * src/analysis/disass/disassembler.c: + * src/analysis/project.c: + Update code. + + * src/glibext/configuration.c: + Typo. + + * src/glibext/delayed.c: + * src/glibext/delayed.h: + * src/glibext/delayed-int.h: + Prepare the next generation of parallel processings. + + * src/glibext/gcodebuffer.c: + Update code. + + * src/gtkext/gtkextstatusbar.c: + Typo. + 15-11-09 Cyrille Bagard * plugins/pychrysa/pychrysa.c: 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 #include +#include +#include #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 */ }; -- cgit v0.11.2-87-g4458