/* Chrysalide - Outil d'analyse de fichiers binaires * manager.c - collecte et gestion des instances partagées * * Copyright (C) 2016 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Foobar. If not, see . */ #include "manager.h" #include #ifdef DEBUG_DUMP_STATS # include #endif /* Gestionnaire d'instances de type identique partagées (instance) */ struct _GShareManager { GObject parent; /* A laisser en premier */ GHashTable *table; /* Collection de partages */ GMutex access; /* Accès à la table */ GType managed; /* Type d'instances gérées */ }; /* Gestionnaire d'instances de type identique partagées (classe) */ struct _GShareManagerClass { GObjectClass parent; /* A laisser en premier */ }; /* Procède à l'initialisation d'une classe de suivi de largeurs. */ static void g_share_manager_class_init(GShareManagerClass *); /* Procède à l'initialisation d'un suivi de largeurs de lignes. */ static void g_share_manager_init(GShareManager *); /* Supprime toutes les références externes. */ static void g_share_manager_dispose(GShareManager *); /* Procède à la libération totale de la mémoire. */ static void g_share_manager_finalize(GShareManager *); /* Détermine le type du gestionnaire d'instances partagées. */ G_DEFINE_TYPE(GShareManager, g_share_manager, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : class = classe de composant GTK à initialiser. * * * * Description : Procède à l'initialisation d'une classe de suivi de largeurs.* * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_share_manager_class_init(GShareManagerClass *class) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(class); object->dispose = (GObjectFinalizeFunc/* ! */)g_share_manager_dispose; object->finalize = (GObjectFinalizeFunc)g_share_manager_finalize; } /****************************************************************************** * * * Paramètres : manager = composant GLib à initialiser. * * * * Description : Procède à l'initialisation d'un suivi de largeurs de lignes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_share_manager_init(GShareManager *manager) { g_mutex_init(&manager->access); } /****************************************************************************** * * * Paramètres : manager = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_share_manager_dispose(GShareManager *manager) { g_hash_table_unref(manager->table); g_mutex_clear(&manager->access); G_OBJECT_CLASS(g_share_manager_parent_class)->dispose(G_OBJECT(manager)); } /****************************************************************************** * * * Paramètres : manager = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_share_manager_finalize(GShareManager *manager) { G_OBJECT_CLASS(g_share_manager_parent_class)->finalize(G_OBJECT(manager)); } /****************************************************************************** * * * Paramètres : type = type d'instances encadrées ici. * * * * Description : Crée un nouveau gestionnaire d'instances partagées. * * * * Retour : Composant GLib créé. * * * * Remarques : - * * * ******************************************************************************/ GShareManager *g_share_manager_new(GType type) { GShareManager *result; /* Gestionnaire à renvoyer */ result = g_object_new(G_TYPE_SHARE_MANAGER, NULL); result->table = g_hash_table_new_full((GHashFunc)g_direct_hash, (GEqualFunc)g_shared_instance_is_equal, (GDestroyNotify)g_object_unref, (GDestroyNotify)NULL); result->managed = type; return result; } /****************************************************************************** * * * Paramètres : manager = gestionnaire d'instance à consulter. * * info = informations à retrouver intégralement. * * * * Description : Retrouve ou crée une instance partagée. * * * * Retour : Instance existante déjà partagée ou nouvellement créée. * * * * Remarques : - * * * ******************************************************************************/ GSharedInstance *g_share_manager_get(GShareManager *manager, const void *info) { GSharedInstance *result; /* Trouvaille à retourner */ gpointer found; /* Elément correspondant ? */ bool status; /* Conclusion d'initialisation */ #ifndef NDEBUG gboolean new; /* Présence de partage existant*/ #endif gboolean find_shared_matching_info(const GSharedInstance *key, gpointer unused, const void *nfo) { return g_shared_instance_compare_info(key, nfo); } g_mutex_lock(&manager->access); found = g_hash_table_find(manager->table, (GHRFunc)find_shared_matching_info, (void *)info); if (found == NULL) { result = g_object_new(manager->managed, NULL); status = g_shared_instance_init(result, info); if (!status) { g_object_unref(result); result = NULL; } else { g_shared_instance_inc_references(result); #ifndef NDEBUG new = g_hash_table_add(manager->table, result); assert(new); #else g_hash_table_add(manager->table, result); #endif } } else result = G_SHARED_INSTANCE(found); if (result != NULL) { g_object_ref(G_OBJECT(result)); g_shared_instance_inc_references(result); } g_mutex_unlock(&manager->access); return result; } /****************************************************************************** * * * Paramètres : manager = gestionnaire d'instance à consulter. * * old = ancienne instance partagée à faire évoluer. * * info = informations à retrouver intégralement. * * container = propriétaire de l'ancienne version à contacter. * * * * Description : Met à jour une instance partagée. * * * * Retour : Instance existante déjà partagée ou nouvellement créée. * * * * Remarques : - * * * ******************************************************************************/ GSharedInstance *g_share_manager_update(GShareManager *manager, GSharedInstance *old, const void *info, GShareContainer *container) { GSharedInstance *result; /* Nouvelle instance à renvoyer*/ result = g_share_manager_get(manager, info); if (container != NULL) g_share_container_replace(container, old, result); g_share_manager_put(manager, old); return result; } /****************************************************************************** * * * Paramètres : manager = gestionnaire d'instance à consulter. * * shared = instance partagée à libérer. * * * * Description : Abandonne un usage d'une instance partagée. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_share_manager_put(GShareManager *manager, GSharedInstance *shared) { #ifndef NDEBUG gboolean found; /* Présence de partage existant*/ #endif g_mutex_lock(&manager->access); g_shared_instance_dec_references(shared); if (g_shared_instance_get_references(shared) == 1) { #ifndef NDEBUG found = g_hash_table_remove(manager->table, shared); assert(found); #else g_hash_table_remove(manager->table, shared); #endif } g_mutex_unlock(&manager->access); } /****************************************************************************** * * * Paramètres : manager = gestionnaire d'instance à consulter. * * * * Description : Imprime des statistiques d'utilisation du gestionnaire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ #ifdef DEBUG_DUMP_STATS void g_share_manager_dump_stats(GShareManager *manager) { unsigned int counter; /* Quantité nécessaire */ GTypeQuery query; /* Informations sur un type */ guint size; /* Taille de la table */ void count_shared_instances(const GSharedInstance *key, gpointer unused, unsigned int *c) { *c += g_shared_instance_get_references(key); } counter = 0; g_mutex_lock(&manager->access); g_hash_table_foreach(manager->table, (GHFunc)count_shared_instances, &counter); size = g_hash_table_size(manager->table); g_mutex_unlock(&manager->access); g_type_query(manager->managed, &query); printf("%s: current = %u / %u - needed = %u / %u (size=%u, saved=%u)\n", query.type_name, size, size * query.instance_size, counter, counter * query.instance_size, query.instance_size, (counter - size) * query.instance_size); } #endif