Ignore:
File:
1 edited

Legend:

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

    r3e6a98c5 r5b46ec8  
    6767/** Heap shrink granularity
    6868 *
    69  * Try not to pump and stress the heap to much
     69 * Try not to pump and stress the heap too much
    7070 * by shrinking and enlarging it too often.
    71  * A heap area won't shrunk if it the released
     71 * A heap area won't shrink if the released
    7272 * free block is smaller than this constant.
    7373 *
     
    200200        do { \
    201201                if (!(expr)) {\
    202                         futex_up(&malloc_futex); \
     202                        heap_unlock(); \
    203203                        assert_abort(#expr, __FILE__, __LINE__); \
    204204                } \
     
    210210
    211211#endif /* NDEBUG */
     212
     213
     214#ifdef FUTEX_UPGRADABLE
     215/** True if the heap may be accessed from multiple threads. */
     216static bool multithreaded = false;
     217
     218/** Makes accesses to the heap thread safe. */
     219void malloc_enable_multithreaded(void)
     220{
     221        multithreaded = true;
     222}
     223
     224/** Serializes access to the heap from multiple threads. */
     225static inline void heap_lock(void)
     226{
     227        if (multithreaded) {
     228                futex_down(&malloc_futex);
     229        } else {
     230                /*
     231                 * Malloc never switches fibrils while the heap is locked.
     232                 * Similarly, it never creates new threads from within the
     233                 * locked region. Therefore, if there are no other threads
     234                 * except this one, the whole operation will complete without
     235                 * any interruptions.
     236                 */
     237        }
     238}
     239
     240/** Serializes access to the heap from multiple threads. */
     241static inline void heap_unlock(void)
     242{
     243        if (multithreaded) {
     244                futex_up(&malloc_futex);
     245        } else {
     246                /*
     247                 * Malloc never switches fibrils while the heap is locked.
     248                 * Similarly, it never creates new threads from within the
     249                 * locked region. Therefore, if there are no other threads
     250                 * except this one, the whole operation will complete without
     251                 * any interruptions.
     252                 */
     253        }
     254}
     255
     256#else
     257
     258/** Makes accesses to the heap thread safe. */
     259void malloc_enable_multithreaded(void)
     260{
     261        /* No-op. Already using thread-safe heap locking operations. */
     262}
     263
     264/** Serializes access to the heap from multiple threads. */
     265static inline void heap_lock(void)
     266{
     267        futex_down(&malloc_futex);
     268}
     269
     270/** Serializes access to the heap from multiple threads. */
     271static inline void heap_unlock(void)
     272{
     273        futex_up(&malloc_futex);
     274}
     275#endif
     276
    212277
    213278/** Initialize a heap block
     
    289354        size_t asize = ALIGN_UP(size, PAGE_SIZE);
    290355        void *astart = as_area_create(AS_AREA_ANY, asize,
    291             AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE);
     356            AS_AREA_WRITE | AS_AREA_READ | AS_AREA_CACHEABLE, AS_AREA_UNPAGED);
    292357        if (astart == AS_MAP_FAILED)
    293358                return false;
     
    785850void *malloc(const size_t size)
    786851{
    787         futex_down(&malloc_futex);
     852        heap_lock();
    788853        void *block = malloc_internal(size, BASE_ALIGN);
    789         futex_up(&malloc_futex);
    790        
     854        heap_unlock();
     855
    791856        return block;
    792857}
     
    807872        size_t palign =
    808873            1 << (fnzb(max(sizeof(void *), align) - 1) + 1);
    809        
    810         futex_down(&malloc_futex);
     874
     875        heap_lock();
    811876        void *block = malloc_internal(size, palign);
    812         futex_up(&malloc_futex);
    813        
     877        heap_unlock();
     878
    814879        return block;
    815880}
     
    828893                return malloc(size);
    829894       
    830         futex_down(&malloc_futex);
     895        heap_lock();
    831896       
    832897        /* Calculate the position of the header. */
     
    863928                ptr = ((void *) head) + sizeof(heap_block_head_t);
    864929        } else {
     930                heap_block_head_t *next_head =
     931                    (heap_block_head_t *) (((void *) head) + head->size);
     932                bool have_next = ((void *) next_head < area->end);
     933
     934                if (((void *) head) + real_size > area->end) {
     935                        /*
     936                         * The current area is too small to hold the resized
     937                         * block. Make sure there are no used blocks standing
     938                         * in our way and try to grow the area using real_size
     939                         * as a safe upper bound.
     940                         */
     941
     942                        bool have_next_next;
     943
     944                        if (have_next) {
     945                                have_next_next = (((void *) next_head) +
     946                                    next_head->size < area->end);
     947                        }
     948                        if (!have_next || (next_head->free && !have_next_next)) {
     949                                /*
     950                                 * There is no next block in this area or
     951                                 * it is a free block and there is no used
     952                                 * block following it. There can't be any
     953                                 * free block following it either as
     954                                 * two free blocks would be merged.
     955                                 */
     956                                (void) area_grow(area, real_size);
     957                        }
     958                }
     959               
    865960                /*
    866961                 * Look at the next block. If it is free and the size is
    867                  * sufficient then merge the two. Otherwise just allocate
    868                  * a new block, copy the original data into it and
    869                  * free the original block.
     962                 * sufficient then merge the two. Otherwise just allocate a new
     963                 * block, copy the original data into it and free the original
     964                 * block.
    870965                 */
    871                 heap_block_head_t *next_head =
    872                     (heap_block_head_t *) (((void *) head) + head->size);
    873                
    874                 if (((void *) next_head < area->end) &&
    875                     (head->size + next_head->size >= real_size) &&
    876                     (next_head->free)) {
     966
     967                if (have_next && (head->size + next_head->size >= real_size) &&
     968                    next_head->free) {
    877969                        block_check(next_head);
    878                         block_init(head, head->size + next_head->size, false, area);
     970                        block_init(head, head->size + next_head->size, false,
     971                            area);
    879972                        split_mark(head, real_size);
    880973                       
    881974                        ptr = ((void *) head) + sizeof(heap_block_head_t);
    882975                        next_fit = NULL;
    883                 } else
     976                } else {
    884977                        reloc = true;
    885         }
    886        
    887         futex_up(&malloc_futex);
     978                }
     979        }
     980       
     981        heap_unlock();
    888982       
    889983        if (reloc) {
     
    9081002                return;
    9091003       
    910         futex_down(&malloc_futex);
     1004        heap_lock();
    9111005       
    9121006        /* Calculate the position of the header. */
     
    9531047        heap_shrink(area);
    9541048       
    955         futex_up(&malloc_futex);
     1049        heap_unlock();
    9561050}
    9571051
    9581052void *heap_check(void)
    9591053{
    960         futex_down(&malloc_futex);
     1054        heap_lock();
    9611055       
    9621056        if (first_heap_area == NULL) {
    963                 futex_up(&malloc_futex);
     1057                heap_unlock();
    9641058                return (void *) -1;
    9651059        }
     
    9751069                    (((uintptr_t) area->start % PAGE_SIZE) != 0) ||
    9761070                    (((uintptr_t) area->end % PAGE_SIZE) != 0)) {
    977                         futex_up(&malloc_futex);
     1071                        heap_unlock();
    9781072                        return (void *) area;
    9791073                }
     
    9861080                        /* Check heap block consistency */
    9871081                        if (head->magic != HEAP_BLOCK_HEAD_MAGIC) {
    988                                 futex_up(&malloc_futex);
     1082                                heap_unlock();
    9891083                                return (void *) head;
    9901084                        }
     
    9941088                        if ((foot->magic != HEAP_BLOCK_FOOT_MAGIC) ||
    9951089                            (head->size != foot->size)) {
    996                                 futex_up(&malloc_futex);
     1090                                heap_unlock();
    9971091                                return (void *) foot;
    9981092                        }
     
    10001094        }
    10011095       
    1002         futex_up(&malloc_futex);
     1096        heap_unlock();
    10031097       
    10041098        return NULL;
Note: See TracChangeset for help on using the changeset viewer.