2 * libc/stdlib/malloc/malloc.c -- malloc function
4 * Copyright (C) 2002,03 NEC Electronics Corporation
5 * Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
7 * This file is subject to the terms and conditions of the GNU Lesser
8 * General Public License. See the file COPYING.LIB in the main
9 * directory of this archive for more details.
11 * Written by Miles Bader <miles@gnu.org>
19 libc_hidden_proto(mmap)
20 libc_hidden_proto(sbrk)
26 /* The malloc heap. We provide a bit of initial static space so that
27 programs can do a little mallocing without mmaping in more space. */
28 HEAP_DECLARE_STATIC_FREE_AREA (initial_fa, 256);
29 struct heap __malloc_heap = HEAP_INIT_WITH_FA (initial_fa);
31 #if defined(MALLOC_USE_LOCKING) && defined(MALLOC_USE_SBRK)
32 /* A lock protecting our use of sbrk. */
33 malloc_mutex_t __malloc_sbrk_lock;
34 #endif /* MALLOC_USE_LOCKING && MALLOC_USE_SBRK */
37 #ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
38 /* A list of all malloc_mmb structures describing blocsk that
39 malloc has mmapped, ordered by the block address. */
40 struct malloc_mmb *__malloc_mmapped_blocks = 0;
42 /* A heap used for allocating malloc_mmb structures. We could allocate
43 them from the main heap, but that tends to cause heap fragmentation in
45 HEAP_DECLARE_STATIC_FREE_AREA (initial_mmb_fa, 48); /* enough for 3 mmbs */
46 struct heap __malloc_mmb_heap = HEAP_INIT_WITH_FA (initial_mmb_fa);
47 #endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
51 malloc_from_heap (size_t size, struct heap *heap)
55 MALLOC_DEBUG (1, "malloc: %d bytes", size);
57 /* Include extra space to record the size of the allocated block. */
58 size += MALLOC_HEADER_SIZE;
62 /* First try to get memory that's already in our heap. */
63 mem = __heap_alloc (heap, &size);
68 /* We couldn't allocate from the heap, so grab some more
69 from the system, add it to the heap, and try again. */
71 /* If we're trying to allocate a block bigger than the default
72 MALLOC_HEAP_EXTEND_SIZE, make sure we get enough to hold it. */
75 = (size < MALLOC_HEAP_EXTEND_SIZE
76 ? MALLOC_HEAP_EXTEND_SIZE
77 : MALLOC_ROUND_UP_TO_PAGE_SIZE (size));
79 /* Allocate the new heap block. */
80 #ifdef MALLOC_USE_SBRK
82 __malloc_lock_sbrk ();
84 /* Use sbrk we can, as it's faster than mmap, and guarantees
85 contiguous allocation. */
86 block = sbrk (block_size);
87 if (likely (block != (void *)-1))
89 /* Because sbrk can return results of arbitrary
90 alignment, align the result to a MALLOC_ALIGNMENT boundary. */
91 long aligned_block = MALLOC_ROUND_UP ((long)block, MALLOC_ALIGNMENT);
92 if (block != (void *)aligned_block)
93 /* Have to adjust. We should only have to actually do this
94 the first time (after which we will have aligned the brk
97 /* Move the brk to reflect the alignment; our next allocation
98 should start on exactly the right alignment. */
99 sbrk (aligned_block - (long)block);
100 block = (void *)aligned_block;
104 __malloc_unlock_sbrk ();
106 #else /* !MALLOC_USE_SBRK */
108 /* Otherwise, use mmap. */
109 #ifdef __ARCH_HAS_MMU__
110 block = mmap ((void *)0, block_size, PROT_READ | PROT_WRITE,
111 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);
113 block = mmap ((void *)0, block_size, PROT_READ | PROT_WRITE,
114 MAP_SHARED | MAP_ANONYMOUS, 0, 0);
117 #endif /* MALLOC_USE_SBRK */
119 if (likely (block != (void *)-1))
121 #if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)
122 struct malloc_mmb *mmb, *prev_mmb, *new_mmb;
125 MALLOC_DEBUG (1, "adding system memroy to heap: 0x%lx - 0x%lx (%d bytes)",
126 (long)block, (long)block + block_size, block_size);
128 /* Get back the heap lock. */
131 /* Put BLOCK into the heap. */
132 __heap_free (heap, block, block_size);
134 MALLOC_DEBUG_INDENT (-1);
136 /* Try again to allocate. */
137 mem = __heap_alloc (heap, &size);
139 __heap_unlock (heap);
141 #if !defined(MALLOC_USE_SBRK) && defined(__UCLIBC_UCLINUX_BROKEN_MUNMAP__)
142 /* Insert a record of BLOCK in sorted order into the
143 __malloc_mmapped_blocks list. */
145 for (prev_mmb = 0, mmb = __malloc_mmapped_blocks;
147 prev_mmb = mmb, mmb = mmb->next)
148 if (block < mmb->mem)
151 new_mmb = malloc_from_heap (sizeof *new_mmb, &__malloc_mmb_heap);
153 new_mmb->mem = block;
154 new_mmb->size = block_size;
157 prev_mmb->next = new_mmb;
159 __malloc_mmapped_blocks = new_mmb;
161 MALLOC_MMB_DEBUG (0, "new mmb at 0x%x: 0x%x[%d]",
163 (unsigned)new_mmb->mem, block_size);
164 #endif /* !MALLOC_USE_SBRK && __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
169 /* Record the size of the block and get the user address. */
171 mem = MALLOC_SETUP (mem, size);
173 MALLOC_DEBUG (-1, "malloc: returning 0x%lx (base:0x%lx, total_size:%ld)",
174 (long)mem, (long)MALLOC_BASE(mem), (long)MALLOC_SIZE(mem));
177 MALLOC_DEBUG (-1, "malloc: returning 0");
186 #ifdef MALLOC_DEBUGGING
187 static int debugging_initialized = 0;
188 if (! debugging_initialized)
190 debugging_initialized = 1;
191 __malloc_debug_init ();
194 __heap_check (&__malloc_heap, "malloc");
197 #ifdef __MALLOC_GLIBC_COMPAT__
198 if (unlikely (size == 0))
201 /* Some programs will call malloc (0). Lets be strict and return NULL */
202 if (unlikely (size == 0))
206 /* Check if they are doing something dumb like malloc(-1) */
207 if (unlikely(((unsigned long)size > (unsigned long)(MALLOC_HEADER_SIZE*-2))))
210 mem = malloc_from_heap (size, &__malloc_heap);
214 __set_errno (ENOMEM);