/* OpenIDA - Outil d'analyse de fichiers binaires * delayed.c - gestion des travaux différés * * Copyright (C) 2009-2010 Cyrille Bagard * * This file is part of OpenIDA. * * OpenIDA is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * OpenIDA is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "delayed.h" #include #include "delayed-int.h" /* -------------------------- TACHE DIFFEREE DANS LE TEMPS -------------------------- */ /* Initialise la classe des travaux différés. */ static void g_delayed_work_class_init(GDelayedWorkClass *); /* Initialise une instance de travail différé. */ static void g_delayed_work_init(GDelayedWork *); /* Supprime toutes les références externes. */ static void g_delayed_work_dispose(GDelayedWork *); /* 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 *, 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)) /* File de traitement pour un type donné (instance) */ typedef struct _GTypedQueue { GObject parent; /* A laisser en premier */ GType type; /* Type 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 */ GThread *thread; /* Procédure de traitement */ } GTypedQueue; /* File de traitement pour un type donné (classe) */ typedef struct _GTypedQueueClass { GObjectClass parent; /* A laisser en premier */ } GTypedQueueClass; /* Indique le type défini pour les travaux typés. */ static GType g_typed_queue_get_type(void); /* Initialise la classe des travaux typés. */ static void g_typed_queue_class_init(GTypedQueueClass *); /* Initialise une instance de gestionnaire de travaux typés. */ static void g_typed_queue_init(GTypedQueue *); /* Crée un nouveau thread dédié à un type de travaux donné. */ static GTypedQueue *g_typed_queue_new(GType, GtkExtStatusBar *); /* Place une nouvelle tâche en attente dans une file dédiée. */ static void g_typed_queue_schedule(GTypedQueue *, GDelayedWork *); /* Assure le traitement en différé. */ static void *g_typed_queue_process(GTypedQueue *); /* ------------------------- TRAITEMENT DE TACHES DIFFEREES ------------------------- */ /* Gestionnaire des travaux différés (instance) */ struct _GWorkQueue { GObject parent; /* A laisser en premier */ GtkExtStatusBar *statusbar; /* Barre de statut principale */ GTypedQueue **threads; /* Files de traitement */ size_t threads_count; /* Nombre de files internes */ }; /* 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 *); /* ---------------------------------------------------------------------------------- */ /* 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); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des travaux différés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_work_class_init(GDelayedWorkClass *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; g_signal_new("work-completed", G_TYPE_DELAYED_WORK, G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET(GDelayedWorkClass, work_completed), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); } /****************************************************************************** * * * Paramètres : work = instance à initialiser. * * * * Description : Initialise une instance de travail différé. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_work_init(GDelayedWork *work) { work->completed = false; work->mutex = g_mutex_new(); work->cond = g_cond_new(); } /****************************************************************************** * * * Paramètres : work = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_work_dispose(GDelayedWork *work) { gpointer obj_class; /* Classe parente */ g_mutex_free(work->mutex); g_cond_free(work->cond); obj_class = g_type_class_peek_parent(G_DELAYED_WORK_GET_CLASS(work)); //G_OBJECT_CLASS(obj_class)->dispose(G_OBJECT(work)); } /****************************************************************************** * * * Paramètres : work = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_work_finalize(GDelayedWork *work) { gpointer obj_class; /* Classe parente */ obj_class = g_type_class_peek_parent(G_DELAYED_WORK_GET_CLASS(work)); //G_OBJECT_CLASS(obj_class)->finalize(G_OBJECT(work)); } /****************************************************************************** * * * Paramètres : work = travail à effectuer. * * statusbar = barre de statut à tenir informée. * * * * Description : Mène l'opération programmée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_delayed_work_process(GDelayedWork *work, GtkExtStatusBar *statusbar) { work->run(work, statusbar); g_signal_emit_by_name(work, "work-completed"); g_mutex_lock(work->mutex); work->completed = true; g_cond_signal(work->cond); g_mutex_unlock(work->mutex); } /****************************************************************************** * * * 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); } /* ---------------------------------------------------------------------------------- */ /* THREAD DE TRAITEMENTS DEDIES */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour les travaux typés. */ G_DEFINE_TYPE(GTypedQueue, g_typed_queue, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des travaux typés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_typed_queue_class_init(GTypedQueueClass *klass) { } /****************************************************************************** * * * Paramètres : queue = instance à initialiser. * * * * Description : Initialise une instance de gestionnaire de travaux typés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_typed_queue_init(GTypedQueue *queue) { GError *error; /* Bilan de création de thread */ queue->mutex = g_mutex_new(); if (queue->mutex == NULL) goto gtqi_error; queue->cond = g_cond_new(); if (queue->cond == NULL) goto gtqi_error; queue->thread = g_thread_create((GThreadFunc)g_typed_queue_process, queue, FALSE, &error); if (!queue->thread) goto gtqi_error; gtqi_error: /* TODO */ return; } /****************************************************************************** * * * Paramètres : type = type dont seront marqués tous les travaux donnés.* * statusbar = barre de statut à tenir informée. * * * * Description : Crée un nouveau thread dédié à un type de travaux donné. * * * * Retour : Structure associée au thread mise en place. * * * * Remarques : - * * * ******************************************************************************/ static GTypedQueue *g_typed_queue_new(GType type, GtkExtStatusBar *statusbar) { GTypedQueue *result; /* Traiteur à retourner */ result = g_object_new(G_TYPE_TYPED_QUEUE, NULL); result->type = type; result->statusbar = statusbar; return result; } /****************************************************************************** * * * Paramètres : queue = 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. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_typed_queue_schedule(GTypedQueue *queue, GDelayedWork *work) { g_mutex_lock(queue->mutex); delayed_work_list_add_tail(work, &queue->works); g_cond_signal(queue->cond); g_mutex_unlock(queue->mutex); } /****************************************************************************** * * * Paramètres : queue = gestionnaire des actions à mener. * * * * Description : Assure le traitement en différé. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ static void *g_typed_queue_process(GTypedQueue *queue) { GDelayedWork *work; /* Traitement à mener */ while (1) { g_mutex_lock(queue->mutex); if (dl_list_empty(queue->works)) g_cond_wait(queue->cond, queue->mutex); work = queue->works; delayed_work_list_del(work, &queue->works); g_mutex_unlock(queue->mutex); g_delayed_work_process(work, queue->statusbar); /* TODO : delete work */ } return NULL; } /* ---------------------------------------------------------------------------------- */ /* 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) { } /****************************************************************************** * * * 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) { } /****************************************************************************** * * * Paramètres : ref = espace de référencements global. * * * * Description : Procède au chargement du gestionnaire d'analyse différées. * * * * Retour : true pour indiquer un chargement réussi, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool init_work_queue(GObject *ref) { GWorkQueue *queue; /* Singleton à mettre en place */ queue = g_object_new(G_TYPE_WORK_QUEUE, NULL); queue->statusbar = g_object_get_data(ref, "statusbar"); if (queue != NULL) _get_work_queue(queue); return (queue != NULL); } /****************************************************************************** * * * Paramètres : queue = nouveau gestionnaire à mémoriser ou NULL. * * * * Description : Fournit le gestionnaire de traitements parallèles courant. * * * * Retour : Gestionnaire de traitements parallèles courant. * * * * Remarques : - * * * ******************************************************************************/ GWorkQueue *_get_work_queue(GWorkQueue *queue) { static GWorkQueue *result = NULL; /* Singleton à retourner */ if (queue != NULL) result = queue; return result; } /****************************************************************************** * * * Paramètres : queue = gestionnaire des actions à mener. * * work = nouvelle tâche à programmer, puis effectuer. * * * * Description : Place une nouvelle tâche en attente. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_work_queue_schedule_work(GWorkQueue *queue, GDelayedWork *work) { GType target; /* Type de travail à ajouter */ size_t i; /* Boucle de traitement */ target = G_TYPE_FROM_INSTANCE(work); for (i = 0; i < queue->threads_count; i++) if (queue->threads[i]->type == target) break; if (i == queue->threads_count) { queue->threads_count++; queue->threads = (GTypedQueue **)realloc(queue->threads, queue->threads_count * sizeof(GTypedQueue *)); queue->threads[i] = g_typed_queue_new(target, queue->statusbar); } g_typed_queue_schedule(queue->threads[i], work); }