malloc.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2009 Martin Decky
00003  * Copyright (c) 2009 Petr Tuma
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions
00008  * are met:
00009  *
00010  * - Redistributions of source code must retain the above copyright
00011  *   notice, this list of conditions and the following disclaimer.
00012  * - Redistributions in binary form must reproduce the above copyright
00013  *   notice, this list of conditions and the following disclaimer in the
00014  *   documentation and/or other materials provided with the distribution.
00015  * - The name of the author may not be used to endorse or promote products
00016  *   derived from this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00019  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00020  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00021  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00023  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00024  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00025  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00026  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00027  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00028  */
00029 
00036 #include <malloc.h>
00037 #include <bool.h>
00038 #include <as.h>
00039 #include <align.h>
00040 #include <macros.h>
00041 #include <assert.h>
00042 #include <errno.h>
00043 #include <bitops.h>
00044 #include <mem.h>
00045 #include <futex.h>
00046 #include <stdlib.h>
00047 #include <adt/gcdlcm.h>
00048 #include "private/malloc.h"
00049 
00051 #define HEAP_BLOCK_HEAD_MAGIC  UINT32_C(0xBEEF0101)
00052 
00054 #define HEAP_BLOCK_FOOT_MAGIC  UINT32_C(0xBEEF0202)
00055 
00057 #define HEAP_AREA_MAGIC  UINT32_C(0xBEEFCAFE)
00058 
00065 #define BASE_ALIGN  16
00066 
00075 #define SHRINK_GRANULARITY  (64 * PAGE_SIZE)
00076 
00078 #define STRUCT_OVERHEAD \
00079         (sizeof(heap_block_head_t) + sizeof(heap_block_foot_t))
00080 
00082 #define AREA_OVERHEAD(size) \
00083         (ALIGN_UP(size + sizeof(heap_area_t), BASE_ALIGN))
00084 
00090 #define GROSS_SIZE(size)  ((size) + STRUCT_OVERHEAD)
00091 
00097 #define NET_SIZE(size)  ((size) - STRUCT_OVERHEAD)
00098 
00102 #define AREA_FIRST_BLOCK_HEAD(area) \
00103         (ALIGN_UP(((uintptr_t) (area)) + sizeof(heap_area_t), BASE_ALIGN))
00104 
00108 #define AREA_LAST_BLOCK_FOOT(area) \
00109         (((uintptr_t) (area)->end) - sizeof(heap_block_foot_t))
00110 
00114 #define BLOCK_HEAD(foot) \
00115         ((heap_block_head_t *) \
00116             (((uintptr_t) (foot)) + sizeof(heap_block_foot_t) - (foot)->size))
00117 
00121 #define BLOCK_FOOT(head) \
00122         ((heap_block_foot_t *) \
00123             (((uintptr_t) (head)) + (head)->size - sizeof(heap_block_foot_t)))
00124 
00133 typedef struct heap_area {
00139         void *start;
00140         
00142         void *end;
00143         
00145         struct heap_area *prev;
00146         
00148         struct heap_area *next;
00149         
00151         uint32_t magic;
00152 } heap_area_t;
00153 
00157 typedef struct {
00158         /* Size of the block (including header and footer) */
00159         size_t size;
00160         
00161         /* Indication of a free block */
00162         bool free;
00163         
00165         heap_area_t *area;
00166         
00167         /* A magic value to detect overwrite of heap header */
00168         uint32_t magic;
00169 } heap_block_head_t;
00170 
00174 typedef struct {
00175         /* Size of the block (including header and footer) */
00176         size_t size;
00177         
00178         /* A magic value to detect overwrite of heap footer */
00179         uint32_t magic;
00180 } heap_block_foot_t;
00181 
00183 static heap_area_t *first_heap_area = NULL;
00184 
00186 static heap_area_t *last_heap_area = NULL;
00187 
00189 static heap_block_head_t *next_fit = NULL;
00190 
00192 static futex_t malloc_futex = FUTEX_INITIALIZER;
00193 
00194 #ifndef NDEBUG
00195 
00196 #define malloc_assert(expr) \
00197         do { \
00198                 if (!(expr)) {\
00199                         futex_up(&malloc_futex); \
00200                         assert_abort(#expr, __FILE__, __LINE__); \
00201                 } \
00202         } while (0)
00203 
00204 #else /* NDEBUG */
00205 
00206 #define malloc_assert(expr)
00207 
00208 #endif /* NDEBUG */
00209 
00221 static void block_init(void *addr, size_t size, bool free, heap_area_t *area)
00222 {
00223         /* Calculate the position of the header and the footer */
00224         heap_block_head_t *head = (heap_block_head_t *) addr;
00225         
00226         head->size = size;
00227         head->free = free;
00228         head->area = area;
00229         head->magic = HEAP_BLOCK_HEAD_MAGIC;
00230         
00231         heap_block_foot_t *foot = BLOCK_FOOT(head);
00232         
00233         foot->size = size;
00234         foot->magic = HEAP_BLOCK_FOOT_MAGIC;
00235 }
00236 
00246 static void block_check(void *addr)
00247 {
00248         heap_block_head_t *head = (heap_block_head_t *) addr;
00249         
00250         malloc_assert(head->magic == HEAP_BLOCK_HEAD_MAGIC);
00251         
00252         heap_block_foot_t *foot = BLOCK_FOOT(head);
00253         
00254         malloc_assert(foot->magic == HEAP_BLOCK_FOOT_MAGIC);
00255         malloc_assert(head->size == foot->size);
00256 }
00257 
00265 static void area_check(void *addr)
00266 {
00267         heap_area_t *area = (heap_area_t *) addr;
00268         
00269         malloc_assert(area->magic == HEAP_AREA_MAGIC);
00270         malloc_assert(addr == area->start);
00271         malloc_assert(area->start < area->end);
00272         malloc_assert(((uintptr_t) area->start % PAGE_SIZE) == 0);
00273         malloc_assert(((uintptr_t) area->end % PAGE_SIZE) == 0);
00274 }
00275 
00283 static bool area_create(size_t size)
00284 {
00285         void *start = as_get_mappable_page(size);
00286         if (start == NULL)
00287                 return false;
00288         
00289         /* Align the heap area on page boundary */
00290         void *astart = (void *) ALIGN_UP((uintptr_t) start, PAGE_SIZE);
00291         size_t asize = ALIGN_UP(size, PAGE_SIZE);
00292         
00293         astart = as_area_create(astart, asize, AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE);
00294         if (astart == (void *) -1)
00295                 return false;
00296         
00297         heap_area_t *area = (heap_area_t *) astart;
00298         
00299         area->start = astart;
00300         area->end = (void *) ((uintptr_t) astart + asize);
00301         area->prev = NULL;
00302         area->next = NULL;
00303         area->magic = HEAP_AREA_MAGIC;
00304         
00305         void *block = (void *) AREA_FIRST_BLOCK_HEAD(area);
00306         size_t bsize = (size_t) (area->end - block);
00307         
00308         block_init(block, bsize, true, area);
00309         
00310         if (last_heap_area == NULL) {
00311                 first_heap_area = area;
00312                 last_heap_area = area;
00313         } else {
00314                 area->prev = last_heap_area;
00315                 last_heap_area->next = area;
00316                 last_heap_area = area;
00317         }
00318         
00319         return true;
00320 }
00321 
00332 static bool area_grow(heap_area_t *area, size_t size)
00333 {
00334         if (size == 0)
00335                 return true;
00336         
00337         area_check(area);
00338         
00339         /* New heap area size */
00340         size_t gross_size = (size_t) (area->end - area->start) + size;
00341         size_t asize = ALIGN_UP(gross_size, PAGE_SIZE);
00342         void *end = (void *) ((uintptr_t) area->start + asize);
00343         
00344         /* Check for overflow */
00345         if (end < area->start)
00346                 return false;
00347         
00348         /* Resize the address space area */
00349         int ret = as_area_resize(area->start, asize, 0);
00350         if (ret != EOK)
00351                 return false;
00352         
00353         /* Add new free block */
00354         size_t net_size = (size_t) (end - area->end);
00355         if (net_size > 0)
00356                 block_init(area->end, net_size, true, area);
00357         
00358         /* Update heap area parameters */
00359         area->end = end;
00360         
00361         return true;
00362 }
00363 
00371 static bool heap_grow(size_t size)
00372 {
00373         if (size == 0)
00374                 return true;
00375         
00376         /* First try to enlarge some existing area */
00377         for (heap_area_t *area = first_heap_area; area != NULL;
00378             area = area->next) {
00379                 if (area_grow(area, size))
00380                         return true;
00381         }
00382         
00383         /* Eventually try to create a new area */
00384         return area_create(AREA_OVERHEAD(size));
00385 }
00386 
00395 static void heap_shrink(heap_area_t *area)
00396 {
00397         area_check(area);
00398         
00399         heap_block_foot_t *last_foot =
00400             (heap_block_foot_t *) AREA_LAST_BLOCK_FOOT(area);
00401         heap_block_head_t *last_head = BLOCK_HEAD(last_foot);
00402         
00403         block_check((void *) last_head);
00404         malloc_assert(last_head->area == area);
00405         
00406         if (last_head->free) {
00407                 /*
00408                  * The last block of the heap area is
00409                  * unused. The area might be potentially
00410                  * shrunk.
00411                  */
00412                 
00413                 heap_block_head_t *first_head =
00414                     (heap_block_head_t *) AREA_FIRST_BLOCK_HEAD(area);
00415                 
00416                 block_check((void *) first_head);
00417                 malloc_assert(first_head->area == area);
00418                 
00419                 size_t shrink_size = ALIGN_DOWN(last_head->size, PAGE_SIZE);
00420                 
00421                 if (first_head == last_head) {
00422                         /*
00423                          * The entire heap area consists of a single
00424                          * free heap block. This means we can get rid
00425                          * of it entirely.
00426                          */
00427                         
00428                         heap_area_t *prev = area->prev;
00429                         heap_area_t *next = area->next;
00430                         
00431                         if (prev != NULL) {
00432                                 area_check(prev);
00433                                 prev->next = next;
00434                         } else
00435                                 first_heap_area = next;
00436                         
00437                         if (next != NULL) {
00438                                 area_check(next);
00439                                 next->prev = prev;
00440                         } else
00441                                 last_heap_area = prev;
00442                         
00443                         as_area_destroy(area->start);
00444                 } else if (shrink_size >= SHRINK_GRANULARITY) {
00445                         /*
00446                          * Make sure that we always shrink the area
00447                          * by a multiple of page size and update
00448                          * the block layout accordingly.
00449                          */
00450                         
00451                         size_t asize = (size_t) (area->end - area->start) - shrink_size;
00452                         void *end = (void *) ((uintptr_t) area->start + asize);
00453                         
00454                         /* Resize the address space area */
00455                         int ret = as_area_resize(area->start, asize, 0);
00456                         if (ret != EOK)
00457                                 abort();
00458                         
00459                         /* Update heap area parameters */
00460                         area->end = end;
00461                         size_t excess = ((size_t) area->end) - ((size_t) last_head);
00462                         
00463                         if (excess > 0) {
00464                                 if (excess >= STRUCT_OVERHEAD) {
00465                                         /*
00466                                          * The previous block cannot be free and there
00467                                          * is enough free space left in the area to
00468                                          * create a new free block.
00469                                          */
00470                                         block_init((void *) last_head, excess, true, area);
00471                                 } else {
00472                                         /*
00473                                          * The excess is small. Therefore just enlarge
00474                                          * the previous block.
00475                                          */
00476                                         heap_block_foot_t *prev_foot = (heap_block_foot_t *)
00477                                             (((uintptr_t) last_head) - sizeof(heap_block_foot_t));
00478                                         heap_block_head_t *prev_head = BLOCK_HEAD(prev_foot);
00479                                         
00480                                         block_check((void *) prev_head);
00481                                         
00482                                         block_init(prev_head, prev_head->size + excess,
00483                                             prev_head->free, area);
00484                                 }
00485                         }
00486                 }
00487         }
00488         
00489         next_fit = NULL;
00490 }
00491 
00499 void __malloc_init(void)
00500 {
00501         if (!area_create(PAGE_SIZE))
00502                 abort();
00503 }
00504 
00514 static void split_mark(heap_block_head_t *cur, const size_t size)
00515 {
00516         malloc_assert(cur->size >= size);
00517         
00518         /* See if we should split the block. */
00519         size_t split_limit = GROSS_SIZE(size);
00520         
00521         if (cur->size > split_limit) {
00522                 /* Block big enough -> split. */
00523                 void *next = ((void *) cur) + size;
00524                 block_init(next, cur->size - size, true, cur->area);
00525                 block_init(cur, size, false, cur->area);
00526         } else {
00527                 /* Block too small -> use as is. */
00528                 cur->free = false;
00529         }
00530 }
00531 
00548 static void *malloc_area(heap_area_t *area, heap_block_head_t *first_block,
00549     heap_block_head_t *final_block, size_t real_size, size_t falign)
00550 {
00551         area_check((void *) area);
00552         malloc_assert((void *) first_block >= (void *) AREA_FIRST_BLOCK_HEAD(area));
00553         malloc_assert((void *) first_block < area->end);
00554         
00555         for (heap_block_head_t *cur = first_block; (void *) cur < area->end;
00556             cur = (heap_block_head_t *) (((void *) cur) + cur->size)) {
00557                 block_check(cur);
00558                 
00559                 /* Finish searching on the final block */
00560                 if ((final_block != NULL) && (cur == final_block))
00561                         break;
00562                 
00563                 /* Try to find a block that is free and large enough. */
00564                 if ((cur->free) && (cur->size >= real_size)) {
00565                         /*
00566                          * We have found a suitable block.
00567                          * Check for alignment properties.
00568                          */
00569                         void *addr = (void *)
00570                             ((uintptr_t) cur + sizeof(heap_block_head_t));
00571                         void *aligned = (void *)
00572                             ALIGN_UP((uintptr_t) addr, falign);
00573                         
00574                         if (addr == aligned) {
00575                                 /* Exact block start including alignment. */
00576                                 split_mark(cur, real_size);
00577                                 
00578                                 next_fit = cur;
00579                                 return addr;
00580                         } else {
00581                                 /* Block start has to be aligned */
00582                                 size_t excess = (size_t) (aligned - addr);
00583                                 
00584                                 if (cur->size >= real_size + excess) {
00585                                         /*
00586                                          * The current block is large enough to fit
00587                                          * data in (including alignment).
00588                                          */
00589                                         if ((void *) cur > (void *) AREA_FIRST_BLOCK_HEAD(area)) {
00590                                                 /*
00591                                                  * There is a block before the current block.
00592                                                  * This previous block can be enlarged to
00593                                                  * compensate for the alignment excess.
00594                                                  */
00595                                                 heap_block_foot_t *prev_foot = (heap_block_foot_t *)
00596                                                     ((void *) cur - sizeof(heap_block_foot_t));
00597                                                 
00598                                                 heap_block_head_t *prev_head = (heap_block_head_t *)
00599                                                     ((void *) cur - prev_foot->size);
00600                                                 
00601                                                 block_check(prev_head);
00602                                                 
00603                                                 size_t reduced_size = cur->size - excess;
00604                                                 heap_block_head_t *next_head = ((void *) cur) + excess;
00605                                                 
00606                                                 if ((!prev_head->free) &&
00607                                                     (excess >= STRUCT_OVERHEAD)) {
00608                                                         /*
00609                                                          * The previous block is not free and there
00610                                                          * is enough free space left to fill in
00611                                                          * a new free block between the previous
00612                                                          * and current block.
00613                                                          */
00614                                                         block_init(cur, excess, true, area);
00615                                                 } else {
00616                                                         /*
00617                                                          * The previous block is free (thus there
00618                                                          * is no need to induce additional
00619                                                          * fragmentation to the heap) or the
00620                                                          * excess is small. Therefore just enlarge
00621                                                          * the previous block.
00622                                                          */
00623                                                         block_init(prev_head, prev_head->size + excess,
00624                                                             prev_head->free, area);
00625                                                 }
00626                                                 
00627                                                 block_init(next_head, reduced_size, true, area);
00628                                                 split_mark(next_head, real_size);
00629                                                 
00630                                                 next_fit = next_head;
00631                                                 return aligned;
00632                                         } else {
00633                                                 /*
00634                                                  * The current block is the first block
00635                                                  * in the heap area. We have to make sure
00636                                                  * that the alignment excess is large enough
00637                                                  * to fit a new free block just before the
00638                                                  * current block.
00639                                                  */
00640                                                 while (excess < STRUCT_OVERHEAD) {
00641                                                         aligned += falign;
00642                                                         excess += falign;
00643                                                 }
00644                                                 
00645                                                 /* Check for current block size again */
00646                                                 if (cur->size >= real_size + excess) {
00647                                                         size_t reduced_size = cur->size - excess;
00648                                                         cur = (heap_block_head_t *)
00649                                                             (AREA_FIRST_BLOCK_HEAD(area) + excess);
00650                                                         
00651                                                         block_init((void *) AREA_FIRST_BLOCK_HEAD(area),
00652                                                             excess, true, area);
00653                                                         block_init(cur, reduced_size, true, area);
00654                                                         split_mark(cur, real_size);
00655                                                         
00656                                                         next_fit = cur;
00657                                                         return aligned;
00658                                                 }
00659                                         }
00660                                 }
00661                         }
00662                 }
00663         }
00664         
00665         return NULL;
00666 }
00667 
00678 static void *malloc_internal(const size_t size, const size_t align)
00679 {
00680         malloc_assert(first_heap_area != NULL);
00681         
00682         if (align == 0)
00683                 return NULL;
00684         
00685         size_t falign = lcm(align, BASE_ALIGN);
00686         size_t real_size = GROSS_SIZE(ALIGN_UP(size, falign));
00687         
00688         bool retry = false;
00689         heap_block_head_t *split;
00690         
00691 loop:
00692         
00693         /* Try the next fit approach */
00694         split = next_fit;
00695         
00696         if (split != NULL) {
00697                 void *addr = malloc_area(split->area, split, NULL, real_size,
00698                     falign);
00699                 
00700                 if (addr != NULL)
00701                         return addr;
00702         }
00703         
00704         /* Search the entire heap */
00705         for (heap_area_t *area = first_heap_area; area != NULL;
00706             area = area->next) {
00707                 heap_block_head_t *first = (heap_block_head_t *)
00708                     AREA_FIRST_BLOCK_HEAD(area);
00709                 
00710                 void *addr = malloc_area(area, first, split, real_size,
00711                     falign);
00712                 
00713                 if (addr != NULL)
00714                         return addr;
00715         }
00716         
00717         if (!retry) {
00718                 /* Try to grow the heap space */
00719                 if (heap_grow(real_size)) {
00720                         retry = true;
00721                         goto loop;
00722                 }
00723         }
00724         
00725         return NULL;
00726 }
00727 
00736 void *calloc(const size_t nmemb, const size_t size)
00737 {
00738         void *block = malloc(nmemb * size);
00739         if (block == NULL)
00740                 return NULL;
00741         
00742         memset(block, 0, nmemb * size);
00743         return block;
00744 }
00745 
00753 void *malloc(const size_t size)
00754 {
00755         futex_down(&malloc_futex);
00756         void *block = malloc_internal(size, BASE_ALIGN);
00757         futex_up(&malloc_futex);
00758         
00759         return block;
00760 }
00761 
00770 void *memalign(const size_t align, const size_t size)
00771 {
00772         if (align == 0)
00773                 return NULL;
00774         
00775         size_t palign =
00776             1 << (fnzb(max(sizeof(void *), align) - 1) + 1);
00777         
00778         futex_down(&malloc_futex);
00779         void *block = malloc_internal(size, palign);
00780         futex_up(&malloc_futex);
00781         
00782         return block;
00783 }
00784 
00793 void *realloc(const void *addr, const size_t size)
00794 {
00795         if (addr == NULL)
00796                 return malloc(size);
00797         
00798         futex_down(&malloc_futex);
00799         
00800         /* Calculate the position of the header. */
00801         heap_block_head_t *head =
00802             (heap_block_head_t *) (addr - sizeof(heap_block_head_t));
00803         
00804         block_check(head);
00805         malloc_assert(!head->free);
00806         
00807         heap_area_t *area = head->area;
00808         
00809         area_check(area);
00810         malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area));
00811         malloc_assert((void *) head < area->end);
00812         
00813         void *ptr = NULL;
00814         bool reloc = false;
00815         size_t real_size = GROSS_SIZE(ALIGN_UP(size, BASE_ALIGN));
00816         size_t orig_size = head->size;
00817         
00818         if (orig_size > real_size) {
00819                 /* Shrink */
00820                 if (orig_size - real_size >= STRUCT_OVERHEAD) {
00821                         /*
00822                          * Split the original block to a full block
00823                          * and a trailing free block.
00824                          */
00825                         block_init((void *) head, real_size, false, area);
00826                         block_init((void *) head + real_size,
00827                             orig_size - real_size, true, area);
00828                         heap_shrink(area);
00829                 }
00830                 
00831                 ptr = ((void *) head) + sizeof(heap_block_head_t);
00832         } else {
00833                 /*
00834                  * Look at the next block. If it is free and the size is
00835                  * sufficient then merge the two. Otherwise just allocate
00836                  * a new block, copy the original data into it and
00837                  * free the original block.
00838                  */
00839                 heap_block_head_t *next_head =
00840                     (heap_block_head_t *) (((void *) head) + head->size);
00841                 
00842                 if (((void *) next_head < area->end) &&
00843                     (head->size + next_head->size >= real_size) &&
00844                     (next_head->free)) {
00845                         block_check(next_head);
00846                         block_init(head, head->size + next_head->size, false, area);
00847                         split_mark(head, real_size);
00848                         
00849                         ptr = ((void *) head) + sizeof(heap_block_head_t);
00850                         next_fit = NULL;
00851                 } else
00852                         reloc = true;
00853         }
00854         
00855         futex_up(&malloc_futex);
00856         
00857         if (reloc) {
00858                 ptr = malloc(size);
00859                 if (ptr != NULL) {
00860                         memcpy(ptr, addr, NET_SIZE(orig_size));
00861                         free(addr);
00862                 }
00863         }
00864         
00865         return ptr;
00866 }
00867 
00873 void free(const void *addr)
00874 {
00875         futex_down(&malloc_futex);
00876         
00877         /* Calculate the position of the header. */
00878         heap_block_head_t *head
00879             = (heap_block_head_t *) (addr - sizeof(heap_block_head_t));
00880         
00881         block_check(head);
00882         malloc_assert(!head->free);
00883         
00884         heap_area_t *area = head->area;
00885         
00886         area_check(area);
00887         malloc_assert((void *) head >= (void *) AREA_FIRST_BLOCK_HEAD(area));
00888         malloc_assert((void *) head < area->end);
00889         
00890         /* Mark the block itself as free. */
00891         head->free = true;
00892         
00893         /* Look at the next block. If it is free, merge the two. */
00894         heap_block_head_t *next_head
00895             = (heap_block_head_t *) (((void *) head) + head->size);
00896         
00897         if ((void *) next_head < area->end) {
00898                 block_check(next_head);
00899                 if (next_head->free)
00900                         block_init(head, head->size + next_head->size, true, area);
00901         }
00902         
00903         /* Look at the previous block. If it is free, merge the two. */
00904         if ((void *) head > (void *) AREA_FIRST_BLOCK_HEAD(area)) {
00905                 heap_block_foot_t *prev_foot =
00906                     (heap_block_foot_t *) (((void *) head) - sizeof(heap_block_foot_t));
00907                 
00908                 heap_block_head_t *prev_head =
00909                     (heap_block_head_t *) (((void *) head) - prev_foot->size);
00910                 
00911                 block_check(prev_head);
00912                 
00913                 if (prev_head->free)
00914                         block_init(prev_head, prev_head->size + head->size, true,
00915                             area);
00916         }
00917         
00918         heap_shrink(area);
00919         
00920         futex_up(&malloc_futex);
00921 }
00922 
00923 void *heap_check(void)
00924 {
00925         futex_down(&malloc_futex);
00926         
00927         if (first_heap_area == NULL) {
00928                 futex_up(&malloc_futex);
00929                 return (void *) -1;
00930         }
00931         
00932         /* Walk all heap areas */
00933         for (heap_area_t *area = first_heap_area; area != NULL;
00934             area = area->next) {
00935                 
00936                 /* Check heap area consistency */
00937                 if ((area->magic != HEAP_AREA_MAGIC) ||
00938                     ((void *) area != area->start) ||
00939                     (area->start >= area->end) ||
00940                     (((uintptr_t) area->start % PAGE_SIZE) != 0) ||
00941                     (((uintptr_t) area->end % PAGE_SIZE) != 0)) {
00942                         futex_up(&malloc_futex);
00943                         return (void *) area;
00944                 }
00945                 
00946                 /* Walk all heap blocks */
00947                 for (heap_block_head_t *head = (heap_block_head_t *)
00948                     AREA_FIRST_BLOCK_HEAD(area); (void *) head < area->end;
00949                     head = (heap_block_head_t *) (((void *) head) + head->size)) {
00950                         
00951                         /* Check heap block consistency */
00952                         if (head->magic != HEAP_BLOCK_HEAD_MAGIC) {
00953                                 futex_up(&malloc_futex);
00954                                 return (void *) head;
00955                         }
00956                         
00957                         heap_block_foot_t *foot = BLOCK_FOOT(head);
00958                         
00959                         if ((foot->magic != HEAP_BLOCK_FOOT_MAGIC) ||
00960                             (head->size != foot->size)) {
00961                                 futex_up(&malloc_futex);
00962                                 return (void *) foot;
00963                         }
00964                 }
00965         }
00966         
00967         futex_up(&malloc_futex);
00968         
00969         return NULL;
00970 }
00971 

Generated on Thu Jun 2 07:45:46 2011 for HelenOS/USB by  doxygen 1.4.7