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

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:        }
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: 
1.6     ! bertrand  241: uprintf("Libération de l'allocateur des buffers\n");
        !           242: BACKTRACE(10);
1.1       bertrand  243:    for(i = 0; i < longueur_tailles; i++)
                    244:    {
                    245:        for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++)
                    246:        {
1.3       bertrand  247:            sys_free((*s_etat_processus).cache_buffer[i][j]);
1.1       bertrand  248:        }
                    249: 
1.3       bertrand  250:        sys_free((*s_etat_processus).cache_buffer[i]);
1.1       bertrand  251:    }
                    252: 
1.3       bertrand  253:    sys_free((*s_etat_processus).cache_buffer);
                    254:    sys_free((*s_etat_processus).pointeur_cache_buffer);
1.1       bertrand  255: 
1.3       bertrand  256:    for(i = 0; i < (*s_etat_processus).pointeur_enveloppes_buffers; i++)
1.1       bertrand  257:    {
1.3       bertrand  258:        sys_free((*s_etat_processus).enveloppes_buffers[i]);
1.1       bertrand  259:    }
                    260: 
1.6     ! bertrand  261: uprintf("Fin de la libération de l'allocateur des buffers\n");
1.3       bertrand  262:    return;
1.1       bertrand  263: }
                    264: 
                    265: 
1.3       bertrand  266: /*
                    267: ================================================================================
                    268:   Allocation d'un buffer et de son enveloppe
                    269: ================================================================================
                    270:   Entrée : état du processus courant, longueur du buffer
                    271: --------------------------------------------------------------------------------
                    272:   Sortie : néant
                    273: --------------------------------------------------------------------------------
                    274:   Effets de bord : néant
                    275: ================================================================================
                    276: */
1.1       bertrand  277: 
                    278: struct_buffer *
1.3       bertrand  279: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
1.1       bertrand  280: {
                    281:    int                     classe;
                    282: 
                    283:    struct_buffer           *s_buffer;
                    284: 
1.3       bertrand  285:    if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
1.1       bertrand  286:    {
                    287:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    288:        return(NULL);
                    289:    }
                    290: 
1.3       bertrand  291:    if (longueur == 0)
                    292:    {
                    293:        (*s_buffer).buffer = NULL;
                    294:        classe = -1;
                    295:    }
                    296:    else
                    297:    {
                    298:        classe = recherche_longueur_buffer_optimale(longueur);
1.1       bertrand  299: 
1.3       bertrand  300:        if (classe >= 0)
1.1       bertrand  301:        {
1.3       bertrand  302:            // La classe correspond à la longueur effectivement disponible
                    303:            // dans le buffer alloué. Or il faut ajouter à ce buffer un
                    304:            // pointeur vers l'enveloppe (struct_buffer *).
                    305: 
                    306:            if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0)
                    307:            {
                    308:                (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe]
                    309:                        [--(*s_etat_processus).pointeur_cache_buffer[classe]];
                    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:            }
1.1       bertrand  322:        }
                    323:        else
                    324:        {
1.3       bertrand  325:            if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
                    326:                    sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
1.1       bertrand  327:            {
                    328:                (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    329:                return(NULL);
                    330:            }
                    331:        }
                    332:    }
1.2       bertrand  333: 
1.1       bertrand  334:    (*s_buffer).classe = classe;
                    335:    (*s_buffer).longueur_requise = longueur;
                    336: 
1.3       bertrand  337:    // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se
                    338:    // compose d'un pointeur vers s_buffer suivi d'une zone variable.
                    339:    // s_buffer est le pointeur sur l'enveloppe.
                    340:    // (*s_buffer).buffer est le pointeur sur le début de la zone allouée
                    341:    // aux données.
                    342:    (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer;
                    343: 
                    344:    return(s_buffer);
1.1       bertrand  345: }
                    346: 
                    347: 
1.3       bertrand  348: /*
                    349: ================================================================================
                    350:   Libération d'un buffer et de son enveloppe
                    351: ================================================================================
                    352:   Entrée : état du processus courant, longueur du buffer
                    353: --------------------------------------------------------------------------------
                    354:   Sortie : néant
                    355: --------------------------------------------------------------------------------
                    356:   Effets de bord : néant
                    357: ================================================================================
                    358: */
                    359: 
1.1       bertrand  360: void
                    361: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
                    362: {
                    363:    if ((*s_buffer).classe < 0)
                    364:    {
1.3       bertrand  365:        if ((*s_buffer).buffer != NULL)
                    366:        {
                    367:            sys_free((*s_buffer).buffer);
                    368:        }
1.1       bertrand  369:    }
                    370:    else
                    371:    {
                    372:        if ((*s_etat_processus).pointeur_cache_buffer[(*s_buffer).classe]
                    373:                < TAILLE_CACHE)
                    374:        {
                    375:            (*s_etat_processus).cache_buffer[(*s_buffer).classe]
                    376:                    [(*s_etat_processus).pointeur_cache_buffer
                    377:                    [(*s_buffer).classe]++] = (*s_buffer).buffer;
                    378:        }
                    379:        else
                    380:        {
1.3       bertrand  381:            sys_free((*s_buffer).buffer);
1.1       bertrand  382:        }
                    383:    }
                    384: 
                    385:    liberation_enveloppe_buffer(s_etat_processus, s_buffer);
                    386:    return;
                    387: }
                    388: 
1.3       bertrand  389: 
                    390: /*
                    391: ================================================================================
                    392:   Allocation d'un buffer et de son enveloppe. Le pointeur retourné est
                    393:   le pointeur sur le début de la zone utilisable pour être conforme au
                    394:   malloc() de la libc.
                    395: ================================================================================
                    396:   Entrée : état du processus courant, longueur du buffer
                    397: --------------------------------------------------------------------------------
                    398:   Sortie : pointeur sur un void
                    399: --------------------------------------------------------------------------------
                    400:   Effets de bord : néant
                    401: ================================================================================
                    402: */
                    403: 
                    404: void *
                    405: rpl_malloc(struct_processus *s_etat_processus, size_t s)
                    406: {
                    407:    struct_buffer               *s_buffer;
                    408: 
                    409:    void                        *pointeur;
                    410: 
1.5       bertrand  411:    if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
                    412:    {
                    413:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    414:        return(NULL);
                    415:    }
                    416: 
1.3       bertrand  417:    if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    418:    {
1.5       bertrand  419:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
                    420: 
1.3       bertrand  421:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    422:        return(NULL);
                    423:    }
                    424: 
                    425:    pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
1.5       bertrand  426: 
                    427:    if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
                    428:            != 0)
                    429:    {
                    430:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    431:        return(NULL);
                    432:    }
                    433: 
1.3       bertrand  434:    return(pointeur);
                    435: }
                    436: 
                    437: 
                    438: /*
                    439: ================================================================================
                    440:   Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
                    441:   le pointeur sur le début de la zone utilisable pour être conforme au
                    442:   malloc() de la libc.
                    443: ================================================================================
                    444:   Entrée : état du processus courant, longueur du buffer
                    445: --------------------------------------------------------------------------------
                    446:   Sortie : pointeur sur un void
                    447: --------------------------------------------------------------------------------
                    448:   Effets de bord : néant
                    449: ================================================================================
                    450: */
                    451: 
                    452: void *
                    453: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
                    454: {
                    455:    struct_buffer               *s_ancien_buffer;
                    456:    struct_buffer               *s_nouveau_buffer;
                    457: 
                    458:    size_t                      longueur_copie;
                    459: 
                    460:    void                        *pointeur;
                    461: 
1.6     ! bertrand  462:    if (ptr == NULL)
        !           463:    {
        !           464:        return(rpl_malloc(s_etat_processus, s));
        !           465:    }
        !           466: 
1.5       bertrand  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: 
1.3       bertrand  473:    if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    474:    {
1.5       bertrand  475:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
                    476: 
1.3       bertrand  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: 
1.5       bertrand  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: 
1.3       bertrand  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 *))));
1.5       bertrand  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: 
1.3       bertrand  534:    liberation_buffer(s_etat_processus, s_buffer);
1.5       bertrand  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: 
1.3       bertrand  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);
1.4       bertrand  559:    return;
1.3       bertrand  560: }
                    561: 
1.1       bertrand  562: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>