From 0fac40d5a5752e8d7b92f57ea3cfa089f13a2d1f Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 21 Jan 2024 00:04:22 +0100
Subject: Define a memory allocator for large sets.

---
 src/glibext/Makefile.am     |   4 +-
 src/glibext/umemslice-int.h |  71 ++++++++
 src/glibext/umemslice.c     | 423 ++++++++++++++++++++++++++++++++++++++++++++
 src/glibext/umemslice.h     |  80 +++++++++
 4 files changed, 577 insertions(+), 1 deletion(-)
 create mode 100644 src/glibext/umemslice-int.h
 create mode 100644 src/glibext/umemslice.c
 create mode 100644 src/glibext/umemslice.h

diff --git a/src/glibext/Makefile.am b/src/glibext/Makefile.am
index ad98809..986bbd1 100644
--- a/src/glibext/Makefile.am
+++ b/src/glibext/Makefile.am
@@ -30,7 +30,9 @@ libglibext_la_SOURCES =						\
 	seq.h seq.c								\
 	signal.h signal.c						\
 	singleton.h singleton.c					\
-	linesegment.h linesegment.c
+	linesegment.h linesegment.c				\
+	umemslice-int.h							\
+	umemslice.h umemslice.c
 
 if BUILD_GTK_SUPPORT
 
diff --git a/src/glibext/umemslice-int.h b/src/glibext/umemslice-int.h
new file mode 100644
index 0000000..36cc2d4
--- /dev/null
+++ b/src/glibext/umemslice-int.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * umemslice-int.h - prototypes internes pour les allocations en série d'un même type d'objets
+ *
+ * Copyright (C) 2023 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_UMEMSLICE_INT_H
+#define _GLIBEXT_UMEMSLICE_INT_H
+
+
+#include <stdbool.h>
+
+
+#include "umemslice.h"
+
+
+
+/* Informations portant sur un bloc */
+typedef struct _slice_slab_info_t
+{
+    void *data_max;                         /* Zone de débordement         */
+    umem_slice_iter_t iter;                 /* Données pour l'utilisateur  */
+
+} slice_slab_info_t;
+
+#define SLICE_INFO_SIZE (sizeof(void *) + sizeof(umem_slice_iter_t))
+
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (instance) */
+struct _GUMemSlice
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    size_t obj_size;                        /* Taille des objects          */
+
+    slice_slab_info_t *slabs;               /* Ensembles complets          */
+    slice_slab_info_t *last;                /* Accès à l'ultime tranche    */
+
+};
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (classe) */
+struct _GUMemSliceClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+};
+
+
+/* Met en place un allocateur de zones identiques. */
+bool g_umem_slice_create(GUMemSlice *, size_t);
+
+
+
+#endif  /* _GLIBEXT_UMEMSLICE_INT_H */
diff --git a/src/glibext/umemslice.c b/src/glibext/umemslice.c
new file mode 100644
index 0000000..1bdb4fe
--- /dev/null
+++ b/src/glibext/umemslice.c
@@ -0,0 +1,423 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * umemslice.c - allocations en série d'un même type d'objets
+ *
+ * Copyright (C) 2023 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "umemslice.h"
+
+
+#include <assert.h>
+#include <stdint.h>
+#include <sys/mman.h>
+
+
+#include "umemslice-int.h"
+#include "../core/logs.h"
+
+
+
+/* --------------------------- GESTION D'UN BLOC D'OBJETS --------------------------- */
+
+
+#define SLAB_SIZE (8 * 1024 * 1024)
+//#define SLAB_SIZE (32 * 1024)
+
+/*  Alloue un espace pour un nouveau slab en mémoire. */
+static slice_slab_info_t *create_slice_slab(size_t, size_t);
+
+/* Supprime l'espace correspondant à un slab en mémoire. */
+static void destroy_slice_slab(slice_slab_info_t *, size_t);
+
+
+
+/* --------------------------- ALLOCATIONS ET LIBERATIONS --------------------------- */
+
+
+/* Initialise la classe des allocateurs d'objets similaires. */
+static void g_umem_slice_class_init(GUMemSliceClass *);
+
+/* Initialise une instance d'allocateur d'objets similaires. */
+static void g_umem_slice_init(GUMemSlice *);
+
+/* Supprime toutes les références externes. */
+static void g_umem_slice_dispose(GUMemSlice *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_umem_slice_finalize(GUMemSlice *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                             GESTION D'UN BLOC D'OBJETS                             */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slab_size = taille totale du slab à allouer.                 *
+*                obj_size  = taille des futurs objets contenus.               *
+*                                                                             *
+*  Description : Alloue un espace pour un nouveau slab en mémoire.            *
+*                                                                             *
+*  Retour      : Adresse du gestionnaire du slab mis en place.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static slice_slab_info_t *create_slice_slab(size_t slab_size, size_t obj_size)
+{
+    slice_slab_info_t *result;              /* Structure à retourner       */
+    void *data;                             /* Zone de mémoire allouée     */
+    int ret;                                /* Bilan d'une précision       */
+    size_t quantity;                        /* Quantité d'objets allouable */
+
+    assert(obj_size % sizeof(unsigned long) == 0);
+
+    data = mmap(NULL, slab_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS/* | MAP_POPULATE*/, -1, 0);
+
+    if (data == MAP_FAILED)
+    {
+        LOG_ERROR_N("mmap");
+        result = NULL;
+        goto exit;
+    }
+
+    ret = madvise(data, slab_size, MADV_SEQUENTIAL);
+    if (ret == -1)
+        LOG_ERROR_N("madvise");
+
+    /* Initialisation du gestionnaire */
+
+    result = data;
+
+    quantity = (slab_size - SLICE_INFO_SIZE) / obj_size;
+
+    //result->data_max = ((uint8_t *)data) + (quantity * obj_size);
+
+    result->iter.data_end = ((uint8_t *)data) + SLICE_INFO_SIZE;
+    result->iter.next = NULL;
+
+    result->data_max = result->iter.data_end + (quantity * obj_size);
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slab      = gestionnaire d'une zone mémoire à manipuler.     *
+*                slab_size = taille totale du slab à allouer.                 *
+*                                                                             *
+*  Description : Supprime l'espace correspondant à un slab en mémoire.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void destroy_slice_slab(slice_slab_info_t *slab, size_t slab_size)
+{
+    void *data;                             /* Zone de mémoire allouée     */
+    int ret;                                /* Bilan de l'opération        */
+
+    data = slab;
+
+    ret = munmap(data, slab_size);
+
+    if (ret == -1)
+        LOG_ERROR_N("munmap");
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                             ALLOCATIONS ET LIBERATIONS                             */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un allocateur en série d'objets depuis une même zone mémoire. */
+G_DEFINE_TYPE(GUMemSlice, g_umem_slice, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des allocateurs d'objets similaires.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_umem_slice_class_init(GUMemSliceClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_umem_slice_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_umem_slice_finalize;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = instance à initialiser.                              *
+*                                                                             *
+*  Description : Initialise une instance d'allocateur d'objets similaires.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_umem_slice_init(GUMemSlice *slice)
+{
+    slice->obj_size = 0;
+
+    slice->slabs = NULL;
+    slice->last = NULL;
+
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = instance d'objet GLib à traiter.                     *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_umem_slice_dispose(GUMemSlice *slice)
+{
+    G_OBJECT_CLASS(g_umem_slice_parent_class)->dispose(G_OBJECT(slice));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = instance d'objet GLib à traiter.                     *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_umem_slice_finalize(GUMemSlice *slice)
+{
+    slice_slab_info_t *slab;                /* Slab à libérer entièrement  */
+    slice_slab_info_t *next;                /* Slab suivant à traiter      */
+
+    for (slab = slice->slabs; slab != NULL; slab = next)
+    {
+        if (slab->iter.next == NULL)
+            next = NULL;
+        else
+            next = (slice_slab_info_t *)(((uint8_t *)slab->iter.next) - sizeof(void *));
+
+        destroy_slice_slab(slab, SLAB_SIZE);
+
+    }
+
+    G_OBJECT_CLASS(g_umem_slice_parent_class)->finalize(G_OBJECT(slice));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : size = taille des objets à allouer en mémoire.               *
+*                                                                             *
+*  Description : Crée un allocateur dédié à la création de zones identiques.  *
+*                                                                             *
+*  Retour      : Allocateur mis en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GUMemSlice *g_umem_slice_new(size_t size)
+{
+    GUMemSlice *result;                     /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_UMEM_SLICE, NULL);
+
+    if (!g_umem_slice_create(result, size))
+        g_clear_object(&result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = instance à initialiser pleinement.                   *
+*                size  = taille des objets à allouer en mémoire.              *
+*                                                                             *
+*  Description : Met en place un allocateur de zones identiques.              *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_umem_slice_create(GUMemSlice *slice, size_t size)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    slice->obj_size = size;
+
+    slice->slabs = create_slice_slab(SLAB_SIZE, size);
+    slice->last = slice->slabs;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = allocateur à manipuler.                              *
+*                                                                             *
+*  Description : Alloue une nouvelle zone de la taille attendue en mémoire.   *
+*                                                                             *
+*  Retour      : Adresse de la zone nouvellement disponible ou NULL.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void *g_umem_slice_alloc(GUMemSlice *slice)
+{
+    void *result;                           /* Allocation à retourner      */
+    slice_slab_info_t *slab;                /* Slab concerné par l'opérat° */
+    umem_slice_iter_t *iter;                /* Tête d'écriture courante    */
+
+    slab = slice->last;
+
+    assert(slab != NULL);
+
+    if (slab->iter.data_end == slab->data_max)
+    {
+        slice->last = create_slice_slab(SLAB_SIZE, slice->obj_size);
+
+        slab->iter.next = &slice->last->iter;
+
+        slab = slice->last;
+
+    }
+
+    iter = &slab->iter;
+
+    result = iter->data_end;
+
+    *((unsigned long *)&iter->data_end) += slice->obj_size;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = allocateur à manipuler.                              *
+*                val   = valeur de 64 bits à intégrer.                        *
+*                                                                             *
+*  Description : Mémorise un mot de 64 bits dans une nouvelle zone en mémoire.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_umem_slice_put_uint64(GUMemSlice *slice, uint64_t val)
+{
+    slice_slab_info_t *slab;                /* Slab concerné par l'opérat° */
+
+    assert(slice->obj_size == sizeof(uint64_t));
+
+    slab = slice->last;
+
+    assert(slab != NULL);
+
+    if (slab->iter.data_end == slab->data_max)
+    {
+        slice->last = create_slice_slab(SLAB_SIZE, slice->obj_size);
+
+        slab->iter.next = &slice->last->iter;
+
+        slab = slice->last;
+
+    }
+
+    *slab->iter.data_end_uint64 = val;
+
+    slab->iter.data_end_ul += slice->obj_size;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : slice = allocateur à consulter.                              *
+*                                                                             *
+*  Description : Fournit un itérateur pour les données allouées.              *
+*                                                                             *
+*  Retour      : Premier descripteur des données allouées.                    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const umem_slice_iter_t *g_umem_slice_get_iter(const GUMemSlice *slice)
+{
+    const umem_slice_iter_t *result;        /* Pointeur à retourner        */
+
+    result = &slice->slabs->iter;
+
+    return result;
+
+}
diff --git a/src/glibext/umemslice.h b/src/glibext/umemslice.h
new file mode 100644
index 0000000..54b8433
--- /dev/null
+++ b/src/glibext/umemslice.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * umemslice.h - prototypes pour les allocations en série d'un même type d'objets
+ *
+ * Copyright (C) 2023 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 Chrysalide.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_UMEMSLICE_H
+#define _GLIBEXT_UMEMSLICE_H
+
+
+#include <glib-object.h>
+#include <stdint.h>
+
+
+
+#define G_TYPE_UMEM_SLICE            g_umem_slice_get_type()
+#define G_UMEM_SLICE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_UMEM_SLICE, GUMemSlice))
+#define G_IS_UMEM_SLICE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_UMEM_SLICE))
+#define G_UMEM_SLICE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_UMEM_SLICE, GUMemSliceClass))
+#define G_IS_UMEM_SLICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_UMEM_SLICE))
+#define G_UMEM_SLICE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_UMEM_SLICE, GUMemSliceClass))
+
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (instance) */
+typedef struct _GUMemSlice GUMemSlice;
+
+/* Allocateur s'appuyant sur des séries d'objets de même type (classe) */
+typedef struct _GUMemSliceClass GUMemSliceClass;
+
+
+/* Indique le type défini pour un allocateur en série d'objets depuis une même zone mémoire. */
+GType g_umem_slice_get_type(void);
+
+/* Crée un allocateur dédié à la création de zones identiques. */
+GUMemSlice *g_umem_slice_new(size_t);
+
+/* Alloue une nouvelle zone de la taille attendue en mémoire. */
+void *g_umem_slice_alloc(GUMemSlice *);
+
+/* Mémorise un mot de 64 bits dans une nouvelle zone en mémoire. */
+void g_umem_slice_put_uint64(GUMemSlice *, uint64_t);
+
+/* Itérateur pour tranches de mémoire */
+typedef struct _umem_slice_iter_t
+{
+    union
+    {
+        void *data_end;                         /* Première zone libre         */
+        uint64_t *data_end_uint64;
+        unsigned long data_end_ul;
+    };
+    struct _umem_slice_iter_t *next;        /* Lien vers tranche suivante  */
+
+    void *data[0];                          /* Accès au premier élément    */
+
+} umem_slice_iter_t;
+
+/* Fournit un itérateur pour les données allouées. */
+const umem_slice_iter_t *g_umem_slice_get_iter(const GUMemSlice *);
+
+
+
+#endif  /* _GLIBEXT_UMEMSLICE_H */
-- 
cgit v0.11.2-87-g4458