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

1.1       bertrand    1: /*
                      2: ================================================================================
1.28    ! bertrand    3:   RPL/2 (R) version 4.1.35
        !             4:   Copyright (C) 1989-2023 Dr. BERTRAND Joël
1.1       bertrand    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:        }
1.6       bertrand  189:    }
1.1       bertrand  190: 
1.6       bertrand  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:    }
1.1       bertrand  197: 
1.6       bertrand  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;
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:    {
1.18      bertrand  290:        if (((*s_buffer).buffer = sys_malloc(sizeof(struct_buffer *))) == NULL)
1.10      bertrand  291:        {
                    292:            (*s_etat_processus).erreur_systeme =
                    293:                    d_es_allocation_memoire;
                    294:            return(NULL);
                    295:        }
                    296: 
1.3       bertrand  297:        classe = -1;
                    298:    }
                    299:    else
                    300:    {
                    301:        classe = recherche_longueur_buffer_optimale(longueur);
1.1       bertrand  302: 
1.3       bertrand  303:        if (classe >= 0)
1.1       bertrand  304:        {
1.3       bertrand  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:            }
1.1       bertrand  325:        }
                    326:        else
                    327:        {
1.3       bertrand  328:            if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
                    329:                    sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
1.1       bertrand  330:            {
                    331:                (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    332:                return(NULL);
                    333:            }
                    334:        }
                    335:    }
1.2       bertrand  336: 
1.1       bertrand  337:    (*s_buffer).classe = classe;
                    338:    (*s_buffer).longueur_requise = longueur;
                    339: 
1.3       bertrand  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);
1.1       bertrand  348: }
                    349: 
                    350: 
1.3       bertrand  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: 
1.1       bertrand  363: void
                    364: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
                    365: {
                    366:    if ((*s_buffer).classe < 0)
                    367:    {
1.3       bertrand  368:        if ((*s_buffer).buffer != NULL)
                    369:        {
                    370:            sys_free((*s_buffer).buffer);
                    371:        }
1.1       bertrand  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:        {
1.3       bertrand  384:            sys_free((*s_buffer).buffer);
1.1       bertrand  385:        }
                    386:    }
                    387: 
                    388:    liberation_enveloppe_buffer(s_etat_processus, s_buffer);
                    389:    return;
                    390: }
                    391: 
1.3       bertrand  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: 
1.5       bertrand  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: 
1.3       bertrand  420:    if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    421:    {
1.5       bertrand  422:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
                    423: 
1.3       bertrand  424:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    425:        return(NULL);
                    426:    }
                    427: 
                    428:    pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
1.5       bertrand  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: 
1.3       bertrand  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: 
1.6       bertrand  465:    if (ptr == NULL)
                    466:    {
                    467:        return(rpl_malloc(s_etat_processus, s));
                    468:    }
                    469: 
1.5       bertrand  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: 
1.3       bertrand  476:    if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    477:    {
1.5       bertrand  478:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
                    479: 
1.3       bertrand  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: 
1.5       bertrand  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: 
1.3       bertrand  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 *))));
1.5       bertrand  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: 
1.3       bertrand  537:    liberation_buffer(s_etat_processus, s_buffer);
1.5       bertrand  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: 
1.3       bertrand  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);
1.4       bertrand  562:    return;
1.3       bertrand  563: }
                    564: 
1.13      bertrand  565: void *
                    566: sys_realloc(void *ptr, size_t s)
                    567: {
                    568:    return(realloc(ptr, s));
                    569: }
                    570: 
1.1       bertrand  571: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>