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 /* Copyright (c) 2010. The SimGrid Team.
8 * All rights reserved. */
10 /* This program is free software; you can redistribute it and/or modify it
11 * under the terms of the license (GNU LGPL) which comes with this package. */
13 #include <string.h> /* Prototypes for memcpy, memmove, memset, etc */
15 #include "mmprivate.h"
17 /* Prototypes for local functions */
19 static int initialize (struct mdesc *mdp);
20 static void* morecore (struct mdesc *mdp, size_t size);
21 static void* align (struct mdesc *mdp, size_t size);
23 /* Aligned allocation. */
26 align (struct mdesc *mdp, size_t size)
29 unsigned long int adj;
31 result = mdp -> morecore (mdp, size);
32 adj = RESIDUAL (result, BLOCKSIZE);
35 adj = BLOCKSIZE - adj;
36 mdp -> morecore (mdp, adj);
37 result = (char*) result + adj;
42 /* Set everything up and remember that we have. */
45 initialize (struct mdesc *mdp)
47 mdp -> heapsize = HEAP / BLOCKSIZE;
48 mdp -> heapinfo = (malloc_info *)
49 align (mdp, mdp -> heapsize * sizeof (malloc_info));
50 if (mdp -> heapinfo == NULL)
54 memset ((void*)mdp -> heapinfo, 0, mdp -> heapsize * sizeof (malloc_info));
55 mdp -> heapinfo[0].free.size = 0;
56 mdp -> heapinfo[0].free.next = mdp -> heapinfo[0].free.prev = 0;
58 mdp -> heapbase = (void*) mdp -> heapinfo;
59 mdp -> flags |= MMALLOC_INITIALIZED;
63 /* Get neatly aligned memory, initializing or
64 growing the heap info table as necessary. */
67 morecore (struct mdesc *mdp, size_t size)
70 malloc_info *newinfo, *oldinfo;
73 result = align (mdp, size);
79 /* Check if we need to grow the info table. */
80 if ((size_t) BLOCK ((char*) result + size) > mdp -> heapsize)
82 newsize = mdp -> heapsize;
83 while ((size_t) BLOCK ((char*) result + size) > newsize)
87 newinfo = (malloc_info *) align (mdp, newsize * sizeof (malloc_info));
90 mdp -> morecore (mdp, -size);
93 memset ((void*) newinfo, 0, newsize * sizeof (malloc_info));
94 memcpy ((void*) newinfo, (void*) mdp -> heapinfo,
95 mdp -> heapsize * sizeof (malloc_info));
96 oldinfo = mdp -> heapinfo;
97 newinfo[BLOCK (oldinfo)].busy.type = 0;
98 newinfo[BLOCK (oldinfo)].busy.info.size
99 = BLOCKIFY (mdp -> heapsize * sizeof (malloc_info));
100 mdp -> heapinfo = newinfo;
101 __mmalloc_free (mdp, (void*)oldinfo);
102 mdp -> heapsize = newsize;
105 mdp -> heaplimit = BLOCK ((char*) result + size);
109 /* Allocate memory from the heap. */
112 mmalloc (void *md, size_t size)
116 size_t block, blocks, lastblocks, start;
126 mdp = MD_TO_MDP (md);
128 if (mdp -> mmalloc_hook != NULL)
130 return ((*mdp -> mmalloc_hook) (md, size));
133 if (!(mdp -> flags & MMALLOC_INITIALIZED))
135 if (!initialize (mdp))
141 if (size < sizeof (struct list))
143 size = sizeof (struct list);
146 /* Determine the allocation policy based on the request size. */
147 if (size <= BLOCKSIZE / 2)
149 /* Small allocation to receive a fragment of a block.
150 Determine the logarithm to base two of the fragment size. */
153 while ((size /= 2) != 0)
158 /* Look in the fragment lists for a
159 free fragment of the desired size. */
160 next = mdp -> fraghead[log].next;
163 /* There are free fragments of this size.
164 Pop a fragment out of the fragment list and return it.
165 Update the block's nfree and first counters. */
166 result = (void*) next;
167 next -> prev -> next = next -> next;
168 if (next -> next != NULL)
170 next -> next -> prev = next -> prev;
172 block = BLOCK (result);
173 if (--mdp -> heapinfo[block].busy.info.frag.nfree != 0)
175 mdp -> heapinfo[block].busy.info.frag.first =
176 RESIDUAL (next -> next, BLOCKSIZE) >> log;
179 /* Update the statistics. */
180 mdp -> heapstats.chunks_used++;
181 mdp -> heapstats.bytes_used += 1 << log;
182 mdp -> heapstats.chunks_free--;
183 mdp -> heapstats.bytes_free -= 1 << log;
187 /* No free fragments of the desired size, so get a new block
188 and break it into fragments, returning the first. */
189 result = mmalloc (md, BLOCKSIZE);
195 /* Link all fragments but the first into the free list. */
196 for (i = 1; i < (size_t) (BLOCKSIZE >> log); ++i)
198 next = (struct list *) ((char*) result + (i << log));
199 next -> next = mdp -> fraghead[log].next;
200 next -> prev = &mdp -> fraghead[log];
201 next -> prev -> next = next;
202 if (next -> next != NULL)
204 next -> next -> prev = next;
208 /* Initialize the nfree and first counters for this block. */
209 block = BLOCK (result);
210 mdp -> heapinfo[block].busy.type = log;
211 mdp -> heapinfo[block].busy.info.frag.nfree = i - 1;
212 mdp -> heapinfo[block].busy.info.frag.first = i - 1;
214 mdp -> heapstats.chunks_free += (BLOCKSIZE >> log) - 1;
215 mdp -> heapstats.bytes_free += BLOCKSIZE - (1 << log);
216 mdp -> heapstats.bytes_used -= BLOCKSIZE - (1 << log);
221 /* Large allocation to receive one or more blocks.
222 Search the free list in a circle starting at the last place visited.
223 If we loop completely around without finding a large enough
224 space we will have to get more memory from the system. */
225 blocks = BLOCKIFY(size);
226 start = block = MALLOC_SEARCH_START;
227 while (mdp -> heapinfo[block].free.size < blocks)
229 block = mdp -> heapinfo[block].free.next;
232 /* Need to get more from the system. Check to see if
233 the new core will be contiguous with the final free
234 block; if so we don't need to get as much. */
235 block = mdp -> heapinfo[0].free.prev;
236 lastblocks = mdp -> heapinfo[block].free.size;
237 if (mdp -> heaplimit != 0 &&
238 block + lastblocks == mdp -> heaplimit &&
239 mdp -> morecore (mdp, 0) == ADDRESS(block + lastblocks) &&
240 (morecore (mdp, (blocks - lastblocks) * BLOCKSIZE)) != NULL)
242 /* Which block we are extending (the `final free
243 block' referred to above) might have changed, if
244 it got combined with a freed info table. */
245 block = mdp -> heapinfo[0].free.prev;
247 mdp -> heapinfo[block].free.size += (blocks - lastblocks);
248 mdp -> heapstats.bytes_free +=
249 (blocks - lastblocks) * BLOCKSIZE;
252 result = morecore(mdp, blocks * BLOCKSIZE);
257 block = BLOCK (result);
258 mdp -> heapinfo[block].busy.type = 0;
259 mdp -> heapinfo[block].busy.info.size = blocks;
260 mdp -> heapstats.chunks_used++;
261 mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
266 /* At this point we have found a suitable free list entry.
267 Figure out how to remove what we need from the list. */
268 result = ADDRESS(block);
269 if (mdp -> heapinfo[block].free.size > blocks)
271 /* The block we found has a bit left over,
272 so relink the tail end back into the free list. */
273 mdp -> heapinfo[block + blocks].free.size
274 = mdp -> heapinfo[block].free.size - blocks;
275 mdp -> heapinfo[block + blocks].free.next
276 = mdp -> heapinfo[block].free.next;
277 mdp -> heapinfo[block + blocks].free.prev
278 = mdp -> heapinfo[block].free.prev;
279 mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
280 = mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
281 = mdp -> heapindex = block + blocks;
285 /* The block exactly matches our requirements,
286 so just remove it from the list. */
287 mdp -> heapinfo[mdp -> heapinfo[block].free.next].free.prev
288 = mdp -> heapinfo[block].free.prev;
289 mdp -> heapinfo[mdp -> heapinfo[block].free.prev].free.next
290 = mdp -> heapindex = mdp -> heapinfo[block].free.next;
291 mdp -> heapstats.chunks_free--;
294 mdp -> heapinfo[block].busy.type = 0;
295 mdp -> heapinfo[block].busy.info.size = blocks;
296 mdp -> heapstats.chunks_used++;
297 mdp -> heapstats.bytes_used += blocks * BLOCKSIZE;
298 mdp -> heapstats.bytes_free -= blocks * BLOCKSIZE;
304 /* When using this package, provide a version of malloc/realloc/free built
305 on top of it, so that if we use the default sbrk() region we will not
306 collide with another malloc package trying to do the same thing, if
307 the application contains any "hidden" calls to malloc/realloc/free (such
308 as inside a system library).
309 FIXME: disabled for now */
311 //void* malloc (size_t size) {
313 // result = mmalloc (NULL, size);