1 /* malloc.c -- Implementation File (module.c template V1.0)
2 Copyright (C) 1995, 2003 Free Software Foundation, Inc.
3 Contributed by James Craig Burley.
5 This file is part of GNU Fortran.
7 GNU Fortran is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
12 GNU Fortran 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
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Fortran; see the file COPYING. If not, write to
19 the Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
26 Fast pool-based memory allocation.
36 /* Externals defined here. */
38 struct _malloc_root_ malloc_root_
42 &malloc_root_.malloc_pool_image_,
43 &malloc_root_.malloc_pool_image_,
44 (mallocPool) &malloc_root_.malloc_pool_image_.eldest,
45 (mallocPool) &malloc_root_.malloc_pool_image_.eldest,
46 (mallocArea_) &malloc_root_.malloc_pool_image_.first,
47 (mallocArea_) &malloc_root_.malloc_pool_image_.first,
50 0, 0, 0, 0, 0, 0, 0, { '/' }
57 /* Simple definitions and enumerations. */
60 /* Internal typedefs. */
63 /* Private include files. */
66 /* Internal structure definitions. */
69 /* Static objects accessed by functions in this module. */
71 static void *malloc_reserve_ = NULL; /* For crashes. */
73 static const char *const malloc_types_[] =
74 {"KS", "KSR", "NF", "NFR", "US", "USR"};
77 /* Static functions (internal). */
79 static void malloc_kill_area_ (mallocPool pool, mallocArea_ a);
81 static void malloc_verify_area_ (mallocPool pool, mallocArea_ a);
84 /* Internal macros. */
86 struct max_alignment {
94 #define MAX_ALIGNMENT (offsetof (struct max_alignment, u))
95 #define ROUNDED_AREA_SIZE (MAX_ALIGNMENT * ((sizeof(mallocArea_) + MAX_ALIGNMENT - 1) / MAX_ALIGNMENT))
98 #define malloc_kill_(ptr,s) do {memset((ptr),127,(s));free((ptr));} while(0)
100 #define malloc_kill_(ptr,s) free((ptr))
103 /* malloc_kill_area_ -- Kill storage area and its object
105 malloc_kill_area_(mallocPool pool,mallocArea_ area);
107 Does the actual killing of a storage area. */
110 malloc_kill_area_ (mallocPool pool UNUSED, mallocArea_ a)
113 assert (strcmp (a->name, ((char *) (a->where)) + a->size) == 0);
115 malloc_kill_ (a->where - ROUNDED_AREA_SIZE, a->size);
116 a->next->previous = a->previous;
117 a->previous->next = a->next;
119 pool->freed += a->size;
124 offsetof (struct _malloc_area_, name)
125 + strlen (a->name) + 1);
128 /* malloc_verify_area_ -- Verify storage area and its object
130 malloc_verify_area_(mallocPool pool,mallocArea_ area);
132 Does the actual verifying of a storage area. */
136 malloc_verify_area_ (mallocPool pool UNUSED, mallocArea_ a UNUSED)
138 mallocSize s = a->size;
140 assert (strcmp (a->name, ((char *) (a->where)) + s) == 0);
144 /* malloc_init -- Initialize malloc cluster
148 Call malloc_init before you do anything else. */
153 if (malloc_reserve_ != NULL)
155 malloc_reserve_ = xmalloc (20 * 1024); /* In case of crash, free this first. */
158 /* malloc_pool_display -- Display a pool
161 malloc_pool_display(p);
163 Displays information associated with the pool and its subpools. */
166 malloc_pool_display (mallocPool p UNUSED)
172 fprintf (dmpout, "Pool \"%s\": bytes allocated=%lu, freed=%lu, old sizes=%lu, new sizes\
173 =%lu,\n allocations=%lu, frees=%lu, resizes=%lu, uses=%lu\n Subpools:\n",
174 p->name, p->allocated, p->freed, p->old_sizes, p->new_sizes, p->allocations,
175 p->frees, p->resizes, p->uses);
177 for (q = p->eldest; q != (mallocPool) & p->eldest; q = q->next)
178 fprintf (dmpout, " \"%s\"\n", q->name);
180 fprintf (dmpout, " Storage areas:\n");
182 for (a = p->first; a != (mallocArea_) & p->first; a = a->next)
184 fprintf (dmpout, " ");
190 /* malloc_pool_kill -- Destroy a pool
195 Releases all storage associated with the pool and its subpools. */
198 malloc_pool_kill (mallocPool p)
207 malloc_pool_display (p);
210 assert (p->next->previous == p);
211 assert (p->previous->next == p);
213 /* Kill off all the subpools. */
215 while ((q = p->eldest) != (mallocPool) &p->eldest)
217 q->uses = 1; /* Force the kill. */
218 malloc_pool_kill (q);
221 /* Now free all the storage areas. */
223 while ((a = p->first) != (mallocArea_) & p->first)
225 malloc_kill_area_ (p, a);
228 /* Now remove from list of sibling pools. */
230 p->next->previous = p->previous;
231 p->previous->next = p->next;
233 /* Finally, free the pool itself. */
236 offsetof (struct _malloc_pool_, name)
237 + strlen (p->name) + 1);
240 /* malloc_pool_new -- Make a new pool
243 p = malloc_pool_new("My new pool",malloc_pool_image(),1024);
245 Makes a new pool with the given name and default new-chunk allocation. */
248 malloc_pool_new (const char *name, mallocPool parent,
249 unsigned long chunks UNUSED)
254 parent = malloc_pool_image ();
256 p = malloc_new_ (offsetof (struct _malloc_pool_, name)
257 + (MALLOC_DEBUG ? strlen (name) + 1 : 0));
258 p->next = (mallocPool) &(parent->eldest);
259 p->previous = parent->youngest;
260 parent->youngest->next = p;
261 parent->youngest = p;
262 p->eldest = (mallocPool) &(p->eldest);
263 p->youngest = (mallocPool) &(p->eldest);
264 p->first = (mallocArea_) &(p->first);
265 p->last = (mallocArea_) &(p->first);
268 p->allocated = p->freed = p->old_sizes = p->new_sizes = p->allocations
269 = p->frees = p->resizes = 0;
270 strcpy (p->name, name);
275 /* malloc_pool_use -- Use an existing pool
278 p = malloc_pool_new(pool);
280 Increments use count for pool; means a matching malloc_pool_kill must
281 be performed before a subsequent one will actually kill the pool. */
284 malloc_pool_use (mallocPool pool)
290 /* malloc_display_ -- Display info on a mallocArea_
298 malloc_display_ (mallocArea_ a UNUSED)
301 fprintf (dmpout, "At %08lX, size=%" mallocSize_f "u, type=%s, \"%s\"\n",
302 (unsigned long) a->where, a->size, malloc_types_[a->type], a->name);
306 /* malloc_find_inpool_ -- Find mallocArea_ for object in pool
311 a = malloc_find_inpool_(pool,ptr);
313 Search for object in list of mallocArea_s, die if not found. */
316 malloc_find_inpool_ (mallocPool pool UNUSED, void *ptr)
319 t = (mallocArea_ *) (ptr - ROUNDED_AREA_SIZE);
323 /* malloc_kill_inpool_ -- Kill object
325 malloc_kill_inpool_(NULL,MALLOC_typeUS_,ptr,size_in_bytes);
327 Find the mallocArea_ for the pointer, make sure the type is proper, and
328 kill both of them. */
331 malloc_kill_inpool_ (mallocPool pool, mallocType_ type UNUSED,
332 void *ptr, mallocSize s UNUSED)
337 pool = malloc_pool_image ();
340 assert ((pool == malloc_pool_image ())
341 || malloc_pool_find_ (pool, malloc_pool_image ()));
344 a = malloc_find_inpool_ (pool, ptr);
346 assert (a->type == type);
347 if ((type != MALLOC_typeUS_) && (type != MALLOC_typeUSR_))
348 assert (a->size == s);
350 malloc_kill_area_ (pool, a);
353 /* malloc_new_ -- Allocate new object, die if unable
355 ptr = malloc_new_(size_in_bytes);
357 Call malloc, bomb if it returns NULL. */
360 malloc_new_ (mallocSize s)
365 #if MALLOC_DEBUG && 0
366 assert (s == (mallocSize) ss);/* Else alloc is too big for this
372 memset (ptr, 126, ss); /* Catch some kinds of errors more
378 /* malloc_new_inpool_ -- Allocate new object, die if unable
380 ptr = malloc_new_inpool_(NULL,MALLOC_typeUS_,"object",size_in_bytes);
382 Allocate the structure and allocate a mallocArea_ to describe it, then
383 add it to the list of mallocArea_s for the pool. */
386 malloc_new_inpool_ (mallocPool pool, mallocType_ type, const char *name, mallocSize s)
394 pool = malloc_pool_image ();
397 assert ((pool == malloc_pool_image ())
398 || malloc_pool_find_ (pool, malloc_pool_image ()));
401 ptr = malloc_new_ (ROUNDED_AREA_SIZE + s + (i = (MALLOC_DEBUG ? strlen (name) + 1 : 0)));
403 strcpy (((char *) (ptr)) + s, name);
405 a = malloc_new_ (offsetof (struct _malloc_area_, name) + i);
406 temp = (mallocArea_ *) ptr;
408 ptr = ptr + ROUNDED_AREA_SIZE;
410 { /* A little optimization to speed up killing
411 of non-permanent stuff. */
413 case MALLOC_typeKPR_:
414 a->next = (mallocArea_) &pool->first;
418 a->next = pool->first;
421 a->previous = a->next->previous;
422 a->next->previous = a;
423 a->previous->next = a;
428 strcpy (a->name, name);
429 pool->allocated += s;
435 /* malloc_new_zinpool_ -- Allocate new zeroed object, die if unable
437 ptr = malloc_new_zinpool_(NULL,MALLOC_typeUS_,"object",size_in_bytes,0);
439 Like malloc_new_inpool_, but zeros out all the bytes in the area (assuming
443 malloc_new_zinpool_ (mallocPool pool, mallocType_ type, const char *name, mallocSize s,
448 ptr = malloc_new_inpool_ (pool, type, name, s);
453 /* malloc_pool_find_ -- See if pool is a descendant of another pool
455 if (malloc_pool_find_(target_pool,parent_pool)) ...;
457 Recursive descent on each of the children of the parent pool, after
458 first checking the children themselves. */
461 malloc_pool_find_ (mallocPool pool, mallocPool parent)
465 for (p = parent->eldest; p != (mallocPool) & parent->eldest; p = p->next)
467 if ((p == pool) || malloc_pool_find_ (pool, p))
473 /* malloc_resize_inpool_ -- Resize existing object in pool
475 ptr = malloc_resize_inpool_(NULL,MALLOC_typeUSR_,ptr,new_size,old_size);
477 Find the object's mallocArea_, check it out, then do the resizing. */
480 malloc_resize_inpool_ (mallocPool pool, mallocType_ type UNUSED,
481 void *ptr, mallocSize ns, mallocSize os UNUSED)
487 pool = malloc_pool_image ();
490 assert ((pool == malloc_pool_image ())
491 || malloc_pool_find_ (pool, malloc_pool_image ()));
494 a = malloc_find_inpool_ (pool, ptr);
496 assert (a->type == type);
497 if ((type == MALLOC_typeKSR_) || (type == MALLOC_typeKPR_))
498 assert (a->size == os);
499 assert (strcmp (a->name, ((char *) (ptr)) + os) == 0);
501 ptr = malloc_resize_ (ptr - ROUNDED_AREA_SIZE, ROUNDED_AREA_SIZE + ns + (MALLOC_DEBUG ? strlen (a->name) + 1: 0));
502 temp = (mallocArea_ *) ptr;
504 ptr = ptr + ROUNDED_AREA_SIZE;
508 strcpy (((char *) (ptr)) + ns, a->name);
509 pool->old_sizes += os;
510 pool->new_sizes += ns;
516 /* malloc_resize_ -- Reallocate object, die if unable
518 ptr = malloc_resize_(ptr,size_in_bytes);
520 Call realloc, bomb if it returns NULL. */
523 malloc_resize_ (void *ptr, mallocSize s)
527 #if MALLOC_DEBUG && 0
528 assert (s == (mallocSize) ss);/* Too big if failure here. */
531 ptr = xrealloc (ptr, ss);
535 /* malloc_verify_inpool_ -- Verify object
537 Find the mallocArea_ for the pointer, make sure the type is proper, and
538 verify both of them. */
541 malloc_verify_inpool_ (mallocPool pool UNUSED, mallocType_ type UNUSED,
542 void *ptr UNUSED, mallocSize s UNUSED)
548 pool = malloc_pool_image ();
550 assert ((pool == malloc_pool_image ())
551 || malloc_pool_find_ (pool, malloc_pool_image ()));
553 a = malloc_find_inpool_ (pool, ptr);
554 assert (a->type == type);
555 if ((type != MALLOC_typeUS_) && (type != MALLOC_typeUSR_))
556 assert (a->size == s);
557 malloc_verify_area_ (pool, a);