2 * libc/stdlib/malloc/free.c -- free 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>
23 free_to_heap (void *mem, struct heap *heap)
26 struct heap_free_area *fa;
28 /* Check for special cases. */
34 MALLOC_DEBUG (1, "free: 0x%lx (base = 0x%lx, total_size = %d)",
35 (long)mem, (long)MALLOC_BASE (mem), MALLOC_SIZE (mem));
37 size = MALLOC_SIZE (mem);
38 mem = MALLOC_BASE (mem);
42 /* Put MEM back in the heap, and get the free-area it was placed in. */
43 fa = __heap_free (heap, mem, size);
45 /* See if the free-area FA has grown big enough that it should be
47 if (HEAP_FREE_AREA_SIZE (fa) < MALLOC_UNMAP_THRESHOLD)
48 /* Nope, nothing left to do, just release the lock. */
51 /* Yup, try to unmap FA. */
53 unsigned long start = (unsigned long)HEAP_FREE_AREA_START (fa);
54 unsigned long end = (unsigned long)HEAP_FREE_AREA_END (fa);
55 #ifndef MALLOC_USE_SBRK
56 # ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
57 struct malloc_mmb *mmb, *prev_mmb;
58 unsigned long mmb_start, mmb_end;
59 # else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
60 unsigned long unmap_start, unmap_end;
61 # endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
62 #endif /* !MALLOC_USE_SBRK */
64 #ifdef MALLOC_USE_SBRK
65 /* Get the sbrk lock so that the two possible calls to sbrk below
66 are guaranteed to be contiguous. */
67 __malloc_lock_sbrk ();
68 /* When using sbrk, we only shrink the heap from the end. It would
69 be possible to allow _both_ -- shrinking via sbrk when possible,
70 and otherwise shrinking via munmap, but this results in holes in
71 memory that prevent the brk from every growing back down; since
72 we only ever grow the heap via sbrk, this tends to produce a
73 continuously growing brk (though the actual memory is unmapped),
74 which could eventually run out of address space. Note that
75 `sbrk(0)' shouldn't normally do a system call, so this test is
77 if ((void *)end != sbrk (0))
79 MALLOC_DEBUG (-1, "not unmapping: 0x%lx - 0x%lx (%ld bytes)",
80 start, end, end - start);
81 __malloc_unlock_sbrk ();
87 MALLOC_DEBUG (0, "unmapping: 0x%lx - 0x%lx (%ld bytes)",
88 start, end, end - start);
90 /* Remove FA from the heap. */
91 __heap_delete (heap, fa);
93 if (__heap_is_empty (heap))
94 /* We want to avoid the heap from losing all memory, so reserve
95 a bit. This test is only a heuristic -- the existance of
96 another free area, even if it's smaller than
97 MALLOC_MIN_SIZE, will cause us not to reserve anything. */
99 /* Put the reserved memory back in the heap; we asssume that
100 MALLOC_UNMAP_THRESHOLD is greater than MALLOC_MIN_SIZE, so
101 we use the latter unconditionally here. */
102 __heap_free (heap, (void *)start, MALLOC_MIN_SIZE);
103 start += MALLOC_MIN_SIZE;
106 #ifdef MALLOC_USE_SBRK
108 /* Release the heap lock; we're still holding the sbrk lock. */
109 __heap_unlock (heap);
112 /* Release the sbrk lock too; now we hold no locks. */
113 __malloc_unlock_sbrk ();
115 #else /* !MALLOC_USE_SBRK */
117 # ifdef __UCLIBC_UCLINUX_BROKEN_MUNMAP__
118 /* Using the uClinux broken munmap, we have to only munmap blocks
119 exactly as we got them from mmap, so scan through our list of
120 mmapped blocks, and return them in order. */
122 MALLOC_MMB_DEBUG (1, "walking mmb list for region 0x%x[%d]...",
126 mmb = __malloc_mmapped_blocks;
128 && ((mmb_end = (mmb_start = (unsigned long)mmb->mem) + mmb->size)
131 MALLOC_MMB_DEBUG (1, "considering mmb at 0x%x: 0x%x[%d]",
132 (unsigned)mmb, mmb_start, mmb_end - mmb_start);
134 if (mmb_start >= start
135 /* If the space between START and MMB_START is non-zero, but
136 too small to return to the heap, we can't unmap MMB. */
137 && (start == mmb_start
138 || mmb_start - start > HEAP_MIN_FREE_AREA_SIZE))
140 struct malloc_mmb *next_mmb = mmb->next;
142 if (mmb_end != end && mmb_end + HEAP_MIN_FREE_AREA_SIZE > end)
143 /* There's too little space left at the end to deallocate
144 this block, so give up. */
147 MALLOC_MMB_DEBUG (1, "unmapping mmb at 0x%x: 0x%x[%d]",
148 (unsigned)mmb, mmb_start, mmb_end - mmb_start);
150 if (mmb_start != start)
151 /* We're going to unmap a part of the heap that begins after
152 start, so put the intervening region back into the heap. */
154 MALLOC_MMB_DEBUG (0, "putting intervening region back into heap: 0x%x[%d]",
155 start, mmb_start - start);
156 __heap_free (heap, (void *)start, mmb_start - start);
159 MALLOC_MMB_DEBUG_INDENT (-1);
161 /* Unlink MMB from the list. */
163 prev_mmb->next = next_mmb;
165 __malloc_mmapped_blocks = next_mmb;
167 /* Start searching again from the end of this block. */
170 /* We have to unlock the heap before we recurse to free the mmb
171 descriptor, because we might be unmapping from the mmb
173 __heap_unlock (heap);
175 /* Release the descriptor block we used. */
176 free_to_heap (mmb, &__malloc_mmb_heap);
178 /* Do the actual munmap. */
179 munmap ((void *)mmb_start, mmb_end - mmb_start);
183 # ifdef __UCLIBC_HAS_THREADS__
184 /* In a multi-threaded program, it's possible that PREV_MMB has
185 been invalidated by another thread when we released the
186 heap lock to do the munmap system call, so just start over
187 from the beginning of the list. It sucks, but oh well;
188 it's probably not worth the bother to do better. */
190 mmb = __malloc_mmapped_blocks;
201 MALLOC_MMB_DEBUG_INDENT (-1);
205 /* Hmm, well there's something we couldn't unmap, so put it back
208 MALLOC_MMB_DEBUG (0, "putting tail region back into heap: 0x%x[%d]",
210 __heap_free (heap, (void *)start, end - start);
213 /* Finally release the lock for good. */
214 __heap_unlock (heap);
216 MALLOC_MMB_DEBUG_INDENT (-1);
218 # else /* !__UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
220 /* MEM/LEN may not be page-aligned, so we have to page-align them,
221 and return any left-over bits on the end to the heap. */
222 unmap_start = MALLOC_ROUND_UP_TO_PAGE_SIZE (start);
223 unmap_end = MALLOC_ROUND_DOWN_TO_PAGE_SIZE (end);
225 /* We have to be careful that any left-over bits are large enough to
226 return. Note that we _don't check_ to make sure there's room to
227 grow/shrink the start/end by another page, we just assume that
228 the unmap threshold is high enough so that this is always safe
229 (i.e., it should probably be at least 3 pages). */
230 if (unmap_start > start)
232 if (unmap_start - start < HEAP_MIN_FREE_AREA_SIZE)
233 unmap_start += MALLOC_PAGE_SIZE;
234 __heap_free (heap, (void *)start, unmap_start - start);
238 if (end - unmap_end < HEAP_MIN_FREE_AREA_SIZE)
239 unmap_end -= MALLOC_PAGE_SIZE;
240 __heap_free (heap, (void *)unmap_end, end - unmap_end);
243 /* Release the heap lock before we do the system call. */
244 __heap_unlock (heap);
246 if (unmap_end > unmap_start)
247 /* Finally, actually unmap the memory. */
248 munmap ((void *)unmap_start, unmap_end - unmap_start);
250 # endif /* __UCLIBC_UCLINUX_BROKEN_MUNMAP__ */
252 #endif /* MALLOC_USE_SBRK */
255 MALLOC_DEBUG_INDENT (-1);
261 free_to_heap (mem, &__malloc_heap);