diff options
author | joseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d> | 2008-02-20 12:48:46 +0000 |
---|---|---|
committer | joseph <joseph@7b3dc134-2b1b-0410-93df-9e9f96275f8d> | 2008-02-20 12:48:46 +0000 |
commit | 8c5ab5ff18f334d83e82d40ce5a15294288d82bb (patch) | |
tree | 7595ae8eb0d289b345daf994d3a4dc8b265eeba6 /libc/malloc | |
parent | 1ee006bef1ce679d91782a9beb3c983cec91cbbe (diff) | |
download | eglibc2-8c5ab5ff18f334d83e82d40ce5a15294288d82bb.tar.gz |
Merge changes between r4014 and r5247 from /fsf/trunk.
git-svn-id: svn://svn.eglibc.org/trunk@5248 7b3dc134-2b1b-0410-93df-9e9f96275f8d
Diffstat (limited to 'libc/malloc')
-rw-r--r-- | libc/malloc/Makefile | 4 | ||||
-rw-r--r-- | libc/malloc/arena.c | 80 | ||||
-rw-r--r-- | libc/malloc/malloc.c | 114 | ||||
-rwxr-xr-x | libc/malloc/memusage.sh | 4 | ||||
-rw-r--r-- | libc/malloc/mtrace.pl | 4 | ||||
-rw-r--r-- | libc/malloc/tst-trim1.c | 56 |
6 files changed, 195 insertions, 67 deletions
diff --git a/libc/malloc/Makefile b/libc/malloc/Makefile index 6df857d4c..da72d3b33 100644 --- a/libc/malloc/Makefile +++ b/libc/malloc/Makefile @@ -1,4 +1,4 @@ -# Copyright (C) 1991-1999, 2000, 2001, 2002, 2003, 2005, 2006 +# Copyright (C) 1991-1999, 2000, 2001, 2002, 2003, 2005, 2006, 2007 # Free Software Foundation, Inc. # This file is part of the GNU C Library. @@ -27,7 +27,7 @@ all: dist-headers := malloc.h headers := $(dist-headers) obstack.h mcheck.h tests := mallocbug tst-malloc tst-valloc tst-calloc tst-obstack \ - tst-mallocstate tst-mcheck tst-mallocfork + tst-mallocstate tst-mcheck tst-mallocfork tst-trim1 test-srcs = tst-mtrace distribute = thread-m.h mtrace.pl mcheck-init.c stackinfo.h memusage.h \ diff --git a/libc/malloc/arena.c b/libc/malloc/arena.c index 4cbb4dc30..9932ee049 100644 --- a/libc/malloc/arena.c +++ b/libc/malloc/arena.c @@ -704,8 +704,8 @@ new_heap(size, top_pad) size_t size, top_pad; return h; } -/* Grow or shrink a heap. size is automatically rounded up to a - multiple of the page size if it is positive. */ +/* Grow a heap. size is automatically rounded up to a + multiple of the page size. */ static int #if __STD_C @@ -717,41 +717,55 @@ grow_heap(h, diff) heap_info *h; long diff; size_t page_mask = malloc_getpagesize - 1; long new_size; - if(diff >= 0) { - diff = (diff + page_mask) & ~page_mask; - new_size = (long)h->size + diff; - if((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE) - return -1; - if((unsigned long) new_size > h->mprotect_size) { - if (mprotect((char *)h + h->mprotect_size, - (unsigned long) new_size - h->mprotect_size, - PROT_READ|PROT_WRITE) != 0) - return -2; - h->mprotect_size = new_size; - } - } else { - 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. */ + diff = (diff + page_mask) & ~page_mask; + new_size = (long)h->size + diff; + if((unsigned long) new_size > (unsigned long) HEAP_MAX_SIZE) + return -1; + if((unsigned long) new_size > h->mprotect_size) { + if (mprotect((char *)h + h->mprotect_size, + (unsigned long) new_size - h->mprotect_size, + PROT_READ|PROT_WRITE) != 0) + return -2; + h->mprotect_size = new_size; + } + + h->size = new_size; + return 0; +} + +/* Shrink a heap. */ + +static int +#if __STD_C +shrink_heap(heap_info *h, long diff) +#else +shrink_heap(h, diff) heap_info *h; long diff; +#endif +{ + long new_size; + + 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. */ #ifdef _LIBC - if (__builtin_expect (__libc_enable_secure, 0)) + if (__builtin_expect (__libc_enable_secure, 0)) #else - if (1) + if (1) #endif - { - if((char *)MMAP((char *)h + new_size, -diff, PROT_NONE, - MAP_PRIVATE|MAP_FIXED) == (char *) MAP_FAILED) - return -2; - h->mprotect_size = new_size; - } + { + if((char *)MMAP((char *)h + new_size, diff, PROT_NONE, + MAP_PRIVATE|MAP_FIXED) == (char *) MAP_FAILED) + return -2; + h->mprotect_size = new_size; + } #ifdef _LIBC - else - madvise ((char *)h + new_size, -diff, MADV_DONTNEED); + else + madvise ((char *)h + new_size, diff, MADV_DONTNEED); #endif - /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/ - } + /*fprintf(stderr, "shrink %p %08lx\n", h, new_size);*/ + h->size = new_size; return 0; } @@ -811,7 +825,7 @@ heap_trim(heap, pad) heap_info *heap; size_t pad; if(extra < (long)pagesz) return 0; /* Try to shrink. */ - if(grow_heap(heap, -extra) != 0) + if(shrink_heap(heap, extra) != 0) return 0; ar_ptr->system_mem -= extra; arena_mem -= extra; diff --git a/libc/malloc/malloc.c b/libc/malloc/malloc.c index 39d5b3fa5..e00eb0f4e 100644 --- a/libc/malloc/malloc.c +++ b/libc/malloc/malloc.c @@ -1,5 +1,5 @@ /* Malloc implementation for multiple threads without lock contention. - Copyright (C) 1996-2006, 2007 Free Software Foundation, Inc. + Copyright (C) 1996-2006, 2007, 2008 Free Software Foundation, Inc. This file is part of the GNU C Library. Contributed by Wolfram Gloger <wg@malloc.de> and Doug Lea <dl@cs.oswego.edu>, 2001. @@ -1592,7 +1592,7 @@ static Void_t* _int_pvalloc(mstate, size_t); static Void_t** _int_icalloc(mstate, size_t, size_t, Void_t**); static Void_t** _int_icomalloc(mstate, size_t, size_t*, Void_t**); #endif -static int mTRIm(size_t); +static int mTRIm(mstate, size_t); static size_t mUSABLe(Void_t*); static void mSTATs(void); static int mALLOPt(int, int); @@ -2739,8 +2739,6 @@ static void do_check_malloc_state(mstate av) mchunkptr p; mchunkptr q; mbinptr b; - unsigned int binbit; - int empty; unsigned int idx; INTERNAL_SIZE_T size; unsigned long total = 0; @@ -2810,8 +2808,8 @@ static void do_check_malloc_state(mstate av) /* binmap is accurate (except for bin 1 == unsorted_chunks) */ if (i >= 2) { - binbit = get_binmap(av,i); - empty = last(b) == b; + unsigned int binbit = get_binmap(av,i); + int empty = last(b) == b; if (!binbit) assert(empty); else if (!empty) @@ -3555,9 +3553,10 @@ public_mALLOc(size_t bytes) /* Maybe the failure is due to running out of mmapped areas. */ if(ar_ptr != &main_arena) { (void)mutex_unlock(&ar_ptr->mutex); - (void)mutex_lock(&main_arena.mutex); - victim = _int_malloc(&main_arena, bytes); - (void)mutex_unlock(&main_arena.mutex); + ar_ptr = &main_arena; + (void)mutex_lock(&ar_ptr->mutex); + victim = _int_malloc(ar_ptr, bytes); + (void)mutex_unlock(&ar_ptr->mutex); } else { #if USE_ARENAS /* ... or sbrk() has failed and there is still a chance to mmap() */ @@ -3762,24 +3761,28 @@ public_mEMALIGn(size_t alignment, size_t bytes) if(!ar_ptr) return 0; p = _int_memalign(ar_ptr, alignment, bytes); - (void)mutex_unlock(&ar_ptr->mutex); if(!p) { /* Maybe the failure is due to running out of mmapped areas. */ if(ar_ptr != &main_arena) { - (void)mutex_lock(&main_arena.mutex); - p = _int_memalign(&main_arena, alignment, bytes); - (void)mutex_unlock(&main_arena.mutex); + (void)mutex_unlock(&ar_ptr->mutex); + ar_ptr = &main_arena; + (void)mutex_lock(&ar_ptr->mutex); + p = _int_memalign(ar_ptr, alignment, bytes); + (void)mutex_unlock(&ar_ptr->mutex); } else { #if USE_ARENAS /* ... or sbrk() has failed and there is still a chance to mmap() */ - ar_ptr = arena_get2(ar_ptr->next ? ar_ptr : 0, bytes); + mstate prev = ar_ptr->next ? ar_ptr : 0; + (void)mutex_unlock(&ar_ptr->mutex); + ar_ptr = arena_get2(prev, bytes); if(ar_ptr) { p = _int_memalign(ar_ptr, alignment, bytes); (void)mutex_unlock(&ar_ptr->mutex); } #endif } - } + } else + (void)mutex_unlock(&ar_ptr->mutex); assert(!p || chunk_is_mmapped(mem2chunk(p)) || ar_ptr == arena_for_chunk(mem2chunk(p))); return p; @@ -3888,6 +3891,12 @@ public_cALLOc(size_t n, size_t elem_size) oldtopsize < mp_.sbrk_base + av->max_system_mem - (char *)oldtop) oldtopsize = (mp_.sbrk_base + av->max_system_mem - (char *)oldtop); #endif + if (av != &main_arena) + { + heap_info *heap = heap_for_ptr (oldtop); + if (oldtopsize < (char *) heap + heap->mprotect_size - (char *) oldtop) + oldtopsize = (char *) heap + heap->mprotect_size - (char *) oldtop; + } #endif mem = _int_malloc(av, sz); @@ -4013,13 +4022,22 @@ public_cFREe(Void_t* m) int public_mTRIm(size_t s) { - int result; + int result = 0; if(__malloc_initialized < 0) ptmalloc_init (); - (void)mutex_lock(&main_arena.mutex); - result = mTRIm(s); - (void)mutex_unlock(&main_arena.mutex); + + mstate ar_ptr = &main_arena; + do + { + (void) mutex_lock (&ar_ptr->mutex); + result |= mTRIm (ar_ptr, s); + (void) mutex_unlock (&ar_ptr->mutex); + + ar_ptr = ar_ptr->next; + } + while (ar_ptr != &main_arena); + return result; } @@ -4475,7 +4493,7 @@ _int_malloc(mstate av, size_t bytes) We require that av->top always exists (i.e., has size >= MINSIZE) after initialization, so if it would otherwise be - exhuasted by current request, it is replenished. (The main + exhausted by current request, it is replenished. (The main reason for ensuring it exists is that we may need MINSIZE space to put in fenceposts in sysmalloc.) */ @@ -4515,7 +4533,7 @@ _int_malloc(mstate av, size_t bytes) */ else { void *p = sYSMALLOc(nb, av); - if (__builtin_expect (perturb_byte, 0)) + if (p != NULL && __builtin_expect (perturb_byte, 0)) alloc_perturb (p, bytes); return p; } @@ -5489,20 +5507,60 @@ _int_pvalloc(av, bytes) mstate av, size_t bytes; */ #if __STD_C -int mTRIm(size_t pad) +static int mTRIm(mstate av, size_t pad) #else -int mTRIm(pad) size_t pad; +static int mTRIm(av, pad) mstate av; size_t pad; #endif { - mstate av = &main_arena; /* already locked */ - /* Ensure initialization/consolidation */ - malloc_consolidate(av); + malloc_consolidate (av); + + const size_t ps = mp_.pagesize; + int psindex = bin_index (ps); + const size_t psm1 = ps - 1; + + int result = 0; + for (int i = 1; i < NBINS; ++i) + if (i == 1 || i >= psindex) + { + mbinptr bin = bin_at (av, i); + + for (mchunkptr p = last (bin); p != bin; p = p->bk) + { + INTERNAL_SIZE_T size = chunksize (p); + + if (size > psm1 + sizeof (struct malloc_chunk)) + { + /* See whether the chunk contains at least one unused page. */ + char *paligned_mem = (char *) (((uintptr_t) p + + sizeof (struct malloc_chunk) + + psm1) & ~psm1); + + assert ((char *) chunk2mem (p) + 4 * SIZE_SZ <= paligned_mem); + assert ((char *) p + size > paligned_mem); + + /* This is the size we could potentially free. */ + size -= paligned_mem - (char *) p; + + if (size > psm1) + { +#ifdef MALLOC_DEBUG + /* When debugging we simulate destroying the memory + content. */ + memset (paligned_mem, 0x89, size & ~psm1); +#endif + madvise (paligned_mem, size & ~psm1, MADV_DONTNEED); + + result = 1; + } + } + } + } #ifndef MORECORE_CANNOT_TRIM - return sYSTRIm(pad, av); + return result | (av == &main_arena ? sYSTRIm (pad, av) : 0); #else - return 0; + return result; #endif } diff --git a/libc/malloc/memusage.sh b/libc/malloc/memusage.sh index eace785cf..c4e189a83 100755 --- a/libc/malloc/memusage.sh +++ b/libc/malloc/memusage.sh @@ -1,5 +1,5 @@ #! @BASH@ -# Copyright (C) 1999-2004, 2005, 2006, 2007 Free Software Foundation, Inc. +# Copyright (C) 1999-2007, 2008 Free Software Foundation, Inc. # This file is part of the GNU C Library. # Contributed by Ulrich Drepper <drepper@gnu.org>, 1999. @@ -71,7 +71,7 @@ do_version() { printf $"Copyright (C) %s Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. -" "2007" +" "2008" printf $"Written by %s. " "Ulrich Drepper" exit 0 diff --git a/libc/malloc/mtrace.pl b/libc/malloc/mtrace.pl index 280b469d9..5e5e1ea0a 100644 --- a/libc/malloc/mtrace.pl +++ b/libc/malloc/mtrace.pl @@ -1,7 +1,7 @@ #! @PERL@ eval "exec @PERL@ -S $0 $*" if 0; -# Copyright (C) 1997-2004, 2005, 2006, 2007 Free Software Foundation, Inc. +# Copyright (C) 1997-2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. # This file is part of the GNU C Library. # Contributed by Ulrich Drepper <drepper@gnu.org>, 1997. # Based on the mtrace.awk script. @@ -45,7 +45,7 @@ arglist: while (@ARGV) { $ARGV[0] eq "--vers" || $ARGV[0] eq "--versi" || $ARGV[0] eq "--versio" || $ARGV[0] eq "--version") { print "mtrace (GNU $PACKAGE) $VERSION\n"; - print "Copyright (C) 2007 Free Software Foundation, Inc.\n"; + print "Copyright (C) 2008 Free Software Foundation, Inc.\n"; print "This is free software; see the source for copying conditions. There is NO\n"; print "warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"; print "Written by Ulrich Drepper <drepper\@gnu.org>\n"; diff --git a/libc/malloc/tst-trim1.c b/libc/malloc/tst-trim1.c new file mode 100644 index 000000000..310707e0e --- /dev/null +++ b/libc/malloc/tst-trim1.c @@ -0,0 +1,56 @@ +#include <malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define N 10000 + +static void *arr[N]; + +static int +do_test (void) +{ + for (int i = 0; i < N; ++i) + { + size_t size = random () % 16384; + + if ((arr[i] = malloc (size)) == NULL) + { + nomem: + puts ("not enough memory"); + return 0; + } + + memset (arr[i], size, size); + } + + void *p = malloc (256); + if (p == NULL) + goto nomem; + memset (p, 1, 256); + + puts ("=================================================================="); + + for (int i = 0; i < N; ++i) + if (i % 13 != 0) + free (arr[i]); + + puts ("=================================================================="); + + malloc_trim (0); + + puts ("=================================================================="); + + p = malloc (30000); + if (p == NULL) + goto nomem; + + memset (p, 2, 30000); + + malloc_trim (0); + + return 0; +} + +#define TEST_FUNCTION do_test () +#include "../test-skeleton.c" |