--- rpl/src/allocateur.c 2015/01/08 16:05:31 1.2 +++ rpl/src/allocateur.c 2015/01/27 14:18:05 1.3 @@ -22,6 +22,18 @@ #include "rpl-conv.h" +// Les fonctions malloc() et free() sont surchargées pour appeler +// les fonctions rpl_malloc() et rpl_free(). Elles sont désactivées pour +// éviter d'avoir un allocateur récursif. + +#undef malloc +#undef realloc +#undef free + +// Classes : +// -1 : trop grand pour utiliser l'allocateur, on utilise l'allocateur par +// défaut du système. La classe -1 est aussi utilisée lorsque le buffer +// n'a pas encore été alloué. Dans ce cas, il est initialisé à NULL. static size_t tailles[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, @@ -45,7 +57,7 @@ static int longueur_tailles = 0; */ static int -recherche_longueur_buffer_optimale(integer8 longueur) +recherche_longueur_buffer_optimale(size_t longueur) { int a; int b; @@ -54,7 +66,7 @@ recherche_longueur_buffer_optimale(integ a = 0; b = longueur_tailles - 1; - if (longueur > ((integer8) tailles[b])) + if (longueur > tailles[b]) { return(-1); } @@ -63,7 +75,7 @@ recherche_longueur_buffer_optimale(integ { m = (a + b) / 2; - if (longueur <= ((integer8) tailles[m])) + if (longueur <= tailles[m]) { b = m; } @@ -79,11 +91,85 @@ recherche_longueur_buffer_optimale(integ /* ================================================================================ - Allocateur de mémoire fonctionnant avec un cache + Allocation d'une enveloppe de buffer + + Contrairement au malloc() de la libc, cet allocateur fournit une structure + (l'enveloppe) contenant un pointeur sur la zone allouée ainsi que la longueur + de la zone allouée et une information de classe pour gérer le cache. + La zone allouée est comporte un pointeur sur l'enveloppe puis un + buffer traditionnel. ================================================================================ - Entrée : longueur du buffer à allouer + Entrée : état du processus courant +-------------------------------------------------------------------------------- + Sortie : enveloppe de buffer +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + +static inline struct_buffer * +allocation_enveloppe_buffer(struct_processus *s_etat_processus) +{ + struct_buffer *s_buffer; + + if ((*s_etat_processus).pointeur_enveloppes_buffers > 0) + { + s_buffer = (*s_etat_processus).enveloppes_buffers + [--(*s_etat_processus).pointeur_enveloppes_buffers]; + } + else + { + if ((s_buffer = sys_malloc(sizeof(struct_buffer))) == NULL) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return(NULL); + } + } + + return(s_buffer); +} + + +/* +================================================================================ + Libération d'une enveloppe de buffer + + Ne libère pas le buffer qui doit être libéré à part. +================================================================================ + Entrée : état du processus courant, enveloppe +-------------------------------------------------------------------------------- + Sortie : néant +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + +static inline void +liberation_enveloppe_buffer(struct_processus *s_etat_processus, + struct_buffer *s_buffer) +{ + if ((*s_etat_processus).pointeur_enveloppes_buffers < TAILLE_CACHE) + { + (*s_etat_processus).enveloppes_buffers + [(*s_etat_processus).pointeur_enveloppes_buffers++] = s_buffer; + } + else + { + sys_free(s_buffer); + } + + return; +} + + +/* +================================================================================ + Initialisation des structures de données de l'allocateur +================================================================================ + Entrée : état du processus courant (contient les données nécessaires + au fonctionnement de l'allocateur par thread) -------------------------------------------------------------------------------- - Sortie : pointeur sur une structure struct_buffer (ou NULL) + Sortie : néant -------------------------------------------------------------------------------- Effets de bord : néant ================================================================================ @@ -101,37 +187,51 @@ initialisation_allocateur_buffer(struct_ longueur_tailles++; } - if (((*s_etat_processus).cache_buffer = malloc(((size_t) + if (((*s_etat_processus).cache_buffer = sys_malloc(((size_t) longueur_tailles) * sizeof(unsigned char **))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } - if (((*s_etat_processus).pointeur_cache_buffer = malloc(((size_t) + if (((*s_etat_processus).pointeur_cache_buffer = sys_malloc(((size_t) longueur_tailles) * sizeof(int))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return; } + } - for(i = 0; i < longueur_tailles; i++) + for(i = 0; i < longueur_tailles; i++) + { + if (((*s_etat_processus).cache_buffer[i] = + sys_malloc(TAILLE_CACHE * sizeof(unsigned char *))) == NULL) { - if (((*s_etat_processus).cache_buffer[i] = - malloc(TAILLE_CACHE * sizeof(unsigned char *))) == NULL) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return; - } - - (*s_etat_processus).pointeur_cache_buffer[i] = 0; + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return; } + + (*s_etat_processus).pointeur_cache_buffer[i] = 0; } + (*s_etat_processus).pointeur_enveloppes_buffers = 0; return; } +/* +================================================================================ + Libération des structures de données de l'allocateur +================================================================================ + Entrée : état du processus courant (contient les données nécessaires + au fonctionnement de l'allocateur par thread) +-------------------------------------------------------------------------------- + Sortie : néant +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + void liberation_allocateur_buffer(struct_processus *s_etat_processus) { @@ -142,116 +242,127 @@ liberation_allocateur_buffer(struct_proc { for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++) { - free((*s_etat_processus).cache_buffer[i][j]); + sys_free((*s_etat_processus).cache_buffer[i][j]); } - free((*s_etat_processus).cache_buffer[i]); - } - - free((*s_etat_processus).cache_buffer); - return; -} - - -static inline struct_buffer * -allocation_enveloppe_buffer(struct_processus *s_etat_processus) -{ - struct_buffer *s_buffer; - - if ((*s_etat_processus).pointeur_enveloppes_buffers > 0) - { - s_buffer = (*s_etat_processus).enveloppes_buffers - [--(*s_etat_processus).pointeur_enveloppes_buffers]; - } - else - { - if ((s_buffer = malloc(sizeof(struct_buffer))) == NULL) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } + sys_free((*s_etat_processus).cache_buffer[i]); } - return(NULL); -} - + sys_free((*s_etat_processus).cache_buffer); + sys_free((*s_etat_processus).pointeur_cache_buffer); -static inline void -liberation_enveloppe_buffer(struct_processus *s_etat_processus, - struct_buffer *s_buffer) -{ - if ((*s_etat_processus).pointeur_enveloppes_buffers < TAILLE_CACHE) - { - (*s_etat_processus).enveloppes_buffers - [(*s_etat_processus).pointeur_enveloppes_buffers++] = s_buffer; - } - else + for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++) { - free(s_buffer); + sys_free((*s_etat_processus).enveloppes_buffers[i]); } return; } +/* +================================================================================ + Allocation d'un buffer et de son enveloppe +================================================================================ + Entrée : état du processus courant, longueur du buffer +-------------------------------------------------------------------------------- + Sortie : néant +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + struct_buffer * -allocation_buffer(struct_processus *s_etat_processus, integer8 longueur) +allocation_buffer(struct_processus *s_etat_processus, size_t longueur) { int classe; struct_buffer *s_buffer; - if (allocation_enveloppe_buffer(s_etat_processus) == NULL) + if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); } - classe = recherche_longueur_buffer_optimale(longueur); - - if (classe >= 0) + if (longueur == 0) { - if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0) + (*s_buffer).buffer = NULL; + classe = -1; + } + else + { + classe = recherche_longueur_buffer_optimale(longueur); + + if (classe >= 0) { - (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe] - [--(*s_etat_processus).pointeur_cache_buffer[classe]]; + // La classe correspond à la longueur effectivement disponible + // dans le buffer alloué. Or il faut ajouter à ce buffer un + // pointeur vers l'enveloppe (struct_buffer *). + + if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0) + { + (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe] + [--(*s_etat_processus).pointeur_cache_buffer[classe]]; + } + else + { + if (((*s_buffer).buffer = sys_malloc((tailles[classe] * + sizeof(unsigned char)) + sizeof(struct_buffer *))) + == NULL) + { + (*s_etat_processus).erreur_systeme = + d_es_allocation_memoire; + return(NULL); + } + } } else { - if (((*s_buffer).buffer = malloc(tailles[classe] * - sizeof(unsigned char))) == NULL) + if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) * + sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL) { (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; return(NULL); } } } - else - { - if (((*s_buffer).buffer = malloc(((size_t) longueur) * - sizeof(unsigned char))) == NULL) - { - (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; - return(NULL); - } - } - - BUG((longueur > ((integer8) tailles[classe])), - uprintf("Bad buffer class !\n")); (*s_buffer).classe = classe; (*s_buffer).longueur_requise = longueur; - return(NULL); + // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se + // compose d'un pointeur vers s_buffer suivi d'une zone variable. + // s_buffer est le pointeur sur l'enveloppe. + // (*s_buffer).buffer est le pointeur sur le début de la zone allouée + // aux données. + (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer; + + return(s_buffer); } +/* +================================================================================ + Libération d'un buffer et de son enveloppe +================================================================================ + Entrée : état du processus courant, longueur du buffer +-------------------------------------------------------------------------------- + Sortie : néant +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + void liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer) { if ((*s_buffer).classe < 0) { - free((*s_buffer).buffer); + if ((*s_buffer).buffer != NULL) + { + sys_free((*s_buffer).buffer); + } } else { @@ -264,7 +375,7 @@ liberation_buffer(struct_processus *s_et } else { - free((*s_buffer).buffer); + sys_free((*s_buffer).buffer); } } @@ -272,4 +383,125 @@ liberation_buffer(struct_processus *s_et return; } + +/* +================================================================================ + Allocation d'un buffer et de son enveloppe. Le pointeur retourné est + le pointeur sur le début de la zone utilisable pour être conforme au + malloc() de la libc. +================================================================================ + Entrée : état du processus courant, longueur du buffer +-------------------------------------------------------------------------------- + Sortie : pointeur sur un void +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + +void * +rpl_malloc(struct_processus *s_etat_processus, size_t s) +{ + struct_buffer *s_buffer; + + void *pointeur; + + if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return(NULL); + } + + pointeur = (*s_buffer).buffer + sizeof(struct_buffer *); + return(pointeur); +} + + +/* +================================================================================ + Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est + le pointeur sur le début de la zone utilisable pour être conforme au + malloc() de la libc. +================================================================================ + Entrée : état du processus courant, longueur du buffer +-------------------------------------------------------------------------------- + Sortie : pointeur sur un void +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + +void * +rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s) +{ + struct_buffer *s_ancien_buffer; + struct_buffer *s_nouveau_buffer; + + size_t longueur_copie; + + void *pointeur; + + if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL) + { + (*s_etat_processus).erreur_systeme = d_es_allocation_memoire; + return(NULL); + } + + s_ancien_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *)))); + + longueur_copie = ((*s_ancien_buffer).longueur_requise > s) + ? s : (*s_ancien_buffer).longueur_requise; + + memcpy((*s_nouveau_buffer).buffer + sizeof(struct_buffer *), + (*s_ancien_buffer).buffer + sizeof(struct_buffer *), + longueur_copie); + + liberation_buffer(s_etat_processus, s_ancien_buffer); + pointeur = (*s_nouveau_buffer).buffer + sizeof(struct_buffer *); + + return(pointeur); +} + + +/* +================================================================================ + Libération d'un buffer et de son enveloppe. +================================================================================ + Entrée : état du processus courant, longueur du buffer +-------------------------------------------------------------------------------- + Sortie : pointeur sur un void +-------------------------------------------------------------------------------- + Effets de bord : néant +================================================================================ +*/ + +void +rpl_free(struct_processus *s_etat_processus, void *ptr) +{ + struct_buffer *s_buffer; + + if (ptr == NULL) + { + return; + } + + s_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *)))); + liberation_buffer(s_etat_processus, s_buffer); + return; +} + + +// Réécriture des fonctions malloc() et free() de la libc + +void * +sys_malloc(size_t s) +{ + return(malloc(s)); +} + +void +sys_free(void *ptr) +{ + free(ptr); +} + // vim: ts=4