File:  [local] / rpl / src / allocateur.c
Revision 1.25: download - view: text, annotated - select for diffs - revision graph
Fri Jan 10 11:15:38 2020 UTC (4 years, 3 months ago) by bertrand
Branches: MAIN
CVS tags: rpl-4_1_32, HEAD
Modification du copyright.

    1: /*
    2: ================================================================================
    3:   RPL/2 (R) version 4.1.32
    4:   Copyright (C) 1989-2020 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:         if (((*s_buffer).buffer = sys_malloc(sizeof(struct_buffer *))) == NULL)
  291:         {
  292:             (*s_etat_processus).erreur_systeme =
  293:                     d_es_allocation_memoire;
  294:             return(NULL);
  295:         }
  296: 
  297:         classe = -1;
  298:     }
  299:     else
  300:     {
  301:         classe = recherche_longueur_buffer_optimale(longueur);
  302: 
  303:         if (classe >= 0)
  304:         {
  305:             // La classe correspond à la longueur effectivement disponible
  306:             // dans le buffer alloué. Or il faut ajouter à ce buffer un
  307:             // pointeur vers l'enveloppe (struct_buffer *).
  308: 
  309:             if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0)
  310:             {
  311:                 (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe]
  312:                         [--(*s_etat_processus).pointeur_cache_buffer[classe]];
  313:             }
  314:             else
  315:             {
  316:                 if (((*s_buffer).buffer = sys_malloc((tailles[classe] *
  317:                         sizeof(unsigned char)) + sizeof(struct_buffer *)))
  318:                         == NULL)
  319:                 {
  320:                     (*s_etat_processus).erreur_systeme =
  321:                             d_es_allocation_memoire;
  322:                     return(NULL);
  323:                 }
  324:             }
  325:         }
  326:         else
  327:         {
  328:             if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
  329:                     sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
  330:             {
  331:                 (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  332:                 return(NULL);
  333:             }
  334:         }
  335:     }
  336: 
  337:     (*s_buffer).classe = classe;
  338:     (*s_buffer).longueur_requise = longueur;
  339: 
  340:     // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se
  341:     // compose d'un pointeur vers s_buffer suivi d'une zone variable.
  342:     // s_buffer est le pointeur sur l'enveloppe.
  343:     // (*s_buffer).buffer est le pointeur sur le début de la zone allouée
  344:     // aux données.
  345:     (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer;
  346: 
  347:     return(s_buffer);
  348: }
  349: 
  350: 
  351: /*
  352: ================================================================================
  353:   Libération d'un buffer et de son enveloppe
  354: ================================================================================
  355:   Entrée : état du processus courant, longueur du buffer
  356: --------------------------------------------------------------------------------
  357:   Sortie : néant
  358: --------------------------------------------------------------------------------
  359:   Effets de bord : néant
  360: ================================================================================
  361: */
  362: 
  363: void
  364: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
  365: {
  366:     if ((*s_buffer).classe < 0)
  367:     {
  368:         if ((*s_buffer).buffer != NULL)
  369:         {
  370:             sys_free((*s_buffer).buffer);
  371:         }
  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;
  381:         }
  382:         else
  383:         {
  384:             sys_free((*s_buffer).buffer);
  385:         }
  386:     }
  387: 
  388:     liberation_enveloppe_buffer(s_etat_processus, s_buffer);
  389:     return;
  390: }
  391: 
  392: 
  393: /*
  394: ================================================================================
  395:   Allocation d'un buffer et de son enveloppe. Le pointeur retourné est
  396:   le pointeur sur le début de la zone utilisable pour être conforme au
  397:   malloc() de la libc.
  398: ================================================================================
  399:   Entrée : état du processus courant, longueur du buffer
  400: --------------------------------------------------------------------------------
  401:   Sortie : pointeur sur un void
  402: --------------------------------------------------------------------------------
  403:   Effets de bord : néant
  404: ================================================================================
  405: */
  406: 
  407: void *
  408: rpl_malloc(struct_processus *s_etat_processus, size_t s)
  409: {
  410:     struct_buffer               *s_buffer;
  411: 
  412:     void                        *pointeur;
  413: 
  414:     if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
  415:     {
  416:         (*s_etat_processus).erreur_systeme = d_es_processus;
  417:         return(NULL);
  418:     }
  419: 
  420:     if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
  421:     {
  422:         pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
  423: 
  424:         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  425:         return(NULL);
  426:     }
  427: 
  428:     pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
  429: 
  430:     if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
  431:             != 0)
  432:     {
  433:         (*s_etat_processus).erreur_systeme = d_es_processus;
  434:         return(NULL);
  435:     }
  436: 
  437:     return(pointeur);
  438: }
  439: 
  440: 
  441: /*
  442: ================================================================================
  443:   Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
  444:   le pointeur sur le début de la zone utilisable pour être conforme au
  445:   malloc() de la libc.
  446: ================================================================================
  447:   Entrée : état du processus courant, longueur du buffer
  448: --------------------------------------------------------------------------------
  449:   Sortie : pointeur sur un void
  450: --------------------------------------------------------------------------------
  451:   Effets de bord : néant
  452: ================================================================================
  453: */
  454: 
  455: void *
  456: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
  457: {
  458:     struct_buffer               *s_ancien_buffer;
  459:     struct_buffer               *s_nouveau_buffer;
  460: 
  461:     size_t                      longueur_copie;
  462: 
  463:     void                        *pointeur;
  464: 
  465:     if (ptr == NULL)
  466:     {
  467:         return(rpl_malloc(s_etat_processus, s));
  468:     }
  469: 
  470:     if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
  471:     {
  472:         (*s_etat_processus).erreur_systeme = d_es_processus;
  473:         return(NULL);
  474:     }
  475: 
  476:     if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
  477:     {
  478:         pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
  479: 
  480:         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  481:         return(NULL);
  482:     }
  483: 
  484:     s_ancien_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
  485: 
  486:     longueur_copie = ((*s_ancien_buffer).longueur_requise > s)
  487:             ? s : (*s_ancien_buffer).longueur_requise;
  488: 
  489:     memcpy((*s_nouveau_buffer).buffer + sizeof(struct_buffer *),
  490:             (*s_ancien_buffer).buffer + sizeof(struct_buffer *),
  491:             longueur_copie);
  492: 
  493:     liberation_buffer(s_etat_processus, s_ancien_buffer);
  494:     pointeur = (*s_nouveau_buffer).buffer + sizeof(struct_buffer *);
  495: 
  496:     if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
  497:             != 0)
  498:     {
  499:         (*s_etat_processus).erreur_systeme = d_es_processus;
  500:         return(NULL);
  501:     }
  502: 
  503:     return(pointeur);
  504: }
  505: 
  506: 
  507: /*
  508: ================================================================================
  509:   Libération d'un buffer et de son enveloppe.
  510: ================================================================================
  511:   Entrée : état du processus courant, longueur du buffer
  512: --------------------------------------------------------------------------------
  513:   Sortie : pointeur sur un void
  514: --------------------------------------------------------------------------------
  515:   Effets de bord : néant
  516: ================================================================================
  517: */
  518: 
  519: void
  520: rpl_free(struct_processus *s_etat_processus, void *ptr)
  521: {
  522:     struct_buffer               *s_buffer;
  523: 
  524:     if (ptr == NULL)
  525:     {
  526:         return;
  527:     }
  528: 
  529:     s_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
  530: 
  531:     if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
  532:     {
  533:         (*s_etat_processus).erreur_systeme = d_es_processus;
  534:         return;
  535:     }
  536: 
  537:     liberation_buffer(s_etat_processus, s_buffer);
  538: 
  539:     if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
  540:             != 0)
  541:     {
  542:         (*s_etat_processus).erreur_systeme = d_es_processus;
  543:         return;
  544:     }
  545: 
  546:     return;
  547: }
  548: 
  549: 
  550: // Réécriture des fonctions malloc() et free() de la libc
  551: 
  552: void *
  553: sys_malloc(size_t s)
  554: {
  555:     return(malloc(s));
  556: }
  557: 
  558: void
  559: sys_free(void *ptr)
  560: {
  561:     free(ptr);
  562:     return;
  563: }
  564: 
  565: void *
  566: sys_realloc(void *ptr, size_t s)
  567: {
  568:     return(realloc(ptr, s));
  569: }
  570: 
  571: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>