1: /*
2: ================================================================================
3: RPL/2 (R) version 4.1.21
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:
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.
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
60: recherche_longueur_buffer_optimale(size_t longueur)
61: {
62: int a;
63: int b;
64: int m;
65:
66: a = 0;
67: b = longueur_tailles - 1;
68:
69: if (longueur > tailles[b])
70: {
71: return(-1);
72: }
73:
74: while((b - a) > 1)
75: {
76: m = (a + b) / 2;
77:
78: if (longueur <= tailles[m])
79: {
80: b = m;
81: }
82: else
83: {
84: a = m;
85: }
86: }
87:
88: return(b);
89: }
90:
91:
92: /*
93: ================================================================================
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
168: ================================================================================
169: Entrée : état du processus courant (contient les données nécessaires
170: au fonctionnement de l'allocateur par thread)
171: --------------------------------------------------------------------------------
172: Sortie : néant
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: }
190:
191: if (((*s_etat_processus).cache_buffer = sys_malloc(((size_t)
192: longueur_tailles) * sizeof(unsigned char **))) == NULL)
193: {
194: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
195: return;
196: }
197:
198: if (((*s_etat_processus).pointeur_cache_buffer = sys_malloc(((size_t)
199: longueur_tailles) * sizeof(int))) == NULL)
200: {
201: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
202: return;
203: }
204:
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)
209: {
210: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
211: return;
212: }
213:
214: (*s_etat_processus).pointeur_cache_buffer[i] = 0;
215: }
216:
217: (*s_etat_processus).pointeur_enveloppes_buffers = 0;
218: return;
219: }
220:
221:
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:
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: {
245: sys_free((*s_etat_processus).cache_buffer[i][j]);
246: }
247:
248: sys_free((*s_etat_processus).cache_buffer[i]);
249: }
250:
251: sys_free((*s_etat_processus).cache_buffer);
252: sys_free((*s_etat_processus).pointeur_cache_buffer);
253:
254: for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++)
255: {
256: sys_free((*s_etat_processus).enveloppes_buffers[i]);
257: }
258:
259: return;
260: }
261:
262:
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: */
274:
275: struct_buffer *
276: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
277: {
278: int classe;
279:
280: struct_buffer *s_buffer;
281:
282: if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
283: {
284: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
285: return(NULL);
286: }
287:
288: if (longueur == 0)
289: {
290: (*s_buffer).buffer = NULL;
291: classe = -1;
292: }
293: else
294: {
295: classe = recherche_longueur_buffer_optimale(longueur);
296:
297: if (classe >= 0)
298: {
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: }
319: }
320: else
321: {
322: if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
323: sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
324: {
325: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
326: return(NULL);
327: }
328: }
329: }
330:
331: (*s_buffer).classe = classe;
332: (*s_buffer).longueur_requise = longueur;
333:
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);
342: }
343:
344:
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:
357: void
358: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
359: {
360: if ((*s_buffer).classe < 0)
361: {
362: if ((*s_buffer).buffer != NULL)
363: {
364: sys_free((*s_buffer).buffer);
365: }
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: {
378: sys_free((*s_buffer).buffer);
379: }
380: }
381:
382: liberation_enveloppe_buffer(s_etat_processus, s_buffer);
383: return;
384: }
385:
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 (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
409: {
410: (*s_etat_processus).erreur_systeme = d_es_processus;
411: return(NULL);
412: }
413:
414: if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
415: {
416: pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
417:
418: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
419: return(NULL);
420: }
421:
422: pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
423:
424: if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
425: != 0)
426: {
427: (*s_etat_processus).erreur_systeme = d_es_processus;
428: return(NULL);
429: }
430:
431: return(pointeur);
432: }
433:
434:
435: /*
436: ================================================================================
437: Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
438: le pointeur sur le début de la zone utilisable pour être conforme au
439: malloc() de la libc.
440: ================================================================================
441: Entrée : état du processus courant, longueur du buffer
442: --------------------------------------------------------------------------------
443: Sortie : pointeur sur un void
444: --------------------------------------------------------------------------------
445: Effets de bord : néant
446: ================================================================================
447: */
448:
449: void *
450: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
451: {
452: struct_buffer *s_ancien_buffer;
453: struct_buffer *s_nouveau_buffer;
454:
455: size_t longueur_copie;
456:
457: void *pointeur;
458:
459: if (ptr == NULL)
460: {
461: return(rpl_malloc(s_etat_processus, s));
462: }
463:
464: if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
465: {
466: (*s_etat_processus).erreur_systeme = d_es_processus;
467: return(NULL);
468: }
469:
470: if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
471: {
472: pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
473:
474: (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
475: return(NULL);
476: }
477:
478: s_ancien_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
479:
480: longueur_copie = ((*s_ancien_buffer).longueur_requise > s)
481: ? s : (*s_ancien_buffer).longueur_requise;
482:
483: memcpy((*s_nouveau_buffer).buffer + sizeof(struct_buffer *),
484: (*s_ancien_buffer).buffer + sizeof(struct_buffer *),
485: longueur_copie);
486:
487: liberation_buffer(s_etat_processus, s_ancien_buffer);
488: pointeur = (*s_nouveau_buffer).buffer + sizeof(struct_buffer *);
489:
490: if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
491: != 0)
492: {
493: (*s_etat_processus).erreur_systeme = d_es_processus;
494: return(NULL);
495: }
496:
497: return(pointeur);
498: }
499:
500:
501: /*
502: ================================================================================
503: Libération d'un buffer et de son enveloppe.
504: ================================================================================
505: Entrée : état du processus courant, longueur du buffer
506: --------------------------------------------------------------------------------
507: Sortie : pointeur sur un void
508: --------------------------------------------------------------------------------
509: Effets de bord : néant
510: ================================================================================
511: */
512:
513: void
514: rpl_free(struct_processus *s_etat_processus, void *ptr)
515: {
516: struct_buffer *s_buffer;
517:
518: if (ptr == NULL)
519: {
520: return;
521: }
522:
523: s_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
524:
525: if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
526: {
527: (*s_etat_processus).erreur_systeme = d_es_processus;
528: return;
529: }
530:
531: liberation_buffer(s_etat_processus, s_buffer);
532:
533: if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
534: != 0)
535: {
536: (*s_etat_processus).erreur_systeme = d_es_processus;
537: return;
538: }
539:
540: return;
541: }
542:
543:
544: // Réécriture des fonctions malloc() et free() de la libc
545:
546: void *
547: sys_malloc(size_t s)
548: {
549: return(malloc(s));
550: }
551:
552: void
553: sys_free(void *ptr)
554: {
555: free(ptr);
556: return;
557: }
558:
559: // vim: ts=4
CVSweb interface <joel.bertrand@systella.fr>