Annotation of rpl/src/allocateur.c, revision 1.5
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: {
1.5 ! bertrand 243: uprintf("L %d ************* %d ********************\n", getpid(), i);
1.1 bertrand 244: for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++)
245: {
1.5 ! bertrand 246: uprintf("L %d %p\n", getpid(), (*s_etat_processus).cache_buffer[i][j]);
1.3 bertrand 247: sys_free((*s_etat_processus).cache_buffer[i][j]);
1.1 bertrand 248: }
249:
1.3 bertrand 250: sys_free((*s_etat_processus).cache_buffer[i]);
1.1 bertrand 251: }
252:
1.3 bertrand 253: sys_free((*s_etat_processus).cache_buffer);
254: sys_free((*s_etat_processus).pointeur_cache_buffer);
1.1 bertrand 255:
1.3 bertrand 256: for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++)
1.1 bertrand 257: {
1.3 bertrand 258: sys_free((*s_etat_processus).enveloppes_buffers[i]);
1.1 bertrand 259: }
260:
1.3 bertrand 261: return;
1.1 bertrand 262: }
263:
264:
1.3 bertrand 265: /*
266: ================================================================================
267: Allocation d'un buffer et de son enveloppe
268: ================================================================================
269: Entrée : état du processus courant, longueur du buffer
270: --------------------------------------------------------------------------------
271: Sortie : néant
272: --------------------------------------------------------------------------------
273: Effets de bord : néant
274: ================================================================================
275: */
1.1 bertrand 276:
277: struct_buffer *
1.3 bertrand 278: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
1.1 bertrand 279: {
280: int classe;
281:
282: struct_buffer *s_buffer;
283:
1.3 bertrand 284: if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
1.1 bertrand 285: {
286: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
287: return(NULL);
288: }
289:
1.3 bertrand 290: if (longueur == 0)
291: {
292: (*s_buffer).buffer = NULL;
293: classe = -1;
294: }
295: else
296: {
297: classe = recherche_longueur_buffer_optimale(longueur);
1.1 bertrand 298:
1.3 bertrand 299: if (classe >= 0)
1.1 bertrand 300: {
1.3 bertrand 301: // La classe correspond à la longueur effectivement disponible
302: // dans le buffer alloué. Or il faut ajouter à ce buffer un
303: // pointeur vers l'enveloppe (struct_buffer *).
304:
305: if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0)
306: {
307: (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe]
308: [--(*s_etat_processus).pointeur_cache_buffer[classe]];
1.5 ! bertrand 309: uprintf("Cachée : %d %p\n", getpid(), (*s_buffer).buffer);
1.3 bertrand 310: }
311: else
312: {
313: if (((*s_buffer).buffer = sys_malloc((tailles[classe] *
314: sizeof(unsigned char)) + sizeof(struct_buffer *)))
315: == NULL)
316: {
317: (*s_etat_processus).erreur_systeme =
318: d_es_allocation_memoire;
319: return(NULL);
320: }
1.5 ! bertrand 321: uprintf("Alloué : %d %p\n", getpid(), (*s_buffer).buffer);
1.3 bertrand 322: }
1.1 bertrand 323: }
324: else
325: {
1.3 bertrand 326: if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
327: sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
1.1 bertrand 328: {
329: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
330: return(NULL);
331: }
1.5 ! bertrand 332: uprintf("Alloué (non cachée) : %d %p\n", getpid(), (*s_buffer).buffer);
1.1 bertrand 333: }
334: }
1.2 bertrand 335:
1.1 bertrand 336: (*s_buffer).classe = classe;
337: (*s_buffer).longueur_requise = longueur;
338:
1.3 bertrand 339: // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se
340: // compose d'un pointeur vers s_buffer suivi d'une zone variable.
341: // s_buffer est le pointeur sur l'enveloppe.
342: // (*s_buffer).buffer est le pointeur sur le début de la zone allouée
343: // aux données.
344: (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer;
345:
346: return(s_buffer);
1.1 bertrand 347: }
348:
349:
1.3 bertrand 350: /*
351: ================================================================================
352: Libération d'un buffer et de son enveloppe
353: ================================================================================
354: Entrée : état du processus courant, longueur du buffer
355: --------------------------------------------------------------------------------
356: Sortie : néant
357: --------------------------------------------------------------------------------
358: Effets de bord : néant
359: ================================================================================
360: */
361:
1.1 bertrand 362: void
363: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
364: {
365: if ((*s_buffer).classe < 0)
366: {
1.3 bertrand 367: if ((*s_buffer).buffer != NULL)
368: {
369: sys_free((*s_buffer).buffer);
1.5 ! bertrand 370: uprintf("Libération (trop grand) : %d %p\n", getpid(), (*s_buffer).buffer);
1.3 bertrand 371: }
1.1 bertrand 372: }
373: else
374: {
375: if ((*s_etat_processus).pointeur_cache_buffer[(*s_buffer).classe]
376: < TAILLE_CACHE)
377: {
378: (*s_etat_processus).cache_buffer[(*s_buffer).classe]
379: [(*s_etat_processus).pointeur_cache_buffer
380: [(*s_buffer).classe]++] = (*s_buffer).buffer;
1.5 ! bertrand 381: uprintf("Mise en cache : %d %p\n", getpid(), (*s_buffer).buffer);
1.1 bertrand 382: }
383: else
384: {
1.3 bertrand 385: sys_free((*s_buffer).buffer);
1.5 ! bertrand 386: uprintf("Libération (cache plein) : %d %p\n", getpid(), (*s_buffer).buffer);
1.1 bertrand 387: }
388: }
389:
390: liberation_enveloppe_buffer(s_etat_processus, s_buffer);
391: return;
392: }
393:
1.3 bertrand 394:
395: /*
396: ================================================================================
397: Allocation d'un buffer et de son enveloppe. Le pointeur retourné est
398: le pointeur sur le début de la zone utilisable pour être conforme au
399: malloc() de la libc.
400: ================================================================================
401: Entrée : état du processus courant, longueur du buffer
402: --------------------------------------------------------------------------------
403: Sortie : pointeur sur un void
404: --------------------------------------------------------------------------------
405: Effets de bord : néant
406: ================================================================================
407: */
408:
409: void *
410: rpl_malloc(struct_processus *s_etat_processus, size_t s)
411: {
412: struct_buffer *s_buffer;
413:
414: void *pointeur;
415:
1.5 ! bertrand 416: if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
! 417: {
! 418: (*s_etat_processus).erreur_systeme = d_es_processus;
! 419: return(NULL);
! 420: }
! 421:
1.3 bertrand 422: if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
423: {
1.5 ! bertrand 424: pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
! 425:
1.3 bertrand 426: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
427: return(NULL);
428: }
429:
430: pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
1.5 ! bertrand 431:
! 432: if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
! 433: != 0)
! 434: {
! 435: (*s_etat_processus).erreur_systeme = d_es_processus;
! 436: return(NULL);
! 437: }
! 438:
1.3 bertrand 439: return(pointeur);
440: }
441:
442:
443: /*
444: ================================================================================
445: Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
446: le pointeur sur le début de la zone utilisable pour être conforme au
447: malloc() de la libc.
448: ================================================================================
449: Entrée : état du processus courant, longueur du buffer
450: --------------------------------------------------------------------------------
451: Sortie : pointeur sur un void
452: --------------------------------------------------------------------------------
453: Effets de bord : néant
454: ================================================================================
455: */
456:
457: void *
458: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
459: {
460: struct_buffer *s_ancien_buffer;
461: struct_buffer *s_nouveau_buffer;
462:
463: size_t longueur_copie;
464:
465: void *pointeur;
466:
1.5 ! bertrand 467: if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
! 468: {
! 469: (*s_etat_processus).erreur_systeme = d_es_processus;
! 470: return(NULL);
! 471: }
! 472:
1.3 bertrand 473: if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
474: {
1.5 ! bertrand 475: pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
! 476:
1.3 bertrand 477: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
478: return(NULL);
479: }
480:
481: s_ancien_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
482:
483: longueur_copie = ((*s_ancien_buffer).longueur_requise > s)
484: ? s : (*s_ancien_buffer).longueur_requise;
485:
486: memcpy((*s_nouveau_buffer).buffer + sizeof(struct_buffer *),
487: (*s_ancien_buffer).buffer + sizeof(struct_buffer *),
488: longueur_copie);
489:
490: liberation_buffer(s_etat_processus, s_ancien_buffer);
491: pointeur = (*s_nouveau_buffer).buffer + sizeof(struct_buffer *);
492:
1.5 ! bertrand 493: if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
! 494: != 0)
! 495: {
! 496: (*s_etat_processus).erreur_systeme = d_es_processus;
! 497: return(NULL);
! 498: }
! 499:
1.3 bertrand 500: return(pointeur);
501: }
502:
503:
504: /*
505: ================================================================================
506: Libération d'un buffer et de son enveloppe.
507: ================================================================================
508: Entrée : état du processus courant, longueur du buffer
509: --------------------------------------------------------------------------------
510: Sortie : pointeur sur un void
511: --------------------------------------------------------------------------------
512: Effets de bord : néant
513: ================================================================================
514: */
515:
516: void
517: rpl_free(struct_processus *s_etat_processus, void *ptr)
518: {
519: struct_buffer *s_buffer;
520:
521: if (ptr == NULL)
522: {
523: return;
524: }
525:
526: s_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
1.5 ! bertrand 527:
! 528: if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
! 529: {
! 530: (*s_etat_processus).erreur_systeme = d_es_processus;
! 531: return;
! 532: }
! 533:
1.3 bertrand 534: liberation_buffer(s_etat_processus, s_buffer);
1.5 ! bertrand 535:
! 536: if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
! 537: != 0)
! 538: {
! 539: (*s_etat_processus).erreur_systeme = d_es_processus;
! 540: return;
! 541: }
! 542:
1.3 bertrand 543: return;
544: }
545:
546:
547: // Réécriture des fonctions malloc() et free() de la libc
548:
549: void *
550: sys_malloc(size_t s)
551: {
552: return(malloc(s));
553: }
554:
555: void
556: sys_free(void *ptr)
557: {
558: free(ptr);
1.4 bertrand 559: return;
1.3 bertrand 560: }
561:
1.1 bertrand 562: // vim: ts=4
CVSweb interface <joel.bertrand@systella.fr>