1 |
1325 |
phoenix |
/*
|
2 |
|
|
* libc/stdlib/malloc/heap.h -- heap allocator used for malloc
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 2002,03 NEC Electronics Corporation
|
5 |
|
|
* Copyright (C) 2002,03 Miles Bader <miles@gnu.org>
|
6 |
|
|
*
|
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.
|
10 |
|
|
*
|
11 |
|
|
* Written by Miles Bader <miles@gnu.org>
|
12 |
|
|
*/
|
13 |
|
|
|
14 |
|
|
#include <features.h>
|
15 |
|
|
|
16 |
|
|
|
17 |
|
|
/* On multi-threaded systems, the heap includes a lock. */
|
18 |
|
|
#ifdef __UCLIBC_HAS_THREADS__
|
19 |
|
|
# include <pthread.h>
|
20 |
|
|
# define HEAP_USE_LOCKING
|
21 |
|
|
#endif
|
22 |
|
|
|
23 |
|
|
|
24 |
|
|
/* The heap allocates in multiples of, and aligned to, HEAP_GRANULARITY.
|
25 |
|
|
HEAP_GRANULARITY must be a power of 2. Malloc depends on this being the
|
26 |
|
|
same as MALLOC_ALIGNMENT. */
|
27 |
|
|
#define HEAP_GRANULARITY_TYPE double
|
28 |
|
|
#define HEAP_GRANULARITY (sizeof (HEAP_GRANULARITY_TYPE))
|
29 |
|
|
|
30 |
|
|
|
31 |
|
|
/* A heap is a collection of memory blocks, from which smaller blocks
|
32 |
|
|
of memory can be allocated. */
|
33 |
|
|
struct heap
|
34 |
|
|
{
|
35 |
|
|
/* A list of memory in the heap available for allocation. */
|
36 |
|
|
struct heap_free_area *free_areas;
|
37 |
|
|
|
38 |
|
|
#ifdef HEAP_USE_LOCKING
|
39 |
|
|
/* A lock that can be used by callers to control access to the heap.
|
40 |
|
|
The heap code _does not_ use this lock, it's merely here for the
|
41 |
|
|
convenience of users! */
|
42 |
|
|
pthread_mutex_t lock;
|
43 |
|
|
#endif
|
44 |
|
|
};
|
45 |
|
|
|
46 |
|
|
/* The HEAP_INIT macro can be used as a static initializer for a heap
|
47 |
|
|
variable. The HEAP_INIT_WITH_FA variant is used to initialize a heap
|
48 |
|
|
with an initial static free-area; its argument FA should be declared
|
49 |
|
|
using HEAP_DECLARE_STATIC_FREE_AREA. */
|
50 |
|
|
#ifdef HEAP_USE_LOCKING
|
51 |
|
|
# define HEAP_INIT { 0, PTHREAD_MUTEX_INITIALIZER }
|
52 |
|
|
# define HEAP_INIT_WITH_FA(fa) { &fa._fa, PTHREAD_MUTEX_INITIALIZER }
|
53 |
|
|
#else
|
54 |
|
|
# define HEAP_INIT { 0 }
|
55 |
|
|
# define HEAP_INIT_WITH_FA(fa) { &fa._fa }
|
56 |
|
|
#endif
|
57 |
|
|
|
58 |
|
|
/* A free-list area `header'. These are actually stored at the _ends_ of
|
59 |
|
|
free areas (to make allocating from the beginning of the area simpler),
|
60 |
|
|
so one might call it a `footer'. */
|
61 |
|
|
struct heap_free_area
|
62 |
|
|
{
|
63 |
|
|
size_t size;
|
64 |
|
|
struct heap_free_area *next, *prev;
|
65 |
|
|
};
|
66 |
|
|
|
67 |
|
|
/* Return the address of the end of the frea area FA. */
|
68 |
|
|
#define HEAP_FREE_AREA_END(fa) ((void *)(fa + 1))
|
69 |
|
|
/* Return the address of the beginning of the frea area FA. FA is
|
70 |
|
|
evaulated multiple times. */
|
71 |
|
|
#define HEAP_FREE_AREA_START(fa) ((void *)((char *)(fa + 1) - (fa)->size))
|
72 |
|
|
/* Return the size of the frea area FA. */
|
73 |
|
|
#define HEAP_FREE_AREA_SIZE(fa) ((fa)->size)
|
74 |
|
|
|
75 |
|
|
/* This rather clumsy macro allows one to declare a static free-area for
|
76 |
|
|
passing to HEAP_INIT_WITH_FA initializer macro. This is only use for
|
77 |
|
|
which NAME is allowed. */
|
78 |
|
|
#define HEAP_DECLARE_STATIC_FREE_AREA(name, size) \
|
79 |
|
|
static struct \
|
80 |
|
|
{ \
|
81 |
|
|
HEAP_GRANULARITY_TYPE aligned_space; \
|
82 |
|
|
char space[HEAP_ADJUST_SIZE(size) \
|
83 |
|
|
- sizeof (struct heap_free_area) \
|
84 |
|
|
- HEAP_GRANULARITY]; \
|
85 |
|
|
struct heap_free_area _fa; \
|
86 |
|
|
} name = { (HEAP_GRANULARITY_TYPE)0, "", { HEAP_ADJUST_SIZE(size), 0, 0 } }
|
87 |
|
|
|
88 |
|
|
|
89 |
|
|
/* Rounds SZ up to be a multiple of HEAP_GRANULARITY. */
|
90 |
|
|
#define HEAP_ADJUST_SIZE(sz) \
|
91 |
|
|
(((sz) + HEAP_GRANULARITY - 1) & ~(HEAP_GRANULARITY - 1))
|
92 |
|
|
|
93 |
|
|
|
94 |
|
|
/* The minimum allocatable size. */
|
95 |
|
|
#define HEAP_MIN_SIZE HEAP_ADJUST_SIZE (sizeof (struct heap_free_area))
|
96 |
|
|
|
97 |
|
|
/* The minimum size of a free area; if allocating memory from a free-area
|
98 |
|
|
would make the free-area smaller than this, the allocation is simply
|
99 |
|
|
given the whole free-area instead. It must include at least enough room
|
100 |
|
|
to hold a struct heap_free_area, plus some extra to avoid excessive heap
|
101 |
|
|
fragmentation (thus increasing speed). This is only a heuristic -- it's
|
102 |
|
|
possible for smaller free-areas than this to exist (say, by realloc
|
103 |
|
|
returning the tail-end of a previous allocation), but __heap_alloc will
|
104 |
|
|
try to get rid of them when possible. */
|
105 |
|
|
#define HEAP_MIN_FREE_AREA_SIZE \
|
106 |
|
|
HEAP_ADJUST_SIZE (sizeof (struct heap_free_area) + 32)
|
107 |
|
|
|
108 |
|
|
|
109 |
|
|
/* branch-prediction macros; they may already be defined by libc. */
|
110 |
|
|
#ifndef likely
|
111 |
|
|
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 96)
|
112 |
|
|
#define likely(cond) __builtin_expect(!!(int)(cond), 1)
|
113 |
|
|
#define unlikely(cond) __builtin_expect((int)(cond), 0)
|
114 |
|
|
#else
|
115 |
|
|
#define likely(cond) (cond)
|
116 |
|
|
#define unlikely(cond) (cond)
|
117 |
|
|
#endif
|
118 |
|
|
#endif /* !likely */
|
119 |
|
|
|
120 |
|
|
|
121 |
|
|
/* Define HEAP_DEBUGGING to cause the heap routines to emit debugging info
|
122 |
|
|
to stderr when the variable __heap_debug is set to true. */
|
123 |
|
|
#ifdef HEAP_DEBUGGING
|
124 |
|
|
extern int __heap_debug;
|
125 |
|
|
#define HEAP_DEBUG(heap, str) (__heap_debug ? __heap_dump (heap, str) : 0)
|
126 |
|
|
#else
|
127 |
|
|
#define HEAP_DEBUG(heap, str) (void)0
|
128 |
|
|
#endif
|
129 |
|
|
|
130 |
|
|
/* Output a text representation of HEAP to stderr, labelling it with STR. */
|
131 |
|
|
extern void __heap_dump (struct heap *heap, const char *str);
|
132 |
|
|
|
133 |
|
|
/* Do some consistency checks on HEAP. If they fail, output an error
|
134 |
|
|
message to stderr, and exit. STR is printed with the failure message. */
|
135 |
|
|
extern void __heap_check (struct heap *heap, const char *str);
|
136 |
|
|
|
137 |
|
|
|
138 |
|
|
#ifdef HEAP_USE_LOCKING
|
139 |
|
|
# define __heap_lock(heap) __pthread_mutex_lock (&(heap)->lock)
|
140 |
|
|
# define __heap_unlock(heap) __pthread_mutex_unlock (&(heap)->lock)
|
141 |
|
|
#else /* !__UCLIBC_HAS_THREADS__ */
|
142 |
|
|
/* Without threads, mutex operations are a nop. */
|
143 |
|
|
# define __heap_lock(heap) (void)0
|
144 |
|
|
# define __heap_unlock(heap) (void)0
|
145 |
|
|
#endif /* HEAP_USE_LOCKING */
|
146 |
|
|
|
147 |
|
|
|
148 |
|
|
/* Delete the free-area FA from HEAP. */
|
149 |
|
|
static inline void
|
150 |
|
|
__heap_delete (struct heap *heap, struct heap_free_area *fa)
|
151 |
|
|
{
|
152 |
|
|
if (fa->next)
|
153 |
|
|
fa->next->prev = fa->prev;
|
154 |
|
|
if (fa->prev)
|
155 |
|
|
fa->prev->next = fa->next;
|
156 |
|
|
else
|
157 |
|
|
heap->free_areas = fa->next;
|
158 |
|
|
}
|
159 |
|
|
|
160 |
|
|
|
161 |
|
|
/* Link the free-area FA between the existing free-area's PREV and NEXT in
|
162 |
|
|
HEAP. PREV and NEXT may be 0; if PREV is 0, FA is installed as the
|
163 |
|
|
first free-area. */
|
164 |
|
|
static inline void
|
165 |
|
|
__heap_link_free_area (struct heap *heap, struct heap_free_area *fa,
|
166 |
|
|
struct heap_free_area *prev,
|
167 |
|
|
struct heap_free_area *next)
|
168 |
|
|
{
|
169 |
|
|
fa->next = next;
|
170 |
|
|
fa->prev = prev;
|
171 |
|
|
|
172 |
|
|
if (prev)
|
173 |
|
|
prev->next = fa;
|
174 |
|
|
else
|
175 |
|
|
heap->free_areas = fa;
|
176 |
|
|
if (next)
|
177 |
|
|
next->prev = fa;
|
178 |
|
|
}
|
179 |
|
|
|
180 |
|
|
/* Update the mutual links between the free-areas PREV and FA in HEAP.
|
181 |
|
|
PREV may be 0, in which case FA is installed as the first free-area (but
|
182 |
|
|
FA may not be 0). */
|
183 |
|
|
static inline void
|
184 |
|
|
__heap_link_free_area_after (struct heap *heap,
|
185 |
|
|
struct heap_free_area *fa,
|
186 |
|
|
struct heap_free_area *prev)
|
187 |
|
|
{
|
188 |
|
|
if (prev)
|
189 |
|
|
prev->next = fa;
|
190 |
|
|
else
|
191 |
|
|
heap->free_areas = fa;
|
192 |
|
|
fa->prev = prev;
|
193 |
|
|
}
|
194 |
|
|
|
195 |
|
|
/* Add a new free-area MEM, of length SIZE, in between the existing
|
196 |
|
|
free-area's PREV and NEXT in HEAP, and return a pointer to its header.
|
197 |
|
|
PREV and NEXT may be 0; if PREV is 0, MEM is installed as the first
|
198 |
|
|
free-area. */
|
199 |
|
|
static inline struct heap_free_area *
|
200 |
|
|
__heap_add_free_area (struct heap *heap, void *mem, size_t size,
|
201 |
|
|
struct heap_free_area *prev,
|
202 |
|
|
struct heap_free_area *next)
|
203 |
|
|
{
|
204 |
|
|
struct heap_free_area *fa = (struct heap_free_area *)
|
205 |
|
|
((char *)mem + size - sizeof (struct heap_free_area));
|
206 |
|
|
|
207 |
|
|
fa->size = size;
|
208 |
|
|
|
209 |
|
|
__heap_link_free_area (heap, fa, prev, next);
|
210 |
|
|
|
211 |
|
|
return fa;
|
212 |
|
|
}
|
213 |
|
|
|
214 |
|
|
|
215 |
|
|
/* Allocate SIZE bytes from the front of the free-area FA in HEAP, and
|
216 |
|
|
return the amount actually allocated (which may be more than SIZE). */
|
217 |
|
|
static inline size_t
|
218 |
|
|
__heap_free_area_alloc (struct heap *heap,
|
219 |
|
|
struct heap_free_area *fa, size_t size)
|
220 |
|
|
{
|
221 |
|
|
size_t fa_size = fa->size;
|
222 |
|
|
|
223 |
|
|
if (fa_size < size + HEAP_MIN_FREE_AREA_SIZE)
|
224 |
|
|
/* There's not enough room left over in FA after allocating the block, so
|
225 |
|
|
just use the whole thing, removing it from the list of free areas. */
|
226 |
|
|
{
|
227 |
|
|
__heap_delete (heap, fa);
|
228 |
|
|
/* Remember that we've alloced the whole area. */
|
229 |
|
|
size = fa_size;
|
230 |
|
|
}
|
231 |
|
|
else
|
232 |
|
|
/* Reduce size of FA to account for this allocation. */
|
233 |
|
|
fa->size = fa_size - size;
|
234 |
|
|
|
235 |
|
|
return size;
|
236 |
|
|
}
|
237 |
|
|
|
238 |
|
|
|
239 |
|
|
/* Allocate and return a block at least *SIZE bytes long from HEAP.
|
240 |
|
|
*SIZE is adjusted to reflect the actual amount allocated (which may be
|
241 |
|
|
greater than requested). */
|
242 |
|
|
extern void *__heap_alloc (struct heap *heap, size_t *size);
|
243 |
|
|
|
244 |
|
|
/* Allocate SIZE bytes at address MEM in HEAP. Return the actual size
|
245 |
|
|
allocated, or 0 if we failed. */
|
246 |
|
|
extern size_t __heap_alloc_at (struct heap *heap, void *mem, size_t size);
|
247 |
|
|
|
248 |
|
|
/* Return the memory area MEM of size SIZE to HEAP.
|
249 |
|
|
Returns the heap free area into which the memory was placed. */
|
250 |
|
|
extern struct heap_free_area *__heap_free (struct heap *heap,
|
251 |
|
|
void *mem, size_t size);
|
252 |
|
|
|
253 |
|
|
/* Return true if HEAP contains absolutely no memory. */
|
254 |
|
|
#define __heap_is_empty(heap) (! (heap)->free_areas)
|