1 /* malloc.c -- Implementation File (module.c template V1.0)
2 Copyright (C) 1995 Free Software Foundation, Inc.
3 Contributed by James Craig Burley (burley@gnu.org).
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 /* Assume gcc/toplev.o is linked in. */
37 void *xmalloc (unsigned size
);
38 void *xrealloc (void *ptr
, int size
);
40 /* Externals defined here. */
42 struct _malloc_root_ malloc_root_
46 &malloc_root_
.malloc_pool_image_
,
47 &malloc_root_
.malloc_pool_image_
,
48 (mallocPool
) &malloc_root_
.malloc_pool_image_
.eldest
,
49 (mallocPool
) &malloc_root_
.malloc_pool_image_
.eldest
,
50 (mallocArea_
) &malloc_root_
.malloc_pool_image_
.first
,
51 (mallocArea_
) &malloc_root_
.malloc_pool_image_
.first
,
54 0, 0, 0, 0, 0, 0, 0, { '/' }
59 /* Simple definitions and enumerations. */
62 /* Internal typedefs. */
65 /* Private include files. */
68 /* Internal structure definitions. */
71 /* Static objects accessed by functions in this module. */
73 static void *malloc_reserve_
= NULL
; /* For crashes. */
75 static char *malloc_types_
[] =
76 {"KS", "KSR", "NF", "NFR", "US", "USR"};
79 /* Static functions (internal). */
81 static void malloc_kill_area_ (mallocPool pool
, mallocArea_ a
);
83 static void malloc_verify_area_ (mallocPool pool
, mallocArea_ a
);
86 /* Internal macros. */
89 #define malloc_kill_(ptr,s) do {memset((ptr),127,(s));free((ptr));} while(0)
91 #define malloc_kill_(ptr,s) free((ptr))
94 /* malloc_kill_area_ -- Kill storage area and its object
96 malloc_kill_area_(mallocPool pool,mallocArea_ area);
98 Does the actual killing of a storage area. */
101 malloc_kill_area_ (mallocPool pool UNUSED
, mallocArea_ a
)
104 assert (strcmp (a
->name
, ((char *) (a
->where
)) + a
->size
) == 0);
106 malloc_kill_ (a
->where
, a
->size
);
107 a
->next
->previous
= a
->previous
;
108 a
->previous
->next
= a
->next
;
110 pool
->freed
+= a
->size
;
114 offsetof (struct _malloc_area_
, name
)
115 + strlen (a
->name
) + 1);
118 /* malloc_verify_area_ -- Verify storage area and its object
120 malloc_verify_area_(mallocPool pool,mallocArea_ area);
122 Does the actual verifying of a storage area. */
126 malloc_verify_area_ (mallocPool pool UNUSED
, mallocArea_ a UNUSED
)
128 mallocSize s
= a
->size
;
130 assert (strcmp (a
->name
, ((char *) (a
->where
)) + s
) == 0);
134 /* malloc_init -- Initialize malloc cluster
138 Call malloc_init before you do anything else. */
143 if (malloc_reserve_
!= NULL
)
145 malloc_reserve_
= malloc (20 * 1024); /* In case of crash, free this first. */
146 assert (malloc_reserve_
!= NULL
);
149 /* malloc_pool_display -- Display a pool
152 malloc_pool_display(p);
154 Displays information associated with the pool and its subpools. */
157 malloc_pool_display (mallocPool p UNUSED
)
163 fprintf (dmpout
, "Pool \"%s\": bytes allocated=%lu, freed=%lu, old sizes=%lu, new sizes\
164 =%lu,\n allocations=%lu, frees=%lu, resizes=%lu, uses=%lu\n Subpools:\n",
165 p
->name
, p
->allocated
, p
->freed
, p
->old_sizes
, p
->new_sizes
, p
->allocations
,
166 p
->frees
, p
->resizes
, p
->uses
);
168 for (q
= p
->eldest
; q
!= (mallocPool
) & p
->eldest
; q
= q
->next
)
169 fprintf (dmpout
, " \"%s\"\n", q
->name
);
171 fprintf (dmpout
, " Storage areas:\n");
173 for (a
= p
->first
; a
!= (mallocArea_
) & p
->first
; a
= a
->next
)
175 fprintf (dmpout
, " ");
181 /* malloc_pool_kill -- Destroy a pool
186 Releases all storage associated with the pool and its subpools. */
189 malloc_pool_kill (mallocPool p
)
198 malloc_pool_display (p
);
201 assert (p
->next
->previous
== p
);
202 assert (p
->previous
->next
== p
);
204 /* Kill off all the subpools. */
206 while ((q
= p
->eldest
) != (mallocPool
) &p
->eldest
)
208 q
->uses
= 1; /* Force the kill. */
209 malloc_pool_kill (q
);
212 /* Now free all the storage areas. */
214 while ((a
= p
->first
) != (mallocArea_
) & p
->first
)
216 malloc_kill_area_ (p
, a
);
219 /* Now remove from list of sibling pools. */
221 p
->next
->previous
= p
->previous
;
222 p
->previous
->next
= p
->next
;
224 /* Finally, free the pool itself. */
227 offsetof (struct _malloc_pool_
, name
)
228 + strlen (p
->name
) + 1);
231 /* malloc_pool_new -- Make a new pool
234 p = malloc_pool_new("My new pool",malloc_pool_image(),1024);
236 Makes a new pool with the given name and default new-chunk allocation. */
239 malloc_pool_new (char *name
, mallocPool parent
,
240 unsigned long chunks UNUSED
)
245 parent
= malloc_pool_image ();
247 p
= malloc_new_ (offsetof (struct _malloc_pool_
, name
)
248 + (MALLOC_DEBUG
? strlen (name
) + 1 : 0));
249 p
->next
= (mallocPool
) &(parent
->eldest
);
250 p
->previous
= parent
->youngest
;
251 parent
->youngest
->next
= p
;
252 parent
->youngest
= p
;
253 p
->eldest
= (mallocPool
) &(p
->eldest
);
254 p
->youngest
= (mallocPool
) &(p
->eldest
);
255 p
->first
= (mallocArea_
) &(p
->first
);
256 p
->last
= (mallocArea_
) &(p
->first
);
259 p
->allocated
= p
->freed
= p
->old_sizes
= p
->new_sizes
= p
->allocations
260 = p
->frees
= p
->resizes
= 0;
261 strcpy (p
->name
, name
);
266 /* malloc_pool_use -- Use an existing pool
269 p = malloc_pool_new(pool);
271 Increments use count for pool; means a matching malloc_pool_kill must
272 be performed before a subsequent one will actually kill the pool. */
275 malloc_pool_use (mallocPool pool
)
281 /* malloc_display_ -- Display info on a mallocArea_
289 malloc_display_ (mallocArea_ a UNUSED
)
292 fprintf (dmpout
, "At %08lX, size=%" mallocSize_f
"u, type=%s, \"%s\"\n",
293 (unsigned long) a
->where
, a
->size
, malloc_types_
[a
->type
], a
->name
);
297 /* malloc_find_inpool_ -- Find mallocArea_ for object in pool
302 a = malloc_find_inpool_(pool,ptr);
304 Search for object in list of mallocArea_s, die if not found. */
307 malloc_find_inpool_ (mallocPool pool
, void *ptr
)
310 mallocArea_ b
= (mallocArea_
) &pool
->first
;
313 for (a
= pool
->first
; a
!= (mallocArea_
) &pool
->first
; a
= a
->next
)
315 assert (("Infinite loop detected" != NULL
) && (a
!= b
));
322 assert ("Couldn't find object in pool!" == NULL
);
326 /* malloc_kill_inpool_ -- Kill object
328 malloc_kill_inpool_(NULL,MALLOC_typeUS_,ptr,size_in_bytes);
330 Find the mallocArea_ for the pointer, make sure the type is proper, and
331 kill both of them. */
334 malloc_kill_inpool_ (mallocPool pool
, mallocType_ type UNUSED
,
335 void *ptr
, mallocSize s UNUSED
)
340 pool
= malloc_pool_image ();
343 assert ((pool
== malloc_pool_image ())
344 || malloc_pool_find_ (pool
, malloc_pool_image ()));
347 a
= malloc_find_inpool_ (pool
, ptr
);
349 assert (a
->type
== type
);
350 if ((type
!= MALLOC_typeUS_
) && (type
!= MALLOC_typeUSR_
))
351 assert (a
->size
== s
);
353 malloc_kill_area_ (pool
, a
);
356 /* malloc_new_ -- Allocate new object, die if unable
358 ptr = malloc_new_(size_in_bytes);
360 Call malloc, bomb if it returns NULL. */
363 malloc_new_ (mallocSize s
)
368 #if MALLOC_DEBUG && 0
369 assert (s
== (mallocSize
) ss
);/* Else alloc is too big for this
375 memset (ptr
, 126, ss
); /* Catch some kinds of errors more
381 /* malloc_new_inpool_ -- Allocate new object, die if unable
383 ptr = malloc_new_inpool_(NULL,MALLOC_typeUS_,"object",size_in_bytes);
385 Allocate the structure and allocate a mallocArea_ to describe it, then
386 add it to the list of mallocArea_s for the pool. */
389 malloc_new_inpool_ (mallocPool pool
, mallocType_ type
, char *name
, mallocSize s
)
396 pool
= malloc_pool_image ();
399 assert ((pool
== malloc_pool_image ())
400 || malloc_pool_find_ (pool
, malloc_pool_image ()));
403 ptr
= malloc_new_ (s
+ (i
= (MALLOC_DEBUG
? strlen (name
) + 1 : 0)));
405 strcpy (((char *) (ptr
)) + s
, name
);
407 a
= malloc_new_ (offsetof (struct _malloc_area_
, name
) + i
);
409 { /* A little optimization to speed up killing
410 of non-permanent stuff. */
412 case MALLOC_typeKPR_
:
413 a
->next
= (mallocArea_
) &pool
->first
;
417 a
->next
= pool
->first
;
420 a
->previous
= a
->next
->previous
;
421 a
->next
->previous
= a
;
422 a
->previous
->next
= a
;
427 strcpy (a
->name
, name
);
428 pool
->allocated
+= s
;
434 /* malloc_new_zinpool_ -- Allocate new zeroed object, die if unable
436 ptr = malloc_new_zinpool_(NULL,MALLOC_typeUS_,"object",size_in_bytes,0);
438 Like malloc_new_inpool_, but zeros out all the bytes in the area (assuming
442 malloc_new_zinpool_ (mallocPool pool
, mallocType_ type
, char *name
, mallocSize s
,
447 ptr
= malloc_new_inpool_ (pool
, type
, name
, s
);
452 /* malloc_pool_find_ -- See if pool is a descendant of another pool
454 if (malloc_pool_find_(target_pool,parent_pool)) ...;
456 Recursive descent on each of the children of the parent pool, after
457 first checking the children themselves. */
460 malloc_pool_find_ (mallocPool pool
, mallocPool parent
)
464 for (p
= parent
->eldest
; p
!= (mallocPool
) & parent
->eldest
; p
= p
->next
)
466 if ((p
== pool
) || malloc_pool_find_ (pool
, p
))
472 /* malloc_resize_inpool_ -- Resize existing object in pool
474 ptr = malloc_resize_inpool_(NULL,MALLOC_typeUSR_,ptr,new_size,old_size);
476 Find the object's mallocArea_, check it out, then do the resizing. */
479 malloc_resize_inpool_ (mallocPool pool
, mallocType_ type UNUSED
,
480 void *ptr
, mallocSize ns
, mallocSize os UNUSED
)
485 pool
= malloc_pool_image ();
488 assert ((pool
== malloc_pool_image ())
489 || malloc_pool_find_ (pool
, malloc_pool_image ()));
492 a
= malloc_find_inpool_ (pool
, ptr
);
494 assert (a
->type
== type
);
495 if ((type
== MALLOC_typeKSR_
) || (type
== MALLOC_typeKPR_
))
496 assert (a
->size
== os
);
497 assert (strcmp (a
->name
, ((char *) (ptr
)) + os
) == 0);
499 ptr
= malloc_resize_ (ptr
, ns
+ (MALLOC_DEBUG
? strlen (a
->name
) + 1: 0));
503 strcpy (((char *) (ptr
)) + ns
, a
->name
);
504 pool
->old_sizes
+= os
;
505 pool
->new_sizes
+= ns
;
511 /* malloc_resize_ -- Reallocate object, die if unable
513 ptr = malloc_resize_(ptr,size_in_bytes);
515 Call realloc, bomb if it returns NULL. */
518 malloc_resize_ (void *ptr
, mallocSize s
)
522 #if MALLOC_DEBUG && 0
523 assert (s
== (mallocSize
) ss
);/* Too big if failure here. */
526 ptr
= xrealloc (ptr
, ss
);
530 /* malloc_verify_inpool_ -- Verify object
532 Find the mallocArea_ for the pointer, make sure the type is proper, and
533 verify both of them. */
536 malloc_verify_inpool_ (mallocPool pool UNUSED
, mallocType_ type UNUSED
,
537 void *ptr UNUSED
, mallocSize s UNUSED
)
543 pool
= malloc_pool_image ();
545 assert ((pool
== malloc_pool_image ())
546 || malloc_pool_find_ (pool
, malloc_pool_image ()));
548 a
= malloc_find_inpool_ (pool
, ptr
);
549 assert (a
->type
== type
);
550 if ((type
!= MALLOC_typeUS_
) && (type
!= MALLOC_typeUSR_
))
551 assert (a
->size
== s
);
552 malloc_verify_area_ (pool
, a
);