Annotation of rpl/src/allocateur.c, revision 1.3

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

CVSweb interface <joel.bertrand@systella.fr>