File:  [local] / rpl / src / allocateur.c
Revision 1.5: download - view: text, annotated - select for diffs - revision graph
Fri Jan 30 07:53:14 2015 UTC (9 years, 3 months ago) by bertrand
Branches: MAIN
CVS tags: HEAD
Ajout d'un mutex sur le nouvel allocateur.

    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:         if (((*s_etat_processus).cache_buffer = sys_malloc(((size_t)
  191:                 longueur_tailles) * sizeof(unsigned char **))) == NULL)
  192:         {
  193:             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  194:             return;
  195:         }
  196: 
  197:         if (((*s_etat_processus).pointeur_cache_buffer = sys_malloc(((size_t)
  198:                 longueur_tailles) * sizeof(int))) == NULL)
  199:         {
  200:             (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  201:             return;
  202:         }
  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: uprintf("L %d ************* %d ********************\n", getpid(), i);
  244:         for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++)
  245:         {
  246: uprintf("L %d %p\n", getpid(), (*s_etat_processus).cache_buffer[i][j]);
  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:     return;
  262: }
  263: 
  264: 
  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: */
  276: 
  277: struct_buffer *
  278: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
  279: {
  280:     int                     classe;
  281: 
  282:     struct_buffer           *s_buffer;
  283: 
  284:     if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
  285:     {
  286:         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  287:         return(NULL);
  288:     }
  289: 
  290:     if (longueur == 0)
  291:     {
  292:         (*s_buffer).buffer = NULL;
  293:         classe = -1;
  294:     }
  295:     else
  296:     {
  297:         classe = recherche_longueur_buffer_optimale(longueur);
  298: 
  299:         if (classe >= 0)
  300:         {
  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]];
  309: uprintf("Cachée : %d %p\n", getpid(), (*s_buffer).buffer);
  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: uprintf("Alloué : %d %p\n", getpid(), (*s_buffer).buffer);
  322:             }
  323:         }
  324:         else
  325:         {
  326:             if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
  327:                     sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
  328:             {
  329:                 (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  330:                 return(NULL);
  331:             }
  332: uprintf("Alloué (non cachée) : %d %p\n", getpid(), (*s_buffer).buffer);
  333:         }
  334:     }
  335: 
  336:     (*s_buffer).classe = classe;
  337:     (*s_buffer).longueur_requise = longueur;
  338: 
  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);
  347: }
  348: 
  349: 
  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: 
  362: void
  363: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
  364: {
  365:     if ((*s_buffer).classe < 0)
  366:     {
  367:         if ((*s_buffer).buffer != NULL)
  368:         {
  369:             sys_free((*s_buffer).buffer);
  370: uprintf("Libération (trop grand) : %d %p\n", getpid(), (*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: uprintf("Mise en cache : %d %p\n", getpid(), (*s_buffer).buffer);
  382:         }
  383:         else
  384:         {
  385:             sys_free((*s_buffer).buffer);
  386: uprintf("Libération (cache plein) : %d %p\n", getpid(), (*s_buffer).buffer);
  387:         }
  388:     }
  389: 
  390:     liberation_enveloppe_buffer(s_etat_processus, s_buffer);
  391:     return;
  392: }
  393: 
  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: 
  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: 
  422:     if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
  423:     {
  424:         pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
  425: 
  426:         (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
  427:         return(NULL);
  428:     }
  429: 
  430:     pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
  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: 
  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: 
  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>