/* 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 .
*/
#include "umemslice.h"
#include
#include
#include
#include "umemslice-int.h"
#include "../core/logs.h"
/* --------------------------- GESTION D'UN BLOC D'OBJETS --------------------------- */
#define SLAB_SIZE (8 * 1024 * 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;
iter->data_end_ul += 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;
}