version 1.2, 2015/01/08 16:05:31
|
version 1.8, 2015/02/19 11:01:17
|
Line 1
|
Line 1
|
/* |
/* |
================================================================================ |
================================================================================ |
RPL/2 (R) version 4.1.20 |
RPL/2 (R) version 4.1.21 |
Copyright (C) 1989-2015 Dr. BERTRAND Joël |
Copyright (C) 1989-2015 Dr. BERTRAND Joël |
|
|
This file is part of RPL/2. |
This file is part of RPL/2. |
Line 22
|
Line 22
|
|
|
#include "rpl-conv.h" |
#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[] = |
static size_t tailles[] = |
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, |
{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, |
Line 45 static int longueur_tailles = 0;
|
Line 57 static int longueur_tailles = 0;
|
*/ |
*/ |
|
|
static int |
static int |
recherche_longueur_buffer_optimale(integer8 longueur) |
recherche_longueur_buffer_optimale(size_t longueur) |
{ |
{ |
int a; |
int a; |
int b; |
int b; |
Line 54 recherche_longueur_buffer_optimale(integ
|
Line 66 recherche_longueur_buffer_optimale(integ
|
a = 0; |
a = 0; |
b = longueur_tailles - 1; |
b = longueur_tailles - 1; |
|
|
if (longueur > ((integer8) tailles[b])) |
if (longueur > tailles[b]) |
{ |
{ |
return(-1); |
return(-1); |
} |
} |
Line 63 recherche_longueur_buffer_optimale(integ
|
Line 75 recherche_longueur_buffer_optimale(integ
|
{ |
{ |
m = (a + b) / 2; |
m = (a + b) / 2; |
|
|
if (longueur <= ((integer8) tailles[m])) |
if (longueur <= tailles[m]) |
{ |
{ |
b = m; |
b = m; |
} |
} |
Line 79 recherche_longueur_buffer_optimale(integ
|
Line 91 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 : pointeur sur une structure struct_buffer (ou NULL) |
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 : néant |
-------------------------------------------------------------------------------- |
-------------------------------------------------------------------------------- |
Effets de bord : néant |
Effets de bord : néant |
================================================================================ |
================================================================================ |
Line 100 initialisation_allocateur_buffer(struct_
|
Line 186 initialisation_allocateur_buffer(struct_
|
{ |
{ |
longueur_tailles++; |
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) |
longueur_tailles) * sizeof(unsigned char **))) == NULL) |
{ |
{ |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
return; |
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) |
longueur_tailles) * sizeof(int))) == NULL) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
|
return; |
|
} |
|
|
|
for(i = 0; i < longueur_tailles; i++) |
|
{ |
|
if (((*s_etat_processus).cache_buffer[i] = |
|
sys_malloc(TAILLE_CACHE * sizeof(unsigned char *))) == NULL) |
{ |
{ |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
return; |
return; |
} |
} |
|
|
for(i = 0; i < longueur_tailles; i++) |
(*s_etat_processus).pointeur_cache_buffer[i] = 0; |
{ |
|
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).pointeur_enveloppes_buffers = 0; |
return; |
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 |
void |
liberation_allocateur_buffer(struct_processus *s_etat_processus) |
liberation_allocateur_buffer(struct_processus *s_etat_processus) |
{ |
{ |
Line 142 liberation_allocateur_buffer(struct_proc
|
Line 242 liberation_allocateur_buffer(struct_proc
|
{ |
{ |
for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++) |
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]); |
sys_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); |
|
} |
|
} |
|
|
|
return(NULL); |
|
} |
|
|
|
|
sys_free((*s_etat_processus).cache_buffer); |
|
sys_free((*s_etat_processus).pointeur_cache_buffer); |
|
|
static inline void |
for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++) |
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 |
sys_free((*s_etat_processus).enveloppes_buffers[i]); |
[(*s_etat_processus).pointeur_enveloppes_buffers++] = s_buffer; |
|
} |
|
else |
|
{ |
|
free(s_buffer); |
|
} |
} |
|
|
return; |
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 * |
struct_buffer * |
allocation_buffer(struct_processus *s_etat_processus, integer8 longueur) |
allocation_buffer(struct_processus *s_etat_processus, size_t longueur) |
{ |
{ |
int classe; |
int classe; |
|
|
struct_buffer *s_buffer; |
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; |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
return(NULL); |
return(NULL); |
} |
} |
|
|
classe = recherche_longueur_buffer_optimale(longueur); |
if (longueur == 0) |
|
|
if (classe >= 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] |
// La classe correspond à la longueur effectivement disponible |
[--(*s_etat_processus).pointeur_cache_buffer[classe]]; |
// 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 |
else |
{ |
{ |
if (((*s_buffer).buffer = malloc(tailles[classe] * |
if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) * |
sizeof(unsigned char))) == NULL) |
sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL) |
{ |
{ |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
return(NULL); |
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).classe = classe; |
(*s_buffer).longueur_requise = longueur; |
(*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 |
void |
liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer) |
liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer) |
{ |
{ |
if ((*s_buffer).classe < 0) |
if ((*s_buffer).classe < 0) |
{ |
{ |
free((*s_buffer).buffer); |
if ((*s_buffer).buffer != NULL) |
|
{ |
|
sys_free((*s_buffer).buffer); |
|
} |
} |
} |
else |
else |
{ |
{ |
Line 264 liberation_buffer(struct_processus *s_et
|
Line 375 liberation_buffer(struct_processus *s_et
|
} |
} |
else |
else |
{ |
{ |
free((*s_buffer).buffer); |
sys_free((*s_buffer).buffer); |
} |
} |
} |
} |
|
|
Line 272 liberation_buffer(struct_processus *s_et
|
Line 383 liberation_buffer(struct_processus *s_et
|
return; |
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 (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_processus; |
|
return(NULL); |
|
} |
|
|
|
if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL) |
|
{ |
|
pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer)); |
|
|
|
(*s_etat_processus).erreur_systeme = d_es_allocation_memoire; |
|
return(NULL); |
|
} |
|
|
|
pointeur = (*s_buffer).buffer + sizeof(struct_buffer *); |
|
|
|
if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer)) |
|
!= 0) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_processus; |
|
return(NULL); |
|
} |
|
|
|
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 (ptr == NULL) |
|
{ |
|
return(rpl_malloc(s_etat_processus, s)); |
|
} |
|
|
|
if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_processus; |
|
return(NULL); |
|
} |
|
|
|
if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL) |
|
{ |
|
pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer)); |
|
|
|
(*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 *); |
|
|
|
if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer)) |
|
!= 0) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_processus; |
|
return(NULL); |
|
} |
|
|
|
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 *)))); |
|
|
|
if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_processus; |
|
return; |
|
} |
|
|
|
liberation_buffer(s_etat_processus, s_buffer); |
|
|
|
if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer)) |
|
!= 0) |
|
{ |
|
(*s_etat_processus).erreur_systeme = d_es_processus; |
|
return; |
|
} |
|
|
|
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); |
|
return; |
|
} |
|
|
// vim: ts=4 |
// vim: ts=4 |