Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/malloc.c

    r207533f rd161715  
    6565#define BASE_ALIGN  16
    6666
    67 /** Heap shrink granularity
    68  *
    69  * Try not to pump and stress the heap to much
    70  * by shrinking and enlarging it too often.
    71  * A heap area won't shrunk if it the released
    72  * free block is smaller than this constant.
    73  *
    74  */
    75 #define SHRINK_GRANULARITY  (64 * PAGE_SIZE)
    76 
    7767/** Overhead of each heap block. */
    7868#define STRUCT_OVERHEAD \
    7969        (sizeof(heap_block_head_t) + sizeof(heap_block_foot_t))
    8070
    81 /** Overhead of each area. */
    82 #define AREA_OVERHEAD(size) \
    83         (ALIGN_UP(size + sizeof(heap_area_t), BASE_ALIGN))
    84 
    8571/** Calculate real size of a heap block.
    8672 *
     
    10086 *
    10187 */
    102 #define AREA_FIRST_BLOCK_HEAD(area) \
     88#define AREA_FIRST_BLOCK(area) \
    10389        (ALIGN_UP(((uintptr_t) (area)) + sizeof(heap_area_t), BASE_ALIGN))
    104 
    105 /** Get last block in heap area.
    106  *
    107  */
    108 #define AREA_LAST_BLOCK_FOOT(area) \
    109         (((uintptr_t) (area)->end) - sizeof(heap_block_foot_t))
    110 
    111 /** Get header in heap block.
    112  *
    113  */
    114 #define BLOCK_HEAD(foot) \
    115         ((heap_block_head_t *) \
    116             (((uintptr_t) (foot)) + sizeof(heap_block_foot_t) - (foot)->size))
    11790
    11891/** Get footer in heap block.
     
    12194#define BLOCK_FOOT(head) \
    12295        ((heap_block_foot_t *) \
    123             (((uintptr_t) (head)) + (head)->size - sizeof(heap_block_foot_t)))
     96            (((uintptr_t) head) + head->size - sizeof(heap_block_foot_t)))
    12497
    12598/** Heap area.
     
    142115        void *end;
    143116       
    144         /** Previous heap area */
    145         struct heap_area *prev;
    146        
    147117        /** Next heap area */
    148118        struct heap_area *next;
     
    187157
    188158/** Next heap block to examine (next fit algorithm) */
    189 static heap_block_head_t *next_fit = NULL;
     159static heap_block_head_t *next = NULL;
    190160
    191161/** Futex for thread-safe heap manipulation */
    192162static futex_t malloc_futex = FUTEX_INITIALIZER;
    193 
    194 #ifndef NDEBUG
    195 
    196 #define malloc_assert(expr) \
    197         do { \
    198                 if (!(expr)) {\
    199                         futex_up(&malloc_futex); \
    200                         assert_abort(#expr, __FILE__, __LINE__); \
    201                 } \
    202         } while (0)
    203 
    204 #else /* NDEBUG */
    205 
    206 #define malloc_assert(expr)
    207 
    208 #endif /* NDEBUG */
    209163
    210164/** Initialize a heap block
     
    248202        heap_block_head_t *head = (heap_block_head_t *) addr;
    249203       
    250         malloc_assert(head->magic == HEAP_BLOCK_HEAD_MAGIC);
     204        assert(head->magic == HEAP_BLOCK_HEAD_MAGIC);
    251205       
    252206        heap_block_foot_t *foot = BLOCK_FOOT(head);
    253207       
    254         malloc_assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC);
    255         malloc_assert(head->size == foot->size);
     208        assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC);
     209        assert(head->size == foot->size);
    256210}
    257211
    258212/** Check a heap area structure
    259213 *
    260  * Should be called only inside the critical section.
    261  *
    262214 * @param addr Address of the heap area.
    263215 *
     
    267219        heap_area_t *area = (heap_area_t *) addr;
    268220       
    269         malloc_assert(area->magic == HEAP_AREA_MAGIC);
    270         malloc_assert(addr == area->start);
    271         malloc_assert(area->start < area->end);
    272         malloc_assert(((uintptr_t) area->start % PAGE_SIZE) == 0);
    273         malloc_assert(((uintptr_t) area->end % PAGE_SIZE) == 0);
     221        assert(area->magic == HEAP_AREA_MAGIC);
     222        assert(area->start < area->end);
     223        assert(((uintptr_t) area->start % PAGE_SIZE) == 0);
     224        assert(((uintptr_t) area->end % PAGE_SIZE) == 0);
    274225}
    275226
    276227/** Create new heap area
    277228 *
    278  * Should be called only inside the critical section.
    279  *
    280  * @param size Size of the area.
     229 * @param start Preffered starting address of the new area.
     230 * @param size  Size of the area.
    281231 *
    282232 */
     
    298248       
    299249        area->start = astart;
    300         area->end = (void *) ((uintptr_t) astart + asize);
    301         area->prev = NULL;
     250        area->end = (void *)
     251            ALIGN_DOWN((uintptr_t) astart + asize, BASE_ALIGN);
    302252        area->next = NULL;
    303253        area->magic = HEAP_AREA_MAGIC;
    304254       
    305         void *block = (void *) AREA_FIRST_BLOCK_HEAD(area);
     255        void *block = (void *) AREA_FIRST_BLOCK(area);
    306256        size_t bsize = (size_t) (area->end - block);
    307257       
     
    312262                last_heap_area = area;
    313263        } else {
    314                 area->prev = last_heap_area;
    315264                last_heap_area->next = area;
    316265                last_heap_area = area;
     
    322271/** Try to enlarge a heap area
    323272 *
    324  * Should be called only inside the critical section.
    325  *
    326273 * @param area Heap area to grow.
    327  * @param size Gross size to grow (bytes).
    328  *
    329  * @return True if successful.
     274 * @param size Gross size of item to allocate (bytes).
    330275 *
    331276 */
     
    337282        area_check(area);
    338283       
     284        size_t asize = ALIGN_UP((size_t) (area->end - area->start) + size,
     285            PAGE_SIZE);
     286       
    339287        /* New heap area size */
    340         size_t gross_size = (size_t) (area->end - area->start) + size;
    341         size_t asize = ALIGN_UP(gross_size, PAGE_SIZE);
    342         void *end = (void *) ((uintptr_t) area->start + asize);
     288        void *end = (void *)
     289            ALIGN_DOWN((uintptr_t) area->start + asize, BASE_ALIGN);
    343290       
    344291        /* Check for overflow */
     
    352299       
    353300        /* Add new free block */
    354         size_t net_size = (size_t) (end - area->end);
    355         if (net_size > 0)
    356                 block_init(area->end, net_size, true, area);
     301        block_init(area->end, (size_t) (end - area->end), true, area);
    357302       
    358303        /* Update heap area parameters */
     
    364309/** Try to enlarge any of the heap areas
    365310 *
    366  * Should be called only inside the critical section.
    367  *
    368311 * @param size Gross size of item to allocate (bytes).
    369312 *
     
    375318       
    376319        /* First try to enlarge some existing area */
    377         for (heap_area_t *area = first_heap_area; area != NULL;
    378             area = area->next) {
     320        heap_area_t *area;
     321        for (area = first_heap_area; area != NULL; area = area->next) {
    379322                if (area_grow(area, size))
    380323                        return true;
     
    382325       
    383326        /* Eventually try to create a new area */
    384         return area_create(AREA_OVERHEAD(size));
    385 }
    386 
    387 /** Try to shrink heap
    388  *
    389  * Should be called only inside the critical section.
     327        return area_create(AREA_FIRST_BLOCK(size));
     328}
     329
     330/** Try to shrink heap space
     331 *
    390332 * In all cases the next pointer is reset.
    391333 *
    392  * @param area Last modified heap area.
    393  *
    394  */
    395 static void heap_shrink(heap_area_t *area)
    396 {
    397         area_check(area);
    398        
    399         heap_block_foot_t *last_foot =
    400             (heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area);
    401         heap_block_head_t *last_head = BLOCK_HEAD(last_foot);
    402        
    403         block_check((void *) last_head);
    404         malloc_assert(last_head->area == area);
    405        
    406         if (last_head->free) {
    407                 /*
    408                  * The last block of the heap area is
    409                  * unused. The area might be potentially
    410                  * shrunk.
    411                  */
    412                
    413                 heap_block_head_t *first_head =
    414                     (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(area);
    415                
    416                 block_check((void *) first_head);
    417                 malloc_assert(first_head->area == area);
    418                
    419                 size_t shrink_size = ALIGN_DOWN(last_head->size, PAGE_SIZE);
    420                
    421                 if (first_head == last_head) {
    422                         /*
    423                          * The entire heap area consists of a single
    424                          * free heap block. This means we can get rid
    425                          * of it entirely.
    426                          */
    427                        
    428                         heap_area_t *prev = area->prev;
    429                         heap_area_t *next = area->next;
    430                        
    431                         if (prev != NULL) {
    432                                 area_check(prev);
    433                                 prev->next = next;
    434                         } else
    435                                 first_heap_area = next;
    436                        
    437                         if (next != NULL) {
    438                                 area_check(next);
    439                                 next->prev = prev;
    440                         } else
    441                                 last_heap_area = prev;
    442                        
    443                         as_area_destroy(area->start);
    444                 } else if (shrink_size >= SHRINK_GRANULARITY) {
    445                         /*
    446                          * Make sure that we always shrink the area
    447                          * by a multiple of page size and update
    448                          * the block layout accordingly.
    449                          */
    450                        
    451                         size_t asize = (size_t) (area->end - area->start) - shrink_size;
    452                         void *end = (void *) ((uintptr_t) area->start + asize);
    453                        
    454                         /* Resize the address space area */
    455                         int ret = as_area_resize(area->start, asize, 0);
    456                         if (ret != EOK)
    457                                 abort();
    458                        
    459                         /* Update heap area parameters */
    460                         area->end = end;
    461                         size_t excess = ((size_t) area->end) - ((size_t) last_head);
    462                        
    463                         if (excess > 0) {
    464                                 if (excess >= STRUCT_OVERHEAD) {
    465                                         /*
    466                                          * The previous block cannot be free and there
    467                                          * is enough free space left in the area to
    468                                          * create a new free block.
    469                                          */
    470                                         block_init((void *) last_head, excess, true, area);
    471                                 } else {
    472                                         /*
    473                                          * The excess is small. Therefore just enlarge
    474                                          * the previous block.
    475                                          */
    476                                         heap_block_foot_t *prev_foot = (heap_block_foot_t *)
    477                                             (((uintptr_t) last_head) - sizeof(heap_block_foot_t));
    478                                         heap_block_head_t *prev_head = BLOCK_HEAD(prev_foot);
    479                                        
    480                                         block_check((void *) prev_head);
    481                                        
    482                                         block_init(prev_head, prev_head->size + excess,
    483                                             prev_head->free, area);
    484                                 }
    485                         }
    486                 }
    487         }
    488        
    489         next_fit = NULL;
     334 */
     335static void heap_shrink(void)
     336{
     337        next = NULL;
    490338}
    491339
     
    514362static void split_mark(heap_block_head_t *cur, const size_t size)
    515363{
    516         malloc_assert(cur->size >= size);
     364        assert(cur->size >= size);
    517365       
    518366        /* See if we should split the block. */
     
    550398{
    551399        area_check((void *) area);
    552         malloc_assert((void *) first_block >= (void *) AREA_FIRST_BLOCK_HEAD(area));
    553         malloc_assert((void *) first_block < area->end);
    554        
    555         for (heap_block_head_t *cur = first_block; (void *) cur < area->end;
     400        assert((void *) first_block >= (void *) AREA_FIRST_BLOCK(area));
     401        assert((void *) first_block < area->end);
     402       
     403        heap_block_head_t *cur;
     404        for (cur = first_block; (void *) cur < area->end;
    556405            cur = (heap_block_head_t *) (((void *) cur) + cur->size)) {
    557406                block_check(cur);
     
    576425                                split_mark(cur, real_size);
    577426                               
    578                                 next_fit = cur;
     427                                next = cur;
    579428                                return addr;
    580429                        } else {
     
    587436                                         * data in (including alignment).
    588437                                         */
    589                                         if ((void *) cur > (void *) AREA_FIRST_BLOCK_HEAD(area)) {
     438                                        if ((void *) cur > (void *) AREA_FIRST_BLOCK(area)) {
    590439                                                /*
    591440                                                 * There is a block before the current block.
     
    628477                                                split_mark(next_head, real_size);
    629478                                               
    630                                                 next_fit = next_head;
     479                                                next = next_head;
    631480                                                return aligned;
    632481                                        } else {
     
    647496                                                        size_t reduced_size = cur->size - excess;
    648497                                                        cur = (heap_block_head_t *)
    649                                                             (AREA_FIRST_BLOCK_HEAD(area) + excess);
     498                                                            (AREA_FIRST_BLOCK(area) + excess);
    650499                                                       
    651                                                         block_init((void *) AREA_FIRST_BLOCK_HEAD(area),
    652                                                             excess, true, area);
     500                                                        block_init((void *) AREA_FIRST_BLOCK(area), excess,
     501                                                            true, area);
    653502                                                        block_init(cur, reduced_size, true, area);
    654503                                                        split_mark(cur, real_size);
    655504                                                       
    656                                                         next_fit = cur;
     505                                                        next = cur;
    657506                                                        return aligned;
    658507                                                }
     
    678527static void *malloc_internal(const size_t size, const size_t align)
    679528{
    680         malloc_assert(first_heap_area != NULL);
     529        assert(first_heap_area != NULL);
    681530       
    682531        if (align == 0)
     
    692541       
    693542        /* Try the next fit approach */
    694         split = next_fit;
     543        split = next;
    695544       
    696545        if (split != NULL) {
     
    703552       
    704553        /* Search the entire heap */
    705         for (heap_area_t *area = first_heap_area; area != NULL;
    706             area = area->next) {
     554        heap_area_t *area;
     555        for (area = first_heap_area; area != NULL; area = area->next) {
    707556                heap_block_head_t *first = (heap_block_head_t *)
    708                     AREA_FIRST_BLOCK_HEAD(area);
     557                    AREA_FIRST_BLOCK(area);
    709558               
    710559                void *addr = malloc_area(area, first, split, real_size,
     
    803652       
    804653        block_check(head);
    805         malloc_assert(!head->free);
     654        assert(!head->free);
    806655       
    807656        heap_area_t *area = head->area;
    808657       
    809658        area_check(area);
    810         malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area));
    811         malloc_assert((void *) head < area->end);
     659        assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
     660        assert((void *) head < area->end);
    812661       
    813662        void *ptr = NULL;
     
    826675                        block_init((void *) head + real_size,
    827676                            orig_size - real_size, true, area);
    828                         heap_shrink(area);
     677                        heap_shrink();
    829678                }
    830679               
     
    848697                       
    849698                        ptr = ((void *) head) + sizeof(heap_block_head_t);
    850                         next_fit = NULL;
     699                        next = NULL;
    851700                } else
    852701                        reloc = true;
     
    880729       
    881730        block_check(head);
    882         malloc_assert(!head->free);
     731        assert(!head->free);
    883732       
    884733        heap_area_t *area = head->area;
    885734       
    886735        area_check(area);
    887         malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area));
    888         malloc_assert((void *) head < area->end);
     736        assert((void *) head >= (void *) AREA_FIRST_BLOCK(area));
     737        assert((void *) head < area->end);
    889738       
    890739        /* Mark the block itself as free. */
     
    902751       
    903752        /* Look at the previous block. If it is free, merge the two. */
    904         if ((void *) head > (void *) AREA_FIRST_BLOCK_HEAD(area)) {
     753        if ((void *) head > (void *) AREA_FIRST_BLOCK(area)) {
    905754                heap_block_foot_t *prev_foot =
    906755                    (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t));
     
    916765        }
    917766       
    918         heap_shrink(area);
     767        heap_shrink();
    919768       
    920769        futex_up(&malloc_futex);
    921770}
    922771
    923 void *heap_check(void)
    924 {
    925         futex_down(&malloc_futex);
    926        
    927         if (first_heap_area == NULL) {
    928                 futex_up(&malloc_futex);
    929                 return (void *) -1;
    930         }
    931        
    932         /* Walk all heap areas */
    933         for (heap_area_t *area = first_heap_area; area != NULL;
    934             area = area->next) {
    935                
    936                 /* Check heap area consistency */
    937                 if ((area->magic != HEAP_AREA_MAGIC) ||
    938                     ((void *) area != area->start) ||
    939                     (area->start >= area->end) ||
    940                     (((uintptr_t) area->start % PAGE_SIZE) != 0) ||
    941                     (((uintptr_t) area->end % PAGE_SIZE) != 0)) {
    942                         futex_up(&malloc_futex);
    943                         return (void *) area;
    944                 }
    945                
    946                 /* Walk all heap blocks */
    947                 for (heap_block_head_t *head = (heap_block_head_t *)
    948                     AREA_FIRST_BLOCK_HEAD(area); (void *) head < area->end;
    949                     head = (heap_block_head_t *) (((void *) head) + head->size)) {
    950                        
    951                         /* Check heap block consistency */
    952                         if (head->magic != HEAP_BLOCK_HEAD_MAGIC) {
    953                                 futex_up(&malloc_futex);
    954                                 return (void *) head;
    955                         }
    956                        
    957                         heap_block_foot_t *foot = BLOCK_FOOT(head);
    958                        
    959                         if ((foot->magic != HEAP_BLOCK_FOOT_MAGIC) ||
    960                             (head->size != foot->size)) {
    961                                 futex_up(&malloc_futex);
    962                                 return (void *) foot;
    963                         }
    964                 }
    965         }
    966        
    967         futex_up(&malloc_futex);
    968        
    969         return NULL;
    970 }
    971 
    972772/** @}
    973773 */
Note: See TracChangeset for help on using the changeset viewer.