diff options
Diffstat (limited to 'libc/malloc/arena.c')
-rw-r--r-- | libc/malloc/arena.c | 43 |
1 files changed, 35 insertions, 8 deletions
diff --git a/libc/malloc/arena.c b/libc/malloc/arena.c index 9e5e33202..b209e3b7c 100644 --- a/libc/malloc/arena.c +++ b/libc/malloc/arena.c @@ -1,6 +1,5 @@ /* Malloc implementation for multiple threads without lock contention. - Copyright (C) 2001,2002,2003,2004,2005,2006,2007,2009,2010,2011,2012 - Free Software Foundation, Inc. + Copyright (C) 2001-2012 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Wolfram Gloger <wg@malloc.de>, 2001. @@ -20,6 +19,9 @@ #include <stdbool.h> +/* Get the implementation for check_may_shrink_heap. */ +#include <malloc-sysdep.h> + /* Compile-time constants. */ #define HEAP_MIN_SIZE (32*1024) @@ -622,9 +624,9 @@ shrink_heap(heap_info *h, long diff) new_size = (long)h->size - diff; if(new_size < (long)sizeof(*h)) return -1; - /* Try to re-map the extra heap space freshly to save memory, and - make it inaccessible. */ - if (__builtin_expect (__libc_enable_secure, 0)) + /* Try to re-map the extra heap space freshly to save memory, and make it + inaccessible. See malloc-sysdep.h to know when this is true. */ + if (__builtin_expect (check_may_shrink_heap (), 0)) { if((char *)MMAP((char *)h + new_size, diff, PROT_NONE, MAP_FIXED) == (char *) MAP_FAILED) @@ -656,15 +658,19 @@ heap_trim(heap_info *heap, size_t pad) unsigned long pagesz = GLRO(dl_pagesize); mchunkptr top_chunk = top(ar_ptr), p, bck, fwd; heap_info *prev_heap; - long new_size, top_size, extra; + long new_size, top_size, extra, prev_size, misalign; /* Can this heap go away completely? */ while(top_chunk == chunk_at_offset(heap, sizeof(*heap))) { prev_heap = heap->prev; - p = chunk_at_offset(prev_heap, prev_heap->size - (MINSIZE-2*SIZE_SZ)); + prev_size = prev_heap->size - (MINSIZE-2*SIZE_SZ); + p = chunk_at_offset(prev_heap, prev_size); + /* fencepost must be properly aligned. */ + misalign = ((long) p) & MALLOC_ALIGN_MASK; + p = chunk_at_offset(prev_heap, prev_size - misalign); assert(p->size == (0|PREV_INUSE)); /* must be fencepost */ p = prev_chunk(p); - new_size = chunksize(p) + (MINSIZE-2*SIZE_SZ); + new_size = chunksize(p) + (MINSIZE-2*SIZE_SZ) + misalign; assert(new_size>0 && new_size<(long)(2*MINSIZE)); if(!prev_inuse(p)) new_size += p->prev_size; @@ -918,6 +924,27 @@ arena_get2(mstate a_tsd, size_t size, mstate avoid_arena) return a; } +/* If we don't have the main arena, then maybe the failure is due to running + out of mmapped areas, so we can try allocating on the main arena. + Otherwise, it is likely that sbrk() has failed and there is still a chance + to mmap(), so try one of the other arenas. */ +static mstate +arena_get_retry (mstate ar_ptr, size_t bytes) +{ + if(ar_ptr != &main_arena) { + (void)mutex_unlock(&ar_ptr->mutex); + ar_ptr = &main_arena; + (void)mutex_lock(&ar_ptr->mutex); + } else { + /* Grab ar_ptr->next prior to releasing its lock. */ + mstate prev = ar_ptr->next ? ar_ptr : 0; + (void)mutex_unlock(&ar_ptr->mutex); + ar_ptr = arena_get2(prev, bytes, ar_ptr); + } + + return ar_ptr; +} + #ifdef PER_THREAD static void __attribute__ ((section ("__libc_thread_freeres_fn"))) arena_thread_freeres (void) |