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

1.1       bertrand    1: /*
                      2: ================================================================================
                      3:   RPL/2 (R) version 4.1.20
                      4:   Copyright (C) 1989-2015 Dr. BERTRAND Joël
                      5: 
                      6:   This file is part of RPL/2.
                      7: 
                      8:   RPL/2 is free software; you can redistribute it and/or modify it
                      9:   under the terms of the CeCILL V2 License as published by the french
                     10:   CEA, CNRS and INRIA.
                     11:  
                     12:   RPL/2 is distributed in the hope that it will be useful, but WITHOUT
                     13:   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
                     14:   FITNESS FOR A PARTICULAR PURPOSE.  See the CeCILL V2 License
                     15:   for more details.
                     16:  
                     17:   You should have received a copy of the CeCILL License
                     18:   along with RPL/2. If not, write to info@cecill.info.
                     19: ================================================================================
                     20: */
                     21: 
                     22: 
                     23: #include "rpl-conv.h"
                     24: 
1.3       bertrand   25: // Les fonctions malloc() et free() sont surchargées pour appeler
                     26: // les fonctions rpl_malloc() et rpl_free(). Elles sont désactivées pour
                     27: // éviter d'avoir un allocateur récursif.
                     28: 
                     29: #undef malloc
                     30: #undef realloc
                     31: #undef free
                     32: 
                     33: // Classes :
                     34: // -1 : trop grand pour utiliser l'allocateur, on utilise l'allocateur par
                     35: // défaut du système. La classe -1 est aussi utilisée lorsque le buffer
                     36: // n'a pas encore été alloué. Dans ce cas, il est initialisé à NULL.
1.1       bertrand   37: 
                     38: static size_t                  tailles[] =
                     39:        { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
                     40:        11, 12, 13, 14, 15, 16, 24, 32, 48, 64,
                     41:        96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048,
                     42:        3072, 4096, 6144, 8192, 12288, 16384, 24576, 32768, 49152, 65536,
                     43:        0 };
                     44: static int                     longueur_tailles = 0;
                     45: 
                     46: 
                     47: /*
                     48: ================================================================================
                     49:   Recherche de la longueur optimale du buffer
                     50: ================================================================================
                     51:   Entrée : longueur du buffer à allouer
                     52: --------------------------------------------------------------------------------
                     53:   Sortie : indice de la liste candidate, -1 si aucune liste
                     54: --------------------------------------------------------------------------------
                     55:   Effets de bord : néant
                     56: ================================================================================
                     57: */
                     58: 
                     59: static int
1.3       bertrand   60: recherche_longueur_buffer_optimale(size_t longueur)
1.1       bertrand   61: {
                     62:    int         a;
                     63:    int         b;
                     64:    int         m;
                     65: 
                     66:    a = 0;
                     67:    b = longueur_tailles - 1;
                     68: 
1.3       bertrand   69:    if (longueur > tailles[b])
1.1       bertrand   70:    {
                     71:        return(-1);
                     72:    }
                     73: 
                     74:    while((b - a) > 1)
                     75:    {
                     76:        m = (a + b) / 2;
                     77: 
1.3       bertrand   78:        if (longueur <= tailles[m])
1.1       bertrand   79:        {
                     80:            b = m;
                     81:        }
                     82:        else
                     83:        {
                     84:            a = m;
                     85:        }
                     86:    }
                     87: 
                     88:    return(b);
                     89: }
                     90: 
                     91: 
                     92: /*
                     93: ================================================================================
1.3       bertrand   94:   Allocation d'une enveloppe de buffer
                     95: 
                     96:   Contrairement au malloc() de la libc, cet allocateur fournit une structure
                     97:   (l'enveloppe) contenant un pointeur sur la zone allouée ainsi que la longueur
                     98:   de la zone allouée et une information de classe pour gérer le cache.
                     99:   La zone allouée est comporte un pointeur sur l'enveloppe puis un
                    100:   buffer traditionnel.
                    101: ================================================================================
                    102:   Entrée : état du processus courant
                    103: --------------------------------------------------------------------------------
                    104:   Sortie : enveloppe de buffer
                    105: --------------------------------------------------------------------------------
                    106:   Effets de bord : néant
                    107: ================================================================================
                    108: */
                    109: 
                    110: static inline struct_buffer *
                    111: allocation_enveloppe_buffer(struct_processus *s_etat_processus)
                    112: {
                    113:    struct_buffer           *s_buffer;
                    114: 
                    115:    if ((*s_etat_processus).pointeur_enveloppes_buffers > 0)
                    116:    {
                    117:        s_buffer = (*s_etat_processus).enveloppes_buffers
                    118:                [--(*s_etat_processus).pointeur_enveloppes_buffers];
                    119:    }
                    120:    else
                    121:    {
                    122:        if ((s_buffer = sys_malloc(sizeof(struct_buffer))) == NULL)
                    123:        {
                    124:            (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    125:            return(NULL);
                    126:        }
                    127:    }
                    128: 
                    129:    return(s_buffer);
                    130: }
                    131: 
                    132: 
                    133: /*
                    134: ================================================================================
                    135:   Libération d'une enveloppe de buffer
                    136: 
                    137:   Ne libère pas le buffer qui doit être libéré à part.
                    138: ================================================================================
                    139:   Entrée : état du processus courant, enveloppe
                    140: --------------------------------------------------------------------------------
                    141:   Sortie : néant
                    142: --------------------------------------------------------------------------------
                    143:   Effets de bord : néant
                    144: ================================================================================
                    145: */
                    146: 
                    147: static inline void
                    148: liberation_enveloppe_buffer(struct_processus *s_etat_processus,
                    149:        struct_buffer *s_buffer)
                    150: {
                    151:    if ((*s_etat_processus).pointeur_enveloppes_buffers < TAILLE_CACHE)
                    152:    {
                    153:        (*s_etat_processus).enveloppes_buffers
                    154:                [(*s_etat_processus).pointeur_enveloppes_buffers++] = s_buffer;
                    155:    }
                    156:    else
                    157:    {
                    158:        sys_free(s_buffer);
                    159:    }
                    160: 
                    161:    return;
                    162: }
                    163: 
                    164: 
                    165: /*
                    166: ================================================================================
                    167:   Initialisation des structures de données de l'allocateur
1.1       bertrand  168: ================================================================================
1.3       bertrand  169:   Entrée : état du processus courant (contient les données nécessaires
                    170:            au fonctionnement de l'allocateur par thread)
1.1       bertrand  171: --------------------------------------------------------------------------------
1.3       bertrand  172:   Sortie : néant
1.1       bertrand  173: --------------------------------------------------------------------------------
                    174:   Effets de bord : néant
                    175: ================================================================================
                    176: */
                    177: 
                    178: void
                    179: initialisation_allocateur_buffer(struct_processus *s_etat_processus)
                    180: {
                    181:    int         i;
                    182: 
                    183:    if (longueur_tailles == 0)
                    184:    {
                    185:        while(tailles[longueur_tailles] != 0)
                    186:        {
                    187:            longueur_tailles++;
                    188:        }
                    189: 
1.3       bertrand  190:        if (((*s_etat_processus).cache_buffer = sys_malloc(((size_t)
1.1       bertrand  191:                longueur_tailles) * sizeof(unsigned char **))) == NULL)
                    192:        {
                    193:            (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    194:            return;
                    195:        }
                    196: 
1.3       bertrand  197:        if (((*s_etat_processus).pointeur_cache_buffer = sys_malloc(((size_t)
1.1       bertrand  198:                longueur_tailles) * sizeof(int))) == NULL)
                    199:        {
                    200:            (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    201:            return;
                    202:        }
1.3       bertrand  203:    }
1.1       bertrand  204: 
1.3       bertrand  205:    for(i = 0; i < longueur_tailles; i++)
                    206:    {
                    207:        if (((*s_etat_processus).cache_buffer[i] =
                    208:                sys_malloc(TAILLE_CACHE * sizeof(unsigned char *))) == NULL)
1.1       bertrand  209:        {
1.3       bertrand  210:            (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    211:            return;
                    212:        }
1.1       bertrand  213: 
1.3       bertrand  214:        (*s_etat_processus).pointeur_cache_buffer[i] = 0;
1.1       bertrand  215:    }
                    216: 
1.3       bertrand  217:    (*s_etat_processus).pointeur_enveloppes_buffers = 0;
1.1       bertrand  218:    return;
                    219: }
                    220: 
                    221: 
1.3       bertrand  222: /*
                    223: ================================================================================
                    224:   Libération des structures de données de l'allocateur
                    225: ================================================================================
                    226:   Entrée : état du processus courant (contient les données nécessaires
                    227:            au fonctionnement de l'allocateur par thread)
                    228: --------------------------------------------------------------------------------
                    229:   Sortie : néant
                    230: --------------------------------------------------------------------------------
                    231:   Effets de bord : néant
                    232: ================================================================================
                    233: */
                    234: 
1.1       bertrand  235: void
                    236: liberation_allocateur_buffer(struct_processus *s_etat_processus)
                    237: {
                    238:    int                         i;
                    239:    int                         j;
                    240: 
                    241:    for(i = 0; i < longueur_tailles; i++)
                    242:    {
1.5     ! bertrand  243: uprintf("L %d ************* %d ********************\n", getpid(), i);
1.1       bertrand  244:        for(j = 0; j < (*s_etat_processus).pointeur_cache_buffer[i]; j++)
                    245:        {
1.5     ! bertrand  246: uprintf("L %d %p\n", getpid(), (*s_etat_processus).cache_buffer[i][j]);
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.3       bertrand  261:    return;
1.1       bertrand  262: }
                    263: 
                    264: 
1.3       bertrand  265: /*
                    266: ================================================================================
                    267:   Allocation d'un buffer et de son enveloppe
                    268: ================================================================================
                    269:   Entrée : état du processus courant, longueur du buffer
                    270: --------------------------------------------------------------------------------
                    271:   Sortie : néant
                    272: --------------------------------------------------------------------------------
                    273:   Effets de bord : néant
                    274: ================================================================================
                    275: */
1.1       bertrand  276: 
                    277: struct_buffer *
1.3       bertrand  278: allocation_buffer(struct_processus *s_etat_processus, size_t longueur)
1.1       bertrand  279: {
                    280:    int                     classe;
                    281: 
                    282:    struct_buffer           *s_buffer;
                    283: 
1.3       bertrand  284:    if ((s_buffer = allocation_enveloppe_buffer(s_etat_processus)) == NULL)
1.1       bertrand  285:    {
                    286:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    287:        return(NULL);
                    288:    }
                    289: 
1.3       bertrand  290:    if (longueur == 0)
                    291:    {
                    292:        (*s_buffer).buffer = NULL;
                    293:        classe = -1;
                    294:    }
                    295:    else
                    296:    {
                    297:        classe = recherche_longueur_buffer_optimale(longueur);
1.1       bertrand  298: 
1.3       bertrand  299:        if (classe >= 0)
1.1       bertrand  300:        {
1.3       bertrand  301:            // La classe correspond à la longueur effectivement disponible
                    302:            // dans le buffer alloué. Or il faut ajouter à ce buffer un
                    303:            // pointeur vers l'enveloppe (struct_buffer *).
                    304: 
                    305:            if ((*s_etat_processus).pointeur_cache_buffer[classe] > 0)
                    306:            {
                    307:                (*s_buffer).buffer = (*s_etat_processus).cache_buffer[classe]
                    308:                        [--(*s_etat_processus).pointeur_cache_buffer[classe]];
1.5     ! bertrand  309: uprintf("Cachée : %d %p\n", getpid(), (*s_buffer).buffer);
1.3       bertrand  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:                }
1.5     ! bertrand  321: uprintf("Alloué : %d %p\n", getpid(), (*s_buffer).buffer);
1.3       bertrand  322:            }
1.1       bertrand  323:        }
                    324:        else
                    325:        {
1.3       bertrand  326:            if (((*s_buffer).buffer = sys_malloc((((size_t) longueur) *
                    327:                    sizeof(unsigned char)) + sizeof(struct_buffer *))) == NULL)
1.1       bertrand  328:            {
                    329:                (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    330:                return(NULL);
                    331:            }
1.5     ! bertrand  332: uprintf("Alloué (non cachée) : %d %p\n", getpid(), (*s_buffer).buffer);
1.1       bertrand  333:        }
                    334:    }
1.2       bertrand  335: 
1.1       bertrand  336:    (*s_buffer).classe = classe;
                    337:    (*s_buffer).longueur_requise = longueur;
                    338: 
1.3       bertrand  339:    // (*s_buffer).buffer est un pointeur sur un 'unsigned char *' et se
                    340:    // compose d'un pointeur vers s_buffer suivi d'une zone variable.
                    341:    // s_buffer est le pointeur sur l'enveloppe.
                    342:    // (*s_buffer).buffer est le pointeur sur le début de la zone allouée
                    343:    // aux données.
                    344:    (*(((struct_buffer **) (*s_buffer).buffer))) = s_buffer;
                    345: 
                    346:    return(s_buffer);
1.1       bertrand  347: }
                    348: 
                    349: 
1.3       bertrand  350: /*
                    351: ================================================================================
                    352:   Libération d'un buffer et de son enveloppe
                    353: ================================================================================
                    354:   Entrée : état du processus courant, longueur du buffer
                    355: --------------------------------------------------------------------------------
                    356:   Sortie : néant
                    357: --------------------------------------------------------------------------------
                    358:   Effets de bord : néant
                    359: ================================================================================
                    360: */
                    361: 
1.1       bertrand  362: void
                    363: liberation_buffer(struct_processus *s_etat_processus, struct_buffer *s_buffer)
                    364: {
                    365:    if ((*s_buffer).classe < 0)
                    366:    {
1.3       bertrand  367:        if ((*s_buffer).buffer != NULL)
                    368:        {
                    369:            sys_free((*s_buffer).buffer);
1.5     ! bertrand  370: uprintf("Libération (trop grand) : %d %p\n", getpid(), (*s_buffer).buffer);
1.3       bertrand  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;
1.5     ! bertrand  381: uprintf("Mise en cache : %d %p\n", getpid(), (*s_buffer).buffer);
1.1       bertrand  382:        }
                    383:        else
                    384:        {
1.3       bertrand  385:            sys_free((*s_buffer).buffer);
1.5     ! bertrand  386: uprintf("Libération (cache plein) : %d %p\n", getpid(), (*s_buffer).buffer);
1.1       bertrand  387:        }
                    388:    }
                    389: 
                    390:    liberation_enveloppe_buffer(s_etat_processus, s_buffer);
                    391:    return;
                    392: }
                    393: 
1.3       bertrand  394: 
                    395: /*
                    396: ================================================================================
                    397:   Allocation d'un buffer et de son enveloppe. Le pointeur retourné est
                    398:   le pointeur sur le début de la zone utilisable pour être conforme au
                    399:   malloc() de la libc.
                    400: ================================================================================
                    401:   Entrée : état du processus courant, longueur du buffer
                    402: --------------------------------------------------------------------------------
                    403:   Sortie : pointeur sur un void
                    404: --------------------------------------------------------------------------------
                    405:   Effets de bord : néant
                    406: ================================================================================
                    407: */
                    408: 
                    409: void *
                    410: rpl_malloc(struct_processus *s_etat_processus, size_t s)
                    411: {
                    412:    struct_buffer               *s_buffer;
                    413: 
                    414:    void                        *pointeur;
                    415: 
1.5     ! bertrand  416:    if (pthread_mutex_lock(&((*s_etat_processus).mutex_allocation_buffer)) != 0)
        !           417:    {
        !           418:        (*s_etat_processus).erreur_systeme = d_es_processus;
        !           419:        return(NULL);
        !           420:    }
        !           421: 
1.3       bertrand  422:    if ((s_buffer = allocation_buffer(s_etat_processus, s)) == NULL)
                    423:    {
1.5     ! bertrand  424:        pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer));
        !           425: 
1.3       bertrand  426:        (*s_etat_processus).erreur_systeme = d_es_allocation_memoire;
                    427:        return(NULL);
                    428:    }
                    429: 
                    430:    pointeur = (*s_buffer).buffer + sizeof(struct_buffer *);
1.5     ! bertrand  431: 
        !           432:    if (pthread_mutex_unlock(&((*s_etat_processus).mutex_allocation_buffer))
        !           433:            != 0)
        !           434:    {
        !           435:        (*s_etat_processus).erreur_systeme = d_es_processus;
        !           436:        return(NULL);
        !           437:    }
        !           438: 
1.3       bertrand  439:    return(pointeur);
                    440: }
                    441: 
                    442: 
                    443: /*
                    444: ================================================================================
                    445:   Réallocation d'un buffer et de son enveloppe. Le pointeur retourné est
                    446:   le pointeur sur le début de la zone utilisable pour être conforme au
                    447:   malloc() de la libc.
                    448: ================================================================================
                    449:   Entrée : état du processus courant, longueur du buffer
                    450: --------------------------------------------------------------------------------
                    451:   Sortie : pointeur sur un void
                    452: --------------------------------------------------------------------------------
                    453:   Effets de bord : néant
                    454: ================================================================================
                    455: */
                    456: 
                    457: void *
                    458: rpl_realloc(struct_processus *s_etat_processus, void *ptr, size_t s)
                    459: {
                    460:    struct_buffer               *s_ancien_buffer;
                    461:    struct_buffer               *s_nouveau_buffer;
                    462: 
                    463:    size_t                      longueur_copie;
                    464: 
                    465:    void                        *pointeur;
                    466: 
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>