Annotation of rpl/src/allocateur.c, revision 1.3
1.1 bertrand 1: /*
2: ================================================================================
3: RPL/2 (R) version 4.1.20
4: Copyright (C) 1989-2015 Dr. BERTRAND Joël
5:
6: This file is part of RPL/2.
7:
8: RPL/2 is free software; you can redistribute it and/or modify it
9: under the terms of the CeCILL V2 License as published by the french
10: CEA, CNRS and INRIA.
11:
12: RPL/2 is distributed in the hope that it will be useful, but WITHOUT
13: ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14: FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL V2 License
15: for more details.
16:
17: You should have received a copy of the CeCILL License
18: along with RPL/2. If not, write to info@cecill.info.
19: ================================================================================
20: */
21:
22:
23: #include "rpl-conv.h"
24:
1.3 ! bertrand 25: // Les fonctions malloc() et free() sont surchargées pour appeler
! 26: // les fonctions rpl_malloc() et rpl_free(). Elles sont désactivées pour
! 27: // éviter d'avoir un allocateur récursif.
! 28:
! 29: #undef malloc
! 30: #undef realloc
! 31: #undef free
! 32:
! 33: // Classes :
! 34: // -1 : trop grand pour utiliser l'allocateur, on utilise l'allocateur par
! 35: // défaut du système. La classe -1 est aussi utilisée lorsque le buffer
! 36: // n'a pas encore été alloué. Dans ce cas, il est initialisé à NULL.
1.1 bertrand 37:
38: static size_t tailles[] =
39: { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
40: 11, 12, 13, 14, 15, 16, 24, 32, 48, 64,
41: 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048,
42: 3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536,
43: 0 };
44: static int longueur_tailles = 0;
45:
46:
47: /*
48: ================================================================================
49: Recherche de la longueur optimale du buffer
50: ================================================================================
51: Entrée : longueur du buffer à allouer
52: --------------------------------------------------------------------------------
53: Sortie : indice de la liste candidate, -1 si aucune liste
54: --------------------------------------------------------------------------------
55: Effets de bord : néant
56: ================================================================================
57: */
58:
59: static int
1.3 ! bertrand 60: recherche_longueur_buffer_optimale(size_t longueur)
1.1 bertrand 61: {
62: int a;
63: int b;
64: int m;
65:
66: a = 0;
67: b = longueur_tailles - 1;
68:
1.3 ! bertrand 69: if (longueur > tailles[b])
1.1 bertrand 70: {
71: return(-1);
72: }
73:
74: while((b - a) > 1)
75: {
76: m = (a + b) / 2;
77:
1.3 ! bertrand 78: if (longueur <= tailles[m])
1.1 bertrand 79: {
80: b = m;
81: }
82: else
83: {
84: a = m;
85: }
86: }
87:
88: return(b);
89: }
90:
91:
92: /*
93: ================================================================================
1.3 ! bertrand 94: Allocation d'une enveloppe de buffer
! 95:
! 96: Contrairement au malloc() de la libc, cet allocateur fournit une structure
! 97: (l'enveloppe) contenant un pointeur sur la zone allouée ainsi que la longueur
! 98: de la zone allouée et une information de classe pour gérer le cache.
! 99: La zone allouée est comporte un pointeur sur l'enveloppe puis un
! 100: buffer traditionnel.
! 101: ================================================================================
! 102: Entrée : état du processus courant
! 103: --------------------------------------------------------------------------------
! 104: Sortie : enveloppe de buffer
! 105: --------------------------------------------------------------------------------
! 106: Effets de bord : néant
! 107: ================================================================================
! 108: */
! 109:
! 110: static inline struct_buffer *
! 111: allocation_enveloppe_buffer(struct_processus *s_etat_processus)
! 112: {
! 113: struct_buffer *s_buffer;
! 114:
! 115: if ((*s_etat_processus).pointeur_enveloppes_buffers > 0)
! 116: {
! 117: s_buffer = (*s_etat_processus).enveloppes_buffers
! 118: [--(*s_etat_processus).pointeur_enveloppes_buffers];
! 119: }
! 120: else
! 121: {
! 122: if ((s_buffer = sys_malloc(sizeof(struct_buffer))) == NULL)
! 123: {
! 124: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
! 125: return(NULL);
! 126: }
! 127: }
! 128:
! 129: return(s_buffer);
! 130: }
! 131:
! 132:
! 133: /*
! 134: ================================================================================
! 135: Libération d'une enveloppe de buffer
! 136:
! 137: Ne libère pas le buffer qui doit être libéré à part.
! 138: ================================================================================
! 139: Entrée : état du processus courant, enveloppe
! 140: --------------------------------------------------------------------------------
! 141: Sortie : néant
! 142: --------------------------------------------------------------------------------
! 143: Effets de bord : néant
! 144: ================================================================================
! 145: */
! 146:
! 147: static inline void
! 148: liberation_enveloppe_buffer(struct_processus *s_etat_processus,
! 149: struct_buffer *s_buffer)
! 150: {
! 151: if ((*s_etat_processus).pointeur_enveloppes_buffers < TAILLE_CACHE)
! 152: {
! 153: (*s_etat_processus).enveloppes_buffers
! 154: [(*s_etat_processus).pointeur_enveloppes_buffers++] = s_buffer;
! 155: }
! 156: else
! 157: {
! 158: sys_free(s_buffer);
! 159: }
! 160:
! 161: return;
! 162: }
! 163:
! 164:
! 165: /*
! 166: ================================================================================
! 167: Initialisation des structures de données de l'allocateur
1.1 bertrand 168: ================================================================================
1.3 ! bertrand 169: Entrée : état du processus courant (contient les données nécessaires
! 170: au fonctionnement de l'allocateur par thread)
1.1 bertrand 171: --------------------------------------------------------------------------------
1.3 ! bertrand 172: Sortie : néant
1.1 bertrand 173: --------------------------------------------------------------------------------
174: Effets de bord : néant
175: ================================================================================
176: */
177:
178: void
179: initialisation_allocateur_buffer(struct_processus *s_etat_processus)
180: {
181: int i;
182:
183: if (longueur_tailles == 0)
184: {
185: while(tailles[longueur_tailles] != 0)
186: {
187: longueur_tailles++;
188: }
189:
1.3 ! bertrand 190: if (((*s_etat_processus).cache_buffer = sys_malloc(((size_t)
1.1 bertrand 191: longueur_tailles) * sizeof(unsigned char **))) == NULL)
192: {
193: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
194: return;
195: }
196:
1.3 ! bertrand 197: if (((*s_etat_processus).pointeur_cache_buffer = sys_malloc(((size_t)
1.1 bertrand 198: longueur_tailles) * sizeof(int))) == NULL)
199: {
200: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
201: return;
202: }
1.3 ! bertrand 203: }
1.1 bertrand 204:
1.3 ! bertrand 205: for(i = 0; i < longueur_tailles; i++)
! 206: {
! 207: if (((*s_etat_processus).cache_buffer[i] =
! 208: sys_malloc(TAILLE_CACHE * sizeof(unsigned char *))) == NULL)
1.1 bertrand 209: {
1.3 ! bertrand 210: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
! 211: return;
! 212: }
1.1 bertrand 213:
1.3 ! bertrand 214: (*s_etat_processus).pointeur_cache_buffer[i] = 0;
1.1 bertrand 215: }
216:
1.3 ! bertrand 217: (*s_etat_processus).pointeur_enveloppes_buffers = 0;
1.1 bertrand 218: return;
219: }
220:
221:
1.3 ! bertrand 222: /*
! 223: ================================================================================
! 224: Libération des structures de données de l'allocateur
! 225: ================================================================================
! 226: Entrée : état du processus courant (contient les données nécessaires
! 227: au fonctionnement de l'allocateur par thread)
! 228: --------------------------------------------------------------------------------
! 229: Sortie : néant
! 230: --------------------------------------------------------------------------------
! 231: Effets de bord : néant
! 232: ================================================================================
! 233: */
! 234:
1.1 bertrand 235: void
236: liberation_allocateur_buffer(struct_processus *s_etat_processus)
237: {
238: int i;
239: int j;
240:
241: for(i = 0; i < longueur_tailles; i++)
242: {
243: for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++)
244: {
1.3 ! bertrand 245: sys_free((*s_etat_processus).cache_buffer[i][j]);
1.1 bertrand 246: }
247:
1.3 ! bertrand 248: sys_free((*s_etat_processus).cache_buffer[i]);
1.1 bertrand 249: }
250:
1.3 ! bertrand 251: sys_free((*s_etat_processus).cache_buffer);
! 252: sys_free((*s_etat_processus).pointeur_cache_buffer);
1.1 bertrand 253:
1.3 ! bertrand 254: for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++)
1.1 bertrand 255: {
1.3 ! bertrand 256: sys_free((*s_etat_processus).enveloppes_buffers[i]);
1.1 bertrand 257: }
258:
1.3 ! bertrand 259: return;
1.1 bertrand 260: }
261:
262:
1.3 ! bertrand 263: /*
! 264: ================================================================================
! 265: Allocation d'un buffer et de son enveloppe
! 266: ================================================================================
! 267: Entrée : état du processus courant, longueur du buffer
! 268: --------------------------------------------------------------------------------
! 269: Sortie : néant
! 270: --------------------------------------------------------------------------------
! 271: Effets de bord : néant
! 272: ================================================================================
! 273: */
1.1 bertrand 274:
275: struct_buffer *
1.3 ! bertrand 276: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
1.1 bertrand 277: {
278: int classe;
279:
280: struct_buffer *s_buffer;
281:
1.3 ! bertrand 282: if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
1.1 bertrand 283: {
284: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
285: return(NULL);
286: }
287:
1.3 ! bertrand 288: if (longueur == 0)
! 289: {
! 290: (*s_buffer).buffer = NULL;
! 291: classe = -1;
! 292: }
! 293: else
! 294: {
! 295: classe = recherche_longueur_buffer_optimale(longueur);
1.1 bertrand 296:
1.3 ! bertrand 297: if (classe >= 0)
1.1 bertrand 298: {
1.3 ! bertrand 299: // La classe correspond à la longueur effectivement disponible
! 300: // dans le buffer alloué. Or il faut ajouter à ce buffer un
! 301: // pointeur vers l'enveloppe (struct_buffer *).
! 302:
! 303: if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0)
! 304: {
! 305: (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe]
! 306: [--(*s_etat_processus).pointeur_cache_buffer[classe]];
! 307: }
! 308: else
! 309: {
! 310: if (((*s_buffer).buffer = sys_malloc((tailles[classe] *
! 311: sizeof(unsigned char)) + sizeof(struct_buffer *)))
! 312: == NULL)
! 313: {
! 314: (*s_etat_processus).erreur_systeme =
! 315: d_es_allocation_memoire;
! 316: return(NULL);
! 317: }
! 318: }
1.1 bertrand 319: }
320: else
321: {
1.3 ! bertrand 322: if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
! 323: sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
1.1 bertrand 324: {
325: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
326: return(NULL);
327: }
328: }
329: }
1.2 bertrand 330:
1.1 bertrand 331: (*s_buffer).classe = classe;
332: (*s_buffer).longueur_requise = longueur;
333:
1.3 ! bertrand 334: // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se
! 335: // compose d'un pointeur vers s_buffer suivi d'une zone variable.
! 336: // s_buffer est le pointeur sur l'enveloppe.
! 337: // (*s_buffer).buffer est le pointeur sur le début de la zone allouée
! 338: // aux données.
! 339: (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer;
! 340:
! 341: return(s_buffer);
1.1 bertrand 342: }
343:
344:
1.3 ! bertrand 345: /*
! 346: ================================================================================
! 347: Libération d'un buffer et de son enveloppe
! 348: ================================================================================
! 349: Entrée : état du processus courant, longueur du buffer
! 350: --------------------------------------------------------------------------------
! 351: Sortie : néant
! 352: --------------------------------------------------------------------------------
! 353: Effets de bord : néant
! 354: ================================================================================
! 355: */
! 356:
1.1 bertrand 357: void
358: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
359: {
360: if ((*s_buffer).classe < 0)
361: {
1.3 ! bertrand 362: if ((*s_buffer).buffer != NULL)
! 363: {
! 364: sys_free((*s_buffer).buffer);
! 365: }
1.1 bertrand 366: }
367: else
368: {
369: if ((*s_etat_processus).pointeur_cache_buffer[(*s_buffer).classe]
370: < TAILLE_CACHE)
371: {
372: (*s_etat_processus).cache_buffer[(*s_buffer).classe]
373: [(*s_etat_processus).pointeur_cache_buffer
374: [(*s_buffer).classe]++] = (*s_buffer).buffer;
375: }
376: else
377: {
1.3 ! bertrand 378: sys_free((*s_buffer).buffer);
1.1 bertrand 379: }
380: }
381:
382: liberation_enveloppe_buffer(s_etat_processus, s_buffer);
383: return;
384: }
385:
1.3 ! bertrand 386:
! 387: /*
! 388: ================================================================================
! 389: Allocation d'un buffer et de son enveloppe. Le pointeur retourné est
! 390: le pointeur sur le début de la zone utilisable pour être conforme au
! 391: malloc() de la libc.
! 392: ================================================================================
! 393: Entrée : état du processus courant, longueur du buffer
! 394: --------------------------------------------------------------------------------
! 395: Sortie : pointeur sur un void
! 396: --------------------------------------------------------------------------------
! 397: Effets de bord : néant
! 398: ================================================================================
! 399: */
! 400:
! 401: void *
! 402: rpl_malloc(struct_processus *s_etat_processus, size_t s)
! 403: {
! 404: struct_buffer *s_buffer;
! 405:
! 406: void *pointeur;
! 407:
! 408: if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
! 409: {
! 410: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
! 411: return(NULL);
! 412: }
! 413:
! 414: pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
! 415: return(pointeur);
! 416: }
! 417:
! 418:
! 419: /*
! 420: ================================================================================
! 421: Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
! 422: le pointeur sur le début de la zone utilisable pour être conforme au
! 423: malloc() de la libc.
! 424: ================================================================================
! 425: Entrée : état du processus courant, longueur du buffer
! 426: --------------------------------------------------------------------------------
! 427: Sortie : pointeur sur un void
! 428: --------------------------------------------------------------------------------
! 429: Effets de bord : néant
! 430: ================================================================================
! 431: */
! 432:
! 433: void *
! 434: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
! 435: {
! 436: struct_buffer *s_ancien_buffer;
! 437: struct_buffer *s_nouveau_buffer;
! 438:
! 439: size_t longueur_copie;
! 440:
! 441: void *pointeur;
! 442:
! 443: if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
! 444: {
! 445: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
! 446: return(NULL);
! 447: }
! 448:
! 449: s_ancien_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
! 450:
! 451: longueur_copie = ((*s_ancien_buffer).longueur_requise > s)
! 452: ? s : (*s_ancien_buffer).longueur_requise;
! 453:
! 454: memcpy((*s_nouveau_buffer).buffer + sizeof(struct_buffer *),
! 455: (*s_ancien_buffer).buffer + sizeof(struct_buffer *),
! 456: longueur_copie);
! 457:
! 458: liberation_buffer(s_etat_processus, s_ancien_buffer);
! 459: pointeur = (*s_nouveau_buffer).buffer + sizeof(struct_buffer *);
! 460:
! 461: return(pointeur);
! 462: }
! 463:
! 464:
! 465: /*
! 466: ================================================================================
! 467: Libération d'un buffer et de son enveloppe.
! 468: ================================================================================
! 469: Entrée : état du processus courant, longueur du buffer
! 470: --------------------------------------------------------------------------------
! 471: Sortie : pointeur sur un void
! 472: --------------------------------------------------------------------------------
! 473: Effets de bord : néant
! 474: ================================================================================
! 475: */
! 476:
! 477: void
! 478: rpl_free(struct_processus *s_etat_processus, void *ptr)
! 479: {
! 480: struct_buffer *s_buffer;
! 481:
! 482: if (ptr == NULL)
! 483: {
! 484: return;
! 485: }
! 486:
! 487: s_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
! 488: liberation_buffer(s_etat_processus, s_buffer);
! 489: return;
! 490: }
! 491:
! 492:
! 493: // Réécriture des fonctions malloc() et free() de la libc
! 494:
! 495: void *
! 496: sys_malloc(size_t s)
! 497: {
! 498: return(malloc(s));
! 499: }
! 500:
! 501: void
! 502: sys_free(void *ptr)
! 503: {
! 504: free(ptr);
! 505: }
! 506:
1.1 bertrand 507: // vim: ts=4
CVSweb interface <joel.bertrand@systella.fr>