summaryrefslogtreecommitdiff
path: root/src/glibext/work.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/glibext/work.c')
-rw-r--r--src/glibext/work.c1213
1 files changed, 47 insertions, 1166 deletions
diff --git a/src/glibext/work.c b/src/glibext/work.c
index 6b5ac35..218fcf8 100644
--- a/src/glibext/work.c
+++ b/src/glibext/work.c
@@ -1,8 +1,8 @@
/* Chrysalide - Outil d'analyse de fichiers binaires
- * delayed.c - gestion des travaux différés
+ * work.c - gestion des travaux différés
*
- * Copyright (C) 2009-2018 Cyrille Bagard
+ * Copyright (C) 2009-2024 Cyrille Bagard
*
* This file is part of Chrysalide.
*
@@ -21,178 +21,29 @@
*/
-#include "delayed.h"
+#include "work.h"
-#include <assert.h>
-#include <inttypes.h>
-#include <malloc.h>
-#include <stdio.h>
-#include <string.h>
+#include "work-int.h"
-#include "delayed-int.h"
-#include "../core/nproc.h"
-#ifdef INCLUDE_GTK_SUPPORT
-# include "../gui/core/global.h"
-#endif
-
-
-
-/* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */
-
/* Initialise la classe des travaux différés. */
-static void g_delayed_work_class_init(GDelayedWorkClass *);
+static void g_generic_work_class_init(GGenericWorkClass *);
/* Initialise une instance de travail différé. */
-static void g_delayed_work_init(GDelayedWork *);
+static void g_generic_work_init(GGenericWork *);
/* Supprime toutes les références externes. */
-static void g_delayed_work_dispose(GDelayedWork *);
+static void g_generic_work_dispose(GGenericWork *);
/* Procède à la libération totale de la mémoire. */
-static void g_delayed_work_finalize(GDelayedWork *);
-
-/* Mène l'opération programmée. */
-static void g_delayed_work_process(GDelayedWork *, GtkStatusStack *);
-
-
-
-/* -------------------------- THREAD DE TRAITEMENTS DEDIES -------------------------- */
-
-
-#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 _GWorkGroup
-{
- GObject parent; /* A laisser en premier */
-
- wgroup_id_t id; /* Identifiant de travaux menés*/
-
- 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 */
- gint pending; /* Tâches en cours d'exécution */
-
- GThread **threads; /* Procédure de traitement */
- guint threads_count; /* Nombre de procédures */
- bool force_exit; /* Procédure d'arrêt */
-
- wait_for_incoming_works_cb callback; /* Encadre les attentes de fin */
- void *data; /* Données à associer */
-
-} GWorkGroup;
-
-/* File de traitement pour un type donné (classe) */
-typedef struct _GWorkGroupClass
-{
- GObjectClass parent; /* A laisser en premier */
-
-} GWorkGroupClass;
-
-
-/* Indique le type défini pour les groupes de travail. */
-static GType g_work_group_get_type(void);
-
-/* Initialise la classe des groupes de travail. */
-static void g_work_group_class_init(GWorkGroupClass *);
-
-/* Initialise une instance de groupe de travail. */
-static void g_work_group_init(GWorkGroup *);
-
-/* Supprime toutes les références externes. */
-static void g_work_group_dispose(GWorkGroup *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_work_group_finalize(GWorkGroup *);
-
-/* Crée un nouveau thread dédié à un type de travaux donné. */
-static GWorkGroup *g_work_group_new(wgroup_id_t, const guint *);
-
-/* 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_work_group_schedule(GWorkGroup *, GDelayedWork *);
-
-/* Assure le traitement en différé. */
-static void *g_work_group_process(GWorkGroup *);
-
-/* Détermine si le groupe est vide de toute programmation. */
-static bool g_work_group_is_empty(GWorkGroup *);
-
-/* Attend que toutes les tâches d'un groupe soient traitées. */
-static void g_work_group_wait_for_completion(GWorkGroup *, GWorkQueue *);
-
-/* Modifie les conditions d'attente des fins d'exécutions. */
-static void g_work_group_set_extra_wait_callback(GWorkGroup *, wait_for_incoming_works_cb, void *);
-
-/* Force un réveil d'une attente en cours pour la confirmer. */
-static void g_work_group_wake_up_waiters(GWorkGroup *);
-
-
+static void g_generic_work_finalize(GGenericWork *);
-/* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */
-
-
-/* Gestionnaire des travaux différés (instance) */
-struct _GWorkQueue
-{
- GObject parent; /* A laisser en premier */
-
- 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 */
- GCond wait_all; /* Réveil d'attente globale */
-
-};
-
-/* Gestionnaire des travaux différés (classe) */
-struct _GWorkQueueClass
-{
- GObjectClass parent; /* A laisser en premier */
-
-};
-
-
-/* Initialise la classe des travaux différés. */
-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 bool g_work_queue_ensure_group_exists(GWorkQueue *, wgroup_id_t, const guint *);
-
-/* Fournit le groupe de travail correspondant à un identifiant. */
-static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *, wgroup_id_t);
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* TACHE DIFFEREE DANS LE TEMPS */
-/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour les travaux différés. */
-G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT);
+G_DEFINE_TYPE(GGenericWork, g_generic_work, G_TYPE_OBJECT);
/******************************************************************************
@@ -207,19 +58,19 @@ G_DEFINE_TYPE(GDelayedWork, g_delayed_work, G_TYPE_OBJECT);
* *
******************************************************************************/
-static void g_delayed_work_class_init(GDelayedWorkClass *klass)
+static void g_generic_work_class_init(GGenericWorkClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
- object->dispose = (GObjectFinalizeFunc/* ! */)g_delayed_work_dispose;
- object->finalize = (GObjectFinalizeFunc)g_delayed_work_finalize;
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_generic_work_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_generic_work_finalize;
g_signal_new("work-completed",
- G_TYPE_DELAYED_WORK,
+ G_TYPE_GENERIC_WORK,
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET(GDelayedWorkClass, work_completed),
+ G_STRUCT_OFFSET(GGenericWorkClass, work_completed),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -239,8 +90,10 @@ static void g_delayed_work_class_init(GDelayedWorkClass *klass)
* *
******************************************************************************/
-static void g_delayed_work_init(GDelayedWork *work)
+static void g_generic_work_init(GGenericWork *work)
{
+ DL_LIST_ITEM_INIT(&work->link);
+
work->completed = false;
g_mutex_init(&work->mutex);
g_cond_init(&work->cond);
@@ -260,12 +113,12 @@ static void g_delayed_work_init(GDelayedWork *work)
* *
******************************************************************************/
-static void g_delayed_work_dispose(GDelayedWork *work)
+static void g_generic_work_dispose(GGenericWork *work)
{
g_mutex_clear(&work->mutex);
g_cond_clear(&work->cond);
- G_OBJECT_CLASS(g_delayed_work_parent_class)->dispose(G_OBJECT(work));
+ G_OBJECT_CLASS(g_generic_work_parent_class)->dispose(G_OBJECT(work));
}
@@ -282,281 +135,19 @@ static void g_delayed_work_dispose(GDelayedWork *work)
* *
******************************************************************************/
-static void g_delayed_work_finalize(GDelayedWork *work)
-{
- G_OBJECT_CLASS(g_delayed_work_parent_class)->finalize(G_OBJECT(work));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : work = travail à effectuer. *
-* status = barre de statut à tenir informée. *
-* *
-* Description : Mène l'opération programmée. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_delayed_work_process(GDelayedWork *work, GtkStatusStack *status)
-{
- G_DELAYED_WORK_GET_CLASS(work)->run(work, status);
-
- g_mutex_lock(&work->mutex);
-
- work->completed = true;
-
- g_cond_signal(&work->cond);
- g_mutex_unlock(&work->mutex);
-
- g_signal_emit_by_name(work, "work-completed");
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : work = travail à surveiller. *
-* *
-* Description : Attend la fin de l'exécution d'une tâche donnée. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_delayed_work_wait_for_completion(GDelayedWork *work)
-{
- g_mutex_lock(&work->mutex);
-
- while (!work->completed)
- g_cond_wait(&work->cond, &work->mutex);
-
- g_mutex_unlock(&work->mutex);
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* THREADS DES TRAITEMENTS DEDIES */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* 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 groupes de travail. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-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_work_group_dispose;
- object->finalize = (GObjectFinalizeFunc)g_work_group_finalize;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = instance à initialiser. *
-* *
-* Description : Initialise une instance de groupe de travail. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_work_group_init(GWorkGroup *group)
-{
- group->works = NULL;
-
- g_mutex_init(&group->mutex);
- g_cond_init(&group->cond);
- g_cond_init(&group->wait_cond);
-
- g_atomic_int_set(&group->pending, 0);
-
- group->threads = NULL;
- group->threads_count = 0;
- group->force_exit = false;
-
- group->callback = NULL;
- group->data = NULL;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : queue = instance d'objet GLib à traiter. *
-* *
-* Description : Supprime toutes les références externes. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_work_group_dispose(GWorkGroup *group)
-{
- guint i; /* Boucle de parcours */
- GDelayedWork *work; /* Travail à oublier */
-
- group->force_exit = true;
-
- /**
- * Concernant la pose du verrou, se référer aux commentaires de la
- * fonction g_work_group_process().
- */
-
- g_mutex_lock(&group->mutex);
-
- g_cond_broadcast(&group->cond);
-
- g_mutex_unlock(&group->mutex);
-
- for (i = 0; i < group->threads_count; i++)
- g_thread_join(group->threads[i]);
-
- while (!dl_list_empty(group->works))
- {
- work = group->works;
- delayed_work_list_del(work, &group->works);
-
- g_object_unref(G_OBJECT(work));
-
- }
-
- 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 : group = instance d'objet GLib à traiter. *
-* *
-* Description : Procède à la libération totale de la mémoire. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_work_group_finalize(GWorkGroup *group)
-{
- if (group->threads != NULL)
- free(group->threads);
-
- G_OBJECT_CLASS(g_work_group_parent_class)->finalize(G_OBJECT(group));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : id = identifiant accordé au nouveau groupe. *
-* count = quantité de threads à allouer. *
-* *
-* Description : Crée un nouveau thread dédié à un type de travaux donné. *
-* *
-* Retour : Structure associée au thread mise en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GWorkGroup *g_work_group_new(wgroup_id_t id, const guint *count)
-{
- GWorkGroup *result; /* Traiteur à retourner */
- guint i; /* Boucle de parcours */
- char name[16]; /* Désignation humaine */
-
- result = g_object_new(G_TYPE_WORK_GROUP, NULL);
-
- result->id = id;
-
- result->threads_count = get_max_online_threads();
-
- if (count != NULL && *count < result->threads_count)
- result->threads_count = *count;
-
- result->threads = (GThread **)calloc(result->threads_count, sizeof(GThread *));
-
- for (i = 0; i < result->threads_count; i++)
- {
- snprintf(name, sizeof(name), "wgrp_%" PRIu64 "-%u", id, i);
-
- result->threads[i] = g_thread_new(name, (GThreadFunc)g_work_group_process, result);
- if (!result->threads[i])
- goto start_error;
-
- }
-
- start_error:
-
- result->threads_count = i;
-
- assert(i > 0);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* 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)
+static void g_generic_work_finalize(GGenericWork *work)
{
- return group->id;
+ G_OBJECT_CLASS(g_generic_work_parent_class)->finalize(G_OBJECT(work));
}
/******************************************************************************
* *
-* Paramètres : group = gestionnaire des actions à mener. *
-* work = nouvelle tâche à programmer, puis effectuer. *
+* Paramètres : work = travail à traiter. *
+* list = ensemble de travaux à considérer. [OUT] *
* *
-* Description : Place une nouvelle tâche en attente dans une file dédiée. *
+* Description : Intègre un travail dans une liste de tâches à effectuer. *
* *
* Retour : - *
* *
@@ -564,161 +155,19 @@ static wgroup_id_t g_work_group_get_id(const GWorkGroup *group)
* *
******************************************************************************/
-static void g_work_group_schedule(GWorkGroup *group, GDelayedWork *work)
+void g_generic_work_add_to_list(GGenericWork *work, GGenericWork **list)
{
- g_mutex_lock(&group->mutex);
-
- g_atomic_int_inc(&group->pending);
-
- delayed_work_list_add_tail(work, &group->works);
-
- g_cond_signal(&group->cond);
-
- g_mutex_unlock(&group->mutex);
+ dl_list_add_tail(work, list, GGenericWork, link);
}
/******************************************************************************
* *
-* Paramètres : group = gestionnaire des actions à mener. *
-* *
-* Description : Assure le traitement en différé. *
-* *
-* Retour : Bilan de l'opération. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void *g_work_group_process(GWorkGroup *group)
-{
- GDelayedWork *work; /* Traitement à mener */
- GtkStatusStack *status; /* Zone d'info éventuelle */
-
- while (1)
- {
- 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)
- {
- g_mutex_unlock(&group->mutex);
- break;
- }
-
- work = group->works;
- delayed_work_list_del(work, &group->works);
-
- g_mutex_unlock(&group->mutex);
-
-#ifdef INCLUDE_GTK_SUPPORT
- status = get_global_status();
-#else
- status = NULL;
-#endif
- g_delayed_work_process(work, status);
-
- g_object_unref(G_OBJECT(work));
-
- /**
- * Verrou ou pas verrou ?
- *
- * La documentation de la GLib indique que ce n'est pas nécessaire :
- *
- * '''
- * It is good practice to lock the same mutex as the waiting threads
- * while calling this function, though not required.
- * '''
- *
- * Ce conseil se trouve verbatim à l'adresse :
- *
- * https://developer.gnome.org/glib/stable/glib-Threads.html#g-cond-broadcast
- *
- * Dans la pratique, il peut arriver que l'attente de la fonction
- * g_work_group_wait_for_completion() ne soit jamais interrompue.
- *
- * La documentation POSIX est un peu plus orientée :
- *
- * '''
- * The pthread_cond_broadcast() functions may be called by a thread
- * whether or not it currently owns the mutex that threads calling
- * pthread_cond_wait() have associated with the condition variable
- * during their waits; however, if predictable scheduling behavior is
- * required, then that mutex shall be locked by the thread calling
- * pthread_cond_broadcast().
- * '''
- *
- * Ce passage complet est consultable à l'adresse :
- *
- * http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_broadcast.html
- *
- * La page de manuel pthread_cond_broadcast(3) est quant à elle plus
- * directrice : aucun complément d'information sur le sujet n'est fourni
- * et les exemples associés utilisent implicement un verrou pendant
- * sont appel.
- */
-
- g_mutex_lock(&group->mutex);
-
- if (g_atomic_int_dec_and_test(&group->pending))
- g_cond_broadcast(&group->wait_cond);
-
- g_mutex_unlock(&group->mutex);
-
- }
-
- return NULL;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = gestionnaire des actions à consulter. *
-* *
-* Description : Détermine si le groupe est vide de toute programmation. *
+* Paramètres : work = travail à traiter. *
+* list = ensemble de travaux à considérer. [OUT] *
* *
-* Retour : Etat du groupe de travail. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static bool g_work_group_is_empty(GWorkGroup *group)
-{
- bool result; /* Etat à retourner */
-
- /**
- * Pour que le résultat soit exploitable, il ne doit pas varier
- * en dehors de la zone couverte par le verrou du groupe avant
- * son utilisation par l'appelant.
- *
- * Il doit donc logiquement y avoir un autre verrou en amont et,
- * comme à priori on ne devrait pas bloquer les groupes principaux
- * pour un traitement particulier, cette procédure ne devrait concerner
- * que des groupes dynamiques.
- */
-
- g_mutex_lock(&group->mutex);
-
- result = dl_list_empty(group->works);
-
- g_mutex_unlock(&group->mutex);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : group = groupe dont les conclusions sont attendues. *
-* queue = queue d'appartenance pour les appels externes. *
-* *
-* Description : Attend que toutes les tâches d'un groupe soient traitées. *
+* Description : Supprime un travail d'une liste de tâches à effectuer. *
* *
* Retour : - *
* *
@@ -726,530 +175,18 @@ static bool g_work_group_is_empty(GWorkGroup *group)
* *
******************************************************************************/
-static void g_work_group_wait_for_completion(GWorkGroup *group, GWorkQueue *queue)
+void g_generic_work_remove_from_list(GGenericWork *work, GGenericWork **list)
{
- wait_for_incoming_works_cb callback; /* Procédure complémentaire */
-
- bool no_extra_check(GWorkQueue *_q, wgroup_id_t _id, void *_data)
- {
- return false;
- }
-
- callback = group->callback != NULL ? group->callback : no_extra_check;
-
- g_mutex_lock(&group->mutex);
-
- /**
- * On attend que :
- * - la liste des tâches programmées soit vide.
- * - il n'existe plus de tâche en cours.
- * - rien n'indique que de nouvelles tâches supplémentaires vont arriver.
- */
-
- while ((g_atomic_int_get(&group->pending) > 0 || callback(queue, group->id, group->data))
- && !group->force_exit)
- {
- g_cond_wait(&group->wait_cond, &group->mutex);
- }
-
- g_mutex_unlock(&group->mutex);
+ dl_list_del(work, list, GGenericWork, link);
}
/******************************************************************************
* *
-* Paramètres : group = groupe dont les paramètres sont à modifier. *
-* callback = éventuelle fonction à appeler ou NULL. *
-* data = données devant accompagner l'appel. *
-* *
-* Description : Modifie les conditions d'attente des fins d'exécutions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_work_group_set_extra_wait_callback(GWorkGroup *group, wait_for_incoming_works_cb callback, void *data)
-{
- group->callback = callback;
- group->data = data;
-
-}
-
-
-/******************************************************************************
+* Paramètres : work = travail à effectuer. *
* *
-* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail.*
-* id = identifiant d'un groupe de travail. *
-* *
-* Description : Force un réveil d'une attente en cours pour la confirmer. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_work_group_wake_up_waiters(GWorkGroup *group)
-{
- /**
- * Concernant la pose du verrou, se référer aux commentaires de la
- * fonction g_work_group_process().
- */
-
- g_mutex_lock(&group->mutex);
-
- g_cond_broadcast(&group->wait_cond);
-
- g_mutex_unlock(&group->mutex);
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/* TRAITEMENT DE TACHES DIFFEREES */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour le gestionnaire des travaux différés. */
-G_DEFINE_TYPE(GWorkQueue, g_work_queue, G_TYPE_OBJECT);
-
-
-/******************************************************************************
-* *
-* Paramètres : klass = classe à initialiser. *
-* *
-* Description : Initialise la classe des travaux différés. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-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;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : queue = instance à initialiser. *
-* *
-* Description : Initialise une instance de gestionnaire de travaux différés. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static void g_work_queue_init(GWorkQueue *queue)
-{
- queue->generator = 0;
-
- queue->groups = NULL;
- queue->groups_count = 0;
- g_mutex_init(&queue->mutex);
- g_cond_init(&queue->wait_all);
-
-}
-
-
-/******************************************************************************
-* *
-* 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_mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->groups_count; i++)
- g_clear_object(&queue->groups[i]);
-
- g_mutex_unlock(&queue->mutex);
-
- g_mutex_clear(&queue->mutex);
- g_cond_clear(&queue->wait_all);
-
- 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));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : - *
-* *
-* Description : Créé un nouveau gestionnaire de tâches parallèles. *
-* *
-* Retour : Gestionnaire de traitements mis en place. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-GWorkQueue *g_work_queue_new(void)
-{
- GWorkQueue *result; /* Instance à retourner */
-
- result = g_object_new(G_TYPE_WORK_QUEUE, NULL);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
-* id = identifiant d'un groupe de travail. *
-* count = quantité de threads à allouer. *
-* *
-* Description : Donne l'assurance de l'existence d'un groupe de travail. *
-* *
-* Retour : true si un nouveau groupe a été constitué, false sinon. *
-* *
-* Remarques : Le verrou d'accès doit être posé par l'appelant. *
-* *
-******************************************************************************/
-
-static bool g_work_queue_ensure_group_exists(GWorkQueue *queue, wgroup_id_t id, const guint *count)
-{
- 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++)
- {
- group = queue->groups[i];
- found = (g_work_group_get_id(group) == id);
- }
-
- if (!found)
- {
- queue->groups_count++;
- queue->groups = (GWorkGroup **)realloc(queue->groups,
- queue->groups_count * sizeof(GWorkGroup *));
-
- group = g_work_group_new(id, count);
- queue->groups[queue->groups_count - 1] = group;
-
- }
-
- return !found;
-
-}
-
-
-/******************************************************************************
-* *
-* 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 */
- bool created; /* Bilan d'une tentative */
-
- g_mutex_lock(&queue->mutex);
-
- do
- {
- result = queue->generator++;
- created = g_work_queue_ensure_group_exists(queue, result, NULL);
- }
- while (!created);
-
- g_mutex_unlock(&queue->mutex);
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
-* count = quantité de threads à allouer. *
-* *
-* Description : Constitue un nouveau petit groupe de travail. *
-* *
-* Retour : Nouvel identifiant unique d'un nouveau groupe de travail. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-wgroup_id_t g_work_queue_define_tiny_work_group(GWorkQueue *queue, guint count)
-{
- wgroup_id_t result; /* Valeur à retourner */
- bool created; /* Bilan d'une tentative */
-
- g_mutex_lock(&queue->mutex);
-
- do
- {
- result = queue->generator++;
- created = g_work_queue_ensure_group_exists(queue, result, &count);
- }
- while (!created);
-
- 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 */
- GWorkGroup *group; /* Groupe de travail manipulé */
-#ifndef NDEBUG
- bool found; /* Repérage du groupe visé */
-#endif
-
-#ifndef NDEBUG
- found = false;
-#endif
-
- g_mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->groups_count; i++)
- {
- group = queue->groups[i];
-
- if (g_work_group_get_id(group) == id)
- {
- g_object_unref(G_OBJECT(group));
-
- 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 *));
-
-#ifndef NDEBUG
- found = true;
-#endif
-
- break;
-
- }
-
- }
-
- assert(found);
-
- g_cond_broadcast(&queue->wait_all);
-
- 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. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work, wgroup_id_t id)
-{
- GWorkGroup *group; /* Groupe de travail à attendre*/
-
- group = g_work_queue_find_group_for_id(queue, id);
- assert(group != NULL);
-
- g_work_group_schedule(group, work);
-
- g_object_unref(G_OBJECT(group));
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail. *
-* id = identifiant d'un groupe de travail. *
-* *
-* Description : Fournit le groupe de travail correspondant à un identifiant. *
-* *
-* Retour : Eventuel groupe existant trouvé ou NULL si aucun. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-static GWorkGroup *g_work_queue_find_group_for_id(GWorkQueue *queue, wgroup_id_t id)
-{
- GWorkGroup *result; /* Trouvaille à retourner */
- size_t i; /* Boucle de parcours */
-
- result = NULL;
-
- g_mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->groups_count; i++)
- if (g_work_group_get_id(queue->groups[i]) == id)
- {
- result = queue->groups[i];
- g_object_ref(G_OBJECT(result));
- break;
- }
-
- 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 : Détermine si un groupe est vide de toute programmation. *
-* *
-* Retour : Etat du groupe de travail. *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
-
-bool g_work_queue_is_empty(GWorkQueue *queue, wgroup_id_t id)
-{
- bool result; /* Etat à retourner */
- GWorkGroup *group; /* Groupe de travail à attendre*/
-
- group = g_work_queue_find_group_for_id(queue, id);
-
- if (group != NULL)
- {
- result = g_work_group_is_empty(group);
- g_object_unref(G_OBJECT(group));
- }
-
- else
- result = true;
-
- return result;
-
-}
-
-
-/******************************************************************************
-* *
-* 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)
-{
- GWorkGroup *group; /* Groupe de travail à attendre*/
-
- group = g_work_queue_find_group_for_id(queue, id);
-
- if (group != NULL)
- {
- g_work_group_wait_for_completion(group, queue);
- g_object_unref(G_OBJECT(group));
- }
-
-}
-
-
-/******************************************************************************
-* *
-* 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. *
+* Description : Mène l'opération programmée. *
* *
* Retour : - *
* *
@@ -1257,80 +194,27 @@ void g_work_queue_wait_for_completion(GWorkQueue *queue, wgroup_id_t id)
* *
******************************************************************************/
-void g_work_queue_wait_for_all_completions(GWorkQueue *queue, const wgroup_id_t *gb_ids, size_t gb_count)
+void g_generic_work_process(GGenericWork *work)
{
- size_t i; /* Boucle de parcours */
-
- g_mutex_lock(&queue->mutex);
-
- wait_again:
-
- /**
- * Attente d'éventuels groupes isolés.
- */
-
- while (queue->groups_count > gb_count)
- g_cond_wait(&queue->wait_all, &queue->mutex);
-
- g_mutex_unlock(&queue->mutex);
-
- /**
- * Attente des groupes principaux.
- */
-
- for (i = 0; i < gb_count; i++)
- g_work_queue_wait_for_completion(queue, gb_ids[i]);
+ G_GENERIC_WORK_GET_CLASS(work)->run(work);
- /**
- * Si le groupe par défaut a généré de nouveaux groupes, on recommence !
- */
-
- g_mutex_lock(&queue->mutex);
-
- if (queue->groups_count > gb_count)
- goto wait_again;
-
- g_mutex_unlock(&queue->mutex);
-
-}
-
-
-/******************************************************************************
-* *
-* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail.*
-* id = identifiant d'un groupe de travail. *
-* callback = éventuelle fonction à appeler ou NULL. *
-* data = données devant accompagner l'appel. *
-* *
-* Description : Modifie les conditions d'attente des fins d'exécutions. *
-* *
-* Retour : - *
-* *
-* Remarques : - *
-* *
-******************************************************************************/
+ g_mutex_lock(&work->mutex);
-void g_work_queue_set_extra_wait_callback(GWorkQueue *queue, wgroup_id_t id, wait_for_incoming_works_cb callback, void *data)
-{
- GWorkGroup *group; /* Groupe de travail à traiter */
+ work->completed = true;
- group = g_work_queue_find_group_for_id(queue, id);
+ g_cond_signal(&work->cond);
+ g_mutex_unlock(&work->mutex);
- if (group != NULL)
- {
- g_work_group_set_extra_wait_callback(group, callback, data);
- g_object_unref(G_OBJECT(group));
- }
+ g_signal_emit_by_name(work, "work-completed");
}
/******************************************************************************
* *
-* Paramètres : queue = gestionnaire de l'ensemble des groupes de travail.*
-* id = identifiant d'un groupe de travail. *
+* Paramètres : work = travail à surveiller. *
* *
-* Description : Force un réveil d'une attente en cours pour la confirmer. *
+* Description : Attend la fin de l'exécution d'une tâche donnée. *
* *
* Retour : - *
* *
@@ -1338,16 +222,13 @@ void g_work_queue_set_extra_wait_callback(GWorkQueue *queue, wgroup_id_t id, wai
* *
******************************************************************************/
-void g_work_queue_wake_up_waiters(GWorkQueue *queue, wgroup_id_t id)
+void g_generic_work_wait_for_completion(GGenericWork *work)
{
- GWorkGroup *group; /* Groupe de travail à traiter */
+ g_mutex_lock(&work->mutex);
- group = g_work_queue_find_group_for_id(queue, id);
+ while (!work->completed)
+ g_cond_wait(&work->cond, &work->mutex);
- if (group != NULL)
- {
- g_work_group_wake_up_waiters(group);
- g_object_unref(G_OBJECT(group));
- }
+ g_mutex_unlock(&work->mutex);
}