File:  [local] / rpl / src / allocateur.c
Revision 1.6: download - view: text, annotated - select for diffs - revision graph
Sun Feb 1 09:47:18 2015 UTC (9 years, 2 months ago) by bertrand
Branches: MAIN
CVS tags: HEAD
Un certain nombre de régressions du nouveau parser ont été corrigées.
Le nouvel allocateur a été amélioré et corrigé. L'instruction DETACH
provoque encore un segfault lors de la libération des données du processus fils.

    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: 
   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: uprintf("Libération de l'allocateur des buffers\n");
  242: BACKTRACE(10);
  243:     for(i = 0; i < longueur_tailles; i++)
  244:     {
  245:         for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++)
  246:         {
  247:             sys_free((*s_etat_processus).cache_buffer[i][j]);
  248:         }
  249: 
  250:         sys_free((*s_etat_processus).cache_buffer[i]);
  251:     }
  252: 
  253:     sys_free((*s_etat_processus).cache_buffer);
  254:     sys_free((*s_etat_processus).pointeur_cache_buffer);
  255: 
  256:     for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++)
  257:     {
  258:         sys_free((*s_etat_processus).enveloppes_buffers[i]);
  259:     }
  260: 
  261: uprintf("Fin de la libération de l'allocateur des buffers\n");
  262:     return;
  263: }
  264: 
  265: 
  266: /*
  267: ================================================================================
  268:   Allocation d'un buffer et de son enveloppe
  269: ================================================================================
  270:   Entrée : état du processus courant, longueur du buffer
  271: --------------------------------------------------------------------------------
  272:   Sortie : néant
  273: --------------------------------------------------------------------------------
  274:   Effets de bord : néant
  275: ================================================================================
  276: */
  277: 
  278: struct_buffer *
  279: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
  280: {
  281:     int                     classe;
  282: 
  283:     struct_buffer           *s_buffer;
  284: 
  285:     if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
  286:     {
  287:         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  288:         return(NULL);
  289:     }
  290: 
  291:     if (longueur == 0)
  292:     {
  293:         (*s_buffer).buffer = NULL;
  294:         classe = -1;
  295:     }
  296:     else
  297:     {
  298:         classe = recherche_longueur_buffer_optimale(longueur);
  299: 
  300:         if (classe >= 0)
  301:         {
  302:             // La classe correspond à la longueur effectivement disponible
  303:             // dans le buffer alloué. Or il faut ajouter à ce buffer un
  304:             // pointeur vers l'enveloppe (struct_buffer *).
  305: 
  306:             if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0)
  307:             {
  308:                 (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe]
  309:                         [--(*s_etat_processus).pointeur_cache_buffer[classe]];
  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:                 }
  321:             }
  322:         }
  323:         else
  324:         {
  325:             if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
  326:                     sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
  327:             {
  328:                 (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  329:                 return(NULL);
  330:             }
  331:         }
  332:     }
  333: 
  334:     (*s_buffer).classe = classe;
  335:     (*s_buffer).longueur_requise = longueur;
  336: 
  337:     // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se
  338:     // compose d'un pointeur vers s_buffer suivi d'une zone variable.
  339:     // s_buffer est le pointeur sur l'enveloppe.
  340:     // (*s_buffer).buffer est le pointeur sur le début de la zone allouée
  341:     // aux données.
  342:     (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer;
  343: 
  344:     return(s_buffer);
  345: }
  346: 
  347: 
  348: /*
  349: ================================================================================
  350:   Libération d'un buffer et de son enveloppe
  351: ================================================================================
  352:   Entrée : état du processus courant, longueur du buffer
  353: --------------------------------------------------------------------------------
  354:   Sortie : néant
  355: --------------------------------------------------------------------------------
  356:   Effets de bord : néant
  357: ================================================================================
  358: */
  359: 
  360: void
  361: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
  362: {
  363:     if ((*s_buffer).classe < 0)
  364:     {
  365:         if ((*s_buffer).buffer != NULL)
  366:         {
  367:             sys_free((*s_buffer).buffer);
  368:         }
  369:     }
  370:     else
  371:     {
  372:         if ((*s_etat_processus).pointeur_cache_buffer[(*s_buffer).classe]
  373:                 < TAILLE_CACHE)
  374:         {
  375:             (*s_etat_processus).cache_buffer[(*s_buffer).classe]
  376:                     [(*s_etat_processus).pointeur_cache_buffer
  377:                     [(*s_buffer).classe]++] = (*s_buffer).buffer;
  378:         }
  379:         else
  380:         {
  381:             sys_free((*s_buffer).buffer);
  382:         }
  383:     }
  384: 
  385:     liberation_enveloppe_buffer(s_etat_processus, s_buffer);
  386:     return;
  387: }
  388: 
  389: 
  390: /*
  391: ================================================================================
  392:   Allocation d'un buffer et de son enveloppe. Le pointeur retourné est
  393:   le pointeur sur le début de la zone utilisable pour être conforme au
  394:   malloc() de la libc.
  395: ================================================================================
  396:   Entrée : état du processus courant, longueur du buffer
  397: --------------------------------------------------------------------------------
  398:   Sortie : pointeur sur un void
  399: --------------------------------------------------------------------------------
  400:   Effets de bord : néant
  401: ================================================================================
  402: */
  403: 
  404: void *
  405: rpl_malloc(struct_processus *s_etat_processus, size_t s)
  406: {
  407:     struct_buffer               *s_buffer;
  408: 
  409:     void                        *pointeur;
  410: 
  411:     if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
  412:     {
  413:         (*s_etat_processus).erreur_systeme = d_es_processus;
  414:         return(NULL);
  415:     }
  416: 
  417:     if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
  418:     {
  419:         pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
  420: 
  421:         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  422:         return(NULL);
  423:     }
  424: 
  425:     pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
  426: 
  427:     if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
  428:             != 0)
  429:     {
  430:         (*s_etat_processus).erreur_systeme = d_es_processus;
  431:         return(NULL);
  432:     }
  433: 
  434:     return(pointeur);
  435: }
  436: 
  437: 
  438: /*
  439: ================================================================================
  440:   Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
  441:   le pointeur sur le début de la zone utilisable pour être conforme au
  442:   malloc() de la libc.
  443: ================================================================================
  444:   Entrée : état du processus courant, longueur du buffer
  445: --------------------------------------------------------------------------------
  446:   Sortie : pointeur sur un void
  447: --------------------------------------------------------------------------------
  448:   Effets de bord : néant
  449: ================================================================================
  450: */
  451: 
  452: void *
  453: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
  454: {
  455:     struct_buffer               *s_ancien_buffer;
  456:     struct_buffer               *s_nouveau_buffer;
  457: 
  458:     size_t                      longueur_copie;
  459: 
  460:     void                        *pointeur;
  461: 
  462:     if (ptr == NULL)
  463:     {
  464:         return(rpl_malloc(s_etat_processus, s));
  465:     }
  466: 
  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: 
  473:     if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
  474:     {
  475:         pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
  476: 
  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: 
  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: 
  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 *))));
  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: 
  534:     liberation_buffer(s_etat_processus, s_buffer);
  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: 
  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);
  559:     return;
  560: }
  561: 
  562: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>