summaryrefslogtreecommitdiff
path: root/libc/malloc/arena.c
diff options
context:
space:
mode:
Diffstat (limited to 'libc/malloc/arena.c')
-rw-r--r--libc/malloc/arena.c43
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)