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

1.1       bertrand    1: /*
                      2: ================================================================================
1.9     ! bertrand    3:   RPL/2 (R) version 4.1.22
1.1       bertrand    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: 
                    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: 
1.5       bertrand  408:    if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
                    409:    {
                    410:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    411:        return(NULL);
                    412:    }
                    413: 
1.3       bertrand  414:    if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    415:    {
1.5       bertrand  416:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
                    417: 
1.3       bertrand  418:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    419:        return(NULL);
                    420:    }
                    421: 
                    422:    pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
1.5       bertrand  423: 
                    424:    if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
                    425:            != 0)
                    426:    {
                    427:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    428:        return(NULL);
                    429:    }
                    430: 
1.3       bertrand  431:    return(pointeur);
                    432: }
                    433: 
                    434: 
                    435: /*
                    436: ================================================================================
                    437:   Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
                    438:   le pointeur sur le début de la zone utilisable pour être conforme au
                    439:   malloc() de la libc.
                    440: ================================================================================
                    441:   Entrée : état du processus courant, longueur du buffer
                    442: --------------------------------------------------------------------------------
                    443:   Sortie : pointeur sur un void
                    444: --------------------------------------------------------------------------------
                    445:   Effets de bord : néant
                    446: ================================================================================
                    447: */
                    448: 
                    449: void *
                    450: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
                    451: {
                    452:    struct_buffer               *s_ancien_buffer;
                    453:    struct_buffer               *s_nouveau_buffer;
                    454: 
                    455:    size_t                      longueur_copie;
                    456: 
                    457:    void                        *pointeur;
                    458: 
1.6       bertrand  459:    if (ptr == NULL)
                    460:    {
                    461:        return(rpl_malloc(s_etat_processus, s));
                    462:    }
                    463: 
1.5       bertrand  464:    if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
                    465:    {
                    466:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    467:        return(NULL);
                    468:    }
                    469: 
1.3       bertrand  470:    if ((s_nouveau_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    471:    {
1.5       bertrand  472:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
                    473: 
1.3       bertrand  474:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    475:        return(NULL);
                    476:    }
                    477: 
                    478:    s_ancien_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
                    479: 
                    480:    longueur_copie = ((*s_ancien_buffer).longueur_requise > s)
                    481:            ? s : (*s_ancien_buffer).longueur_requise;
                    482: 
                    483:    memcpy((*s_nouveau_buffer).buffer + sizeof(struct_buffer *),
                    484:            (*s_ancien_buffer).buffer + sizeof(struct_buffer *),
                    485:            longueur_copie);
                    486: 
                    487:    liberation_buffer(s_etat_processus, s_ancien_buffer);
                    488:    pointeur = (*s_nouveau_buffer).buffer + sizeof(struct_buffer *);
                    489: 
1.5       bertrand  490:    if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
                    491:            != 0)
                    492:    {
                    493:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    494:        return(NULL);
                    495:    }
                    496: 
1.3       bertrand  497:    return(pointeur);
                    498: }
                    499: 
                    500: 
                    501: /*
                    502: ================================================================================
                    503:   Libération d'un buffer et de son enveloppe.
                    504: ================================================================================
                    505:   Entrée : état du processus courant, longueur du buffer
                    506: --------------------------------------------------------------------------------
                    507:   Sortie : pointeur sur un void
                    508: --------------------------------------------------------------------------------
                    509:   Effets de bord : néant
                    510: ================================================================================
                    511: */
                    512: 
                    513: void
                    514: rpl_free(struct_processus *s_etat_processus, void *ptr)
                    515: {
                    516:    struct_buffer               *s_buffer;
                    517: 
                    518:    if (ptr == NULL)
                    519:    {
                    520:        return;
                    521:    }
                    522: 
                    523:    s_buffer = (*((struct_buffer **) (ptr - sizeof(struct_buffer *))));
1.5       bertrand  524: 
                    525:    if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
                    526:    {
                    527:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    528:        return;
                    529:    }
                    530: 
1.3       bertrand  531:    liberation_buffer(s_etat_processus, s_buffer);
1.5       bertrand  532: 
                    533:    if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
                    534:            != 0)
                    535:    {
                    536:        (*s_etat_processus).erreur_systeme = d_es_processus;
                    537:        return;
                    538:    }
                    539: 
1.3       bertrand  540:    return;
                    541: }
                    542: 
                    543: 
                    544: // Réécriture des fonctions malloc() et free() de la libc
                    545: 
                    546: void *
                    547: sys_malloc(size_t s)
                    548: {
                    549:    return(malloc(s));
                    550: }
                    551: 
                    552: void
                    553: sys_free(void *ptr)
                    554: {
                    555:    free(ptr);
1.4       bertrand  556:    return;
1.3       bertrand  557: }
                    558: 
1.1       bertrand  559: // vim: ts=4

CVSweb interface <joel.bertrand@systella.fr>