1 /* Memory allocator `malloc'.
2 Copyright 1990, 1991, 1992 Free Software Foundation
4 Written May 1989 by Mike Haertel.
5 Heavily modified Mar 1992 by Fred Fish for mmap'd version.
7 The GNU C Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
12 The GNU C Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
17 You should have received a copy of the GNU Library General Public
18 License along with the GNU C Library; see the file COPYING.LIB. If
19 not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 The author may be reached (Email) at the address mike@ai.mit.edu,
23 or (US mail) as Mike Haertel c/o Free Software Foundation. */
25 #include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
27 #include "mmprivate.h"
29 /* Prototypes for local functions */
31 static int initialize (struct mdesc *mdp);
32 static void* morecore (struct mdesc *mdp, size_t size);
33 static void* align (struct mdesc *mdp, size_t size);
35 /* Aligned allocation. */
38 align (struct mdesc *mdp, size_t size)
41 unsigned long int adj;
43 result = mdp -> morecore (mdp, size);
44 adj = RESIDUAL (result, BLOCKSIZE);
47 adj = BLOCKSIZE - adj;
48 mdp -> morecore (mdp, adj);
49 result = (char*) result + adj;
54 /* Set everything up and remember that we have. */
57 initialize (struct mdesc *mdp)
59 mdp -> heapsize = HEAP / BLOCKSIZE;
60 mdp -> heapinfo = (malloc_info *)
61 align (mdp, mdp -> heapsize * sizeof (malloc_info));
62 if (mdp -> heapinfo == NULL)
66 memset ((void*)mdp -> heapinfo, 0, mdp -> heapsize * sizeof (malloc_info));
67 mdp -> heapinfo[0].free.size = 0;
68 mdp -> heapinfo[0].free.next = mdp -> heapinfo[0].free.prev = 0;
70 mdp -> heapbase = (void*) mdp -> heapinfo;
71 mdp -> flags |= MMALLOC_INITIALIZED;
75 /* Get neatly aligned memory, initializing or
76 growing the heap info table as necessary. */
79 morecore (struct mdesc *mdp, size_t size)
82 malloc_info *newinfo, *oldinfo;
85 result = align (mdp, size);
91 /* Check if we need to grow the info table. */
92 if ((size_t) BLOCK ((char*) result + size) > mdp -> heapsize)
94 newsize = mdp -> heapsize;
95 while ((size_t) BLOCK ((char*) result + size) > newsize)
99 newinfo = (malloc_info *) align (mdp, newsize * sizeof (malloc_info));
102 mdp -> morecore (mdp, -size);
105 memset ((void*) newinfo, 0, newsize * sizeof (malloc_info));
106 memcpy ((void*) newinfo, (void*) mdp -> heapinfo,
107 mdp -> heapsize * sizeof (malloc_info));
108 oldinfo = mdp -> heapinfo;
109 newinfo[BLOCK (oldinfo)].busy.type = 0;
110 newinfo[BLOCK (oldinfo)].busy.info.size
111 = BLOCKIFY (mdp -> heapsize * sizeof (malloc_info));
112 mdp -> heapinfo = newinfo;
113 __mmalloc_free (mdp, (void*)oldinfo);
114 mdp -> heapsize = newsize;
117 mdp -> heaplimit = BLOCK ((char*) result + size);
121 /* Allocate memory from the heap. */
130 size_t block, blocks, lastblocks, start;
140 mdp = MD_TO_MDP (md);
142 if (mdp -> mmalloc_hook != NULL)
144 return ((*mdp -> mmalloc_hook) (md, size));
147 if (!(mdp -> flags & MMALLOC_INITIALIZED))
149 if (!initialize (mdp))
155 if (size < sizeof (struct list))
157 size = sizeof (struct list);
160 /* Determine the allocation policy based on the request size. */
161 if (size <= BLOCKSIZE / 2)
163 /* Small allocation to receive a fragment of a block.
164 Determine the logarithm to base two of the fragment size. */
167 while ((size /= 2) != 0)
172 /* Look in the fragment lists for a
173 free fragment of the desired size. */
174 next = mdp -> fraghead[log].next;
177 /* There are free fragments of this size.
178 Pop a fragment out of the fragment list and return it.
179 Update the block's nfree and first counters. */
180 result = (void*) next;
181 next -> prev -> next = next -> next;
182 if (next -> next != NULL)
184 next -> next -> prev = next -> prev;
186 block = BLOCK (result);
187 if (--mdp -> heapinfo[block].busy.info.frag.nfree != 0)
189 mdp -> heapinfo[block].busy.info.frag.first =
190 RESIDUAL (next -> next, BLOCKSIZE) >> log;
193 /* Update the statistics. */
194 mdp -> heapstats.chunks_used++;
195 mdp -> heapstats.bytes_used += 1 << log;
196 mdp -> heapstats.chunks_free--;
197 mdp -> heapstats.bytes_free -= 1 << log;
201 /* No free fragments of the desired size, so get a new block
202 and break it into fragments, returning the first. */
203 result = mmalloc (md, BLOCKSIZE);
209 /* Link all fragments but the first into the free list. */
210 for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
212 next = (struct list *) ((char*) result + (i << log));
213 next -> next = mdp -> fraghead[log].next;
214 next -> prev = &mdp -> fraghead[log];
215 next -> prev -> next = next;
216 if (next -> next != NULL)
218 next -> next -> prev = next;
222 /* Initialize the nfree and first counters for this block. */
223 block = BLOCK (result);
224 mdp -> heapinfo[block].busy.type = log;
225 mdp -> heapinfo[block].busy.info.frag.nfree = i - 1;
226 mdp -> heapinfo[block].busy.info.frag.first = i - 1;
228 mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1;
229 mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log);
230 mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log);
235 /* Large allocation to receive one or more blocks.
236 Search the free list in a circle starting at the last place visited.
237 If we loop completely around without finding a large enough
238 space we will have to get more memory from the system. */
239 blocks = BLOCKIFY(size);
240 start = block = MALLOC_SEARCH_START;
241 while (mdp -> heapinfo[block].free.size < blocks)
243 block = mdp -> heapinfo[block].free.next;
246 /* Need to get more from the system. Check to see if
247 the new core will be contiguous with the final free
248 block; if so we don't need to get as much. */
249 block = mdp -> heapinfo[0].free.prev;
250 lastblocks = mdp -> heapinfo[block].free.size;
251 if (mdp -> heaplimit != 0 &&
252 block + lastblocks == mdp -> heaplimit &&
253 mdp -> morecore (mdp, 0) == ADDRESS(block + lastblocks) &&
254 (morecore (mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL)
256 /* Which block we are extending (the `final free
257 block' referred to above) might have changed, if
258 it got combined with a freed info table. */
259 block = mdp -> heapinfo[0].free.prev;
261 mdp -> heapinfo[block].free.size += (blocks - lastblocks);
262 mdp -> heapstats.bytes_free +=
263 (blocks - lastblocks) * BLOCKSIZE;
266 result = morecore(mdp, blocks * BLOCKSIZE);
271 block = BLOCK (result);
272 mdp -> heapinfo[block].busy.type = 0;
273 mdp -> heapinfo[block].busy.info.size = blocks;
274 mdp -> heapstats.chunks_used++;
275 mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
280 /* At this point we have found a suitable free list entry.
281 Figure out how to remove what we need from the list. */
282 result = ADDRESS(block);
283 if (mdp -> heapinfo[block].free.size > blocks)
285 /* The block we found has a bit left over,
286 so relink the tail end back into the free list. */
287 mdp -> heapinfo[block + blocks].free.size
288 = mdp -> heapinfo[block].free.size - blocks;
289 mdp -> heapinfo[block + blocks].free.next
290 = mdp -> heapinfo[block].free.next;
291 mdp -> heapinfo[block + blocks].free.prev
292 = mdp -> heapinfo[block].free.prev;
293 mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
294 = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
295 = mdp -> heapindex = block + blocks;
299 /* The block exactly matches our requirements,
300 so just remove it from the list. */
301 mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
302 = mdp -> heapinfo[block].free.prev;
303 mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
304 = mdp -> heapindex = mdp -> heapinfo[block].free.next;
305 mdp -> heapstats.chunks_free--;
308 mdp -> heapinfo[block].busy.type = 0;
309 mdp -> heapinfo[block].busy.info.size = blocks;
310 mdp -> heapstats.chunks_used++;
311 mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
312 mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE;
318 /* When using this package, provide a version of malloc/realloc/free built
319 on top of it, so that if we use the default sbrk() region we will not
320 collide with another malloc package trying to do the same thing, if
321 the application contains any "hidden" calls to malloc/realloc/free (such
322 as inside a system library). */
328 result = mmalloc (NULL, size);