File:  [local] / rpl / src / allocateur.c
Revision 1.8: download - view: text, annotated - select for diffs - revision graph
Thu Feb 19 11:01:17 2015 UTC (9 years, 2 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_21, HEAD
En route pour la 4.1.21.

    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>