]> Pileus Git - ~andy/gtk/blob - glib/gmem.c
Try to figure out if this is Digital Unix and we need -std1 to get the
[~andy/gtk] / glib / gmem.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19 #include <stdlib.h>
20 #include <string.h>
21 #include "glib.h"
22
23
24 /* #define MEM_PROFILE */
25 /* #define MEM_CHECK */
26
27
28 #define MAX_MEM_AREA  65536L
29 #define MEM_AREA_SIZE 4L
30
31 #if SIZEOF_VOID_P > SIZEOF_LONG
32 #define MEM_ALIGN     SIZEOF_VOID_P
33 #else
34 #define MEM_ALIGN     SIZEOF_LONG
35 #endif
36
37
38 typedef struct _GFreeAtom      GFreeAtom;
39 typedef struct _GMemArea       GMemArea;
40 typedef struct _GRealMemChunk  GRealMemChunk;
41
42 struct _GFreeAtom
43 {
44   GFreeAtom *next;
45 };
46
47 struct _GMemArea
48 {
49   GMemArea *next;            /* the next mem area */
50   GMemArea *prev;            /* the previous mem area */
51   gulong index;              /* the current index into the "mem" array */
52   gulong free;               /* the number of free bytes in this mem area */
53   gulong allocated;          /* the number of atoms allocated from this area */
54   gulong mark;               /* is this mem area marked for deletion */
55   gchar mem[MEM_AREA_SIZE];  /* the mem array from which atoms get allocated
56                               * the actual size of this array is determined by
57                               *  the mem chunk "area_size". ANSI says that it
58                               *  must be declared to be the maximum size it
59                               *  can possibly be (even though the actual size
60                               *  may be less).
61                               */
62 };
63
64 struct _GRealMemChunk
65 {
66   gchar *name;               /* name of this MemChunk...used for debugging output */
67   gint type;                 /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */
68   gint num_mem_areas;        /* the number of memory areas */
69   gint num_marked_areas;     /* the number of areas marked for deletion */
70   guint atom_size;           /* the size of an atom */
71   gulong area_size;          /* the size of a memory area */
72   GMemArea *mem_area;        /* the current memory area */
73   GMemArea *mem_areas;       /* a list of all the mem areas owned by this chunk */
74   GMemArea *free_mem_area;   /* the free area...which is about to be destroyed */
75   GFreeAtom *free_atoms;     /* the free atoms list */
76   GTree *mem_tree;           /* tree of mem areas sorted by memory address */
77   GRealMemChunk *next;       /* pointer to the next chunk */
78   GRealMemChunk *prev;       /* pointer to the previous chunk */
79 };
80
81
82 static gulong g_mem_chunk_compute_size (gulong    size);
83 static gint   g_mem_chunk_area_compare (GMemArea *a,
84                                         GMemArea *b);
85 static gint   g_mem_chunk_area_search  (GMemArea *a,
86                                         gchar    *addr);
87
88
89 static GRealMemChunk *mem_chunks = NULL;
90
91 #ifdef MEM_PROFILE
92 static gulong allocations[4096] = { 0 };
93 static gulong allocated_mem = 0;
94 static gulong freed_mem = 0;
95 #endif /* MEM_PROFILE */
96
97
98 #ifndef USE_DMALLOC
99
100 gpointer
101 g_malloc (gulong size)
102 {
103   gpointer p;
104
105
106 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
107   gulong *t;
108 #endif /* MEM_PROFILE || MEM_CHECK */
109
110
111   if (size == 0)
112     return NULL;
113
114
115 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
116   size += SIZEOF_LONG;
117 #endif /* MEM_PROFILE || MEM_CHECK */
118
119 #ifdef MEM_CHECK
120   size += SIZEOF_LONG;
121 #endif /* MEM_CHECK */
122
123
124   p = (gpointer) malloc (size);
125   if (!p)
126     g_error ("could not allocate %ld bytes", size);
127
128
129 #ifdef MEM_CHECK
130   size -= SIZEOF_LONG;
131
132   t = p;
133   p = ((guchar*) p + SIZEOF_LONG);
134   *t = 0;
135 #endif /* MEM_CHECK */
136
137 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
138   size -= SIZEOF_LONG;
139
140   t = p;
141   p = ((guchar*) p + SIZEOF_LONG);
142   *t = size;
143
144 #ifdef MEM_PROFILE
145   if (size <= 4095)
146     allocations[size-1] += 1;
147   else
148     allocations[4095] += 1;
149   allocated_mem += size;
150 #endif /* MEM_PROFILE */
151 #endif /* MEM_PROFILE || MEM_CHECK */
152
153
154   return p;
155 }
156
157 gpointer
158 g_malloc0 (gulong size)
159 {
160   gpointer p;
161
162
163 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
164   gulong *t;
165 #endif /* MEM_PROFILE || MEM_CHECK */
166
167
168   if (size == 0)
169     return NULL;
170
171
172 #ifdef MEM_PROFILE
173   size += SIZEOF_LONG;
174 #endif /* MEM_PROFILE */
175
176 #ifdef MEM_CHECK
177   size += SIZEOF_LONG;
178 #endif /* MEM_CHECK */
179
180
181   p = (gpointer) calloc (size, 1);
182   if (!p)
183     g_error ("could not allocate %ld bytes", size);
184
185
186 #ifdef MEM_CHECK
187   size -= SIZEOF_LONG;
188
189   t = p;
190   p = ((guchar*) p + SIZEOF_LONG);
191   *t = 0;
192 #endif /* MEM_CHECK */
193
194 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
195   size -= SIZEOF_LONG;
196
197   t = p;
198   p = ((guchar*) p + SIZEOF_LONG);
199   *t = size;
200
201 #ifdef MEM_PROFILE
202   if (size <= 4095)
203     allocations[size-1] += 1;
204   else
205     allocations[4095] += 1;
206   allocated_mem += size;
207 #endif /* MEM_PROFILE */
208 #endif /* MEM_PROFILE */
209
210
211   return p;
212 }
213
214 gpointer
215 g_realloc (gpointer mem,
216            gulong   size)
217 {
218   gpointer p;
219
220 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
221   gulong *t;
222 #endif /* MEM_PROFILE || MEM_CHECK */
223
224
225   if (size == 0)
226     return NULL;
227
228
229 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
230   size += SIZEOF_LONG;
231 #endif /* MEM_PROFILE || MEM_CHECK */
232
233 #ifdef MEM_CHECK
234   size += SIZEOF_LONG;
235 #endif /* MEM_CHECK */
236
237
238   if (!mem)
239     p = (gpointer) malloc (size);
240   else
241     {
242 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
243       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
244 #ifdef MEM_PROFILE
245       freed_mem += *t;
246 #endif /* MEM_PROFILE */
247       mem = t;
248 #endif /* MEM_PROFILE || MEM_CHECK */
249
250 #ifdef MEM_CHECK
251       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
252       if (*t >= 1)
253         g_warning ("trying to realloc freed memory\n");
254       mem = t;
255 #endif /* MEM_CHECK */
256
257       p = (gpointer) realloc (mem, size);
258     }
259
260   if (!p)
261     g_error ("could not reallocate %ld bytes", size);
262
263
264 #ifdef MEM_CHECK
265   size -= SIZEOF_LONG;
266
267   t = p;
268   p = ((guchar*) p + SIZEOF_LONG);
269   *t = 0;
270 #endif /* MEM_CHECK */
271
272 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
273   size -= SIZEOF_LONG;
274
275   t = p;
276   p = ((guchar*) p + SIZEOF_LONG);
277   *t = size;
278
279 #ifdef MEM_PROFILE
280   if (size <= 4095)
281     allocations[size-1] += 1;
282   else
283     allocations[4095] += 1;
284   allocated_mem += size;
285 #endif /* MEM_PROFILE */
286 #endif /* MEM_PROFILE || MEM_CHECK */
287
288
289   return p;
290 }
291
292 void
293 g_free (gpointer mem)
294 {
295   if (mem)
296     {
297 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
298       gulong *t;
299       gulong size;
300 #endif /* MEM_PROFILE || MEM_CHECK */
301
302 #if defined(MEM_PROFILE) || defined(MEM_CHECK)
303       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
304       size = *t;
305 #ifdef MEM_PROFILE
306       freed_mem += size;
307 #endif /* MEM_PROFILE */
308       mem = t;
309 #endif /* MEM_PROFILE || MEM_CHECK */
310
311 #ifdef MEM_CHECK
312       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
313       if (*t >= 1)
314         g_warning ("freeing previously freed memory\n");
315       *t += 1;
316       mem = t;
317
318       memset ((guchar*) mem + 8, 0, size);
319 #else /* MEM_CHECK */
320       free (mem);
321 #endif /* MEM_CHECK */
322     }
323 }
324
325 #endif /* ! USE_DMALLOC */
326
327
328 void
329 g_mem_profile (void)
330 {
331 #ifdef MEM_PROFILE
332   gint i;
333
334   for (i = 0; i < 4095; i++)
335     if (allocations[i] > 0)
336       g_print ("%lu allocations of %d bytes\n", allocations[i], i + 1);
337
338   if (allocations[4095] > 0)
339     g_print ("%lu allocations of greater than 4095 bytes\n", allocations[4095]);
340   g_print ("%lu bytes allocated\n", allocated_mem);
341   g_print ("%lu bytes freed\n", freed_mem);
342   g_print ("%lu bytes in use\n", allocated_mem - freed_mem);
343 #endif /* MEM_PROFILE */
344 }
345
346 void
347 g_mem_check (gpointer mem)
348 {
349 #ifdef MEM_CHECK
350   gulong *t;
351
352   t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG);
353
354   if (*t >= 1)
355     g_warning ("mem: 0x%08x has been freed: %lu\n", (gulong) mem, *t);
356 #endif /* MEM_CHECK */
357 }
358
359 GMemChunk*
360 g_mem_chunk_new (gchar  *name,
361                  gint    atom_size,
362                  gulong  area_size,
363                  gint    type)
364 {
365   GRealMemChunk *mem_chunk;
366   gulong rarea_size;
367
368   mem_chunk = g_new (struct _GRealMemChunk, 1);
369   mem_chunk->name = name;
370   mem_chunk->type = type;
371   mem_chunk->num_mem_areas = 0;
372   mem_chunk->num_marked_areas = 0;
373   mem_chunk->mem_area = NULL;
374   mem_chunk->free_mem_area = NULL;
375   mem_chunk->free_atoms = NULL;
376   mem_chunk->mem_tree = NULL;
377   mem_chunk->mem_areas = NULL;
378   mem_chunk->atom_size = atom_size;
379
380   if (mem_chunk->type == G_ALLOC_AND_FREE)
381     mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
382
383   if (mem_chunk->atom_size % MEM_ALIGN)
384     mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN);
385
386   mem_chunk->area_size = area_size;
387   if (mem_chunk->area_size > MAX_MEM_AREA)
388     mem_chunk->area_size = MAX_MEM_AREA;
389   while (mem_chunk->area_size < mem_chunk->atom_size)
390     mem_chunk->area_size *= 2;
391
392   rarea_size = mem_chunk->area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
393   rarea_size = g_mem_chunk_compute_size (rarea_size);
394   mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
395
396   /*
397   mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE);
398   if (mem_chunk->area_size < mem_chunk->atom_size)
399     {
400       mem_chunk->area_size = (mem_chunk->area_size + sizeof (GMemArea) - MEM_AREA_SIZE) * 2;
401       mem_chunk->area_size -= (sizeof (GMemArea) - MEM_AREA_SIZE);
402     }
403
404   if (mem_chunk->area_size % mem_chunk->atom_size)
405     mem_chunk->area_size += mem_chunk->atom_size - (mem_chunk->area_size % mem_chunk->atom_size);
406     */
407
408   mem_chunk->next = mem_chunks;
409   mem_chunk->prev = NULL;
410   if (mem_chunks)
411     mem_chunks->prev = mem_chunk;
412   mem_chunks = mem_chunk;
413
414   return ((GMemChunk*) mem_chunk);
415 }
416
417 void
418 g_mem_chunk_destroy (GMemChunk *mem_chunk)
419 {
420   GRealMemChunk *rmem_chunk;
421   GMemArea *mem_areas;
422   GMemArea *temp_area;
423
424   g_assert (mem_chunk != NULL);
425
426   rmem_chunk = (GRealMemChunk*) mem_chunk;
427
428   mem_areas = rmem_chunk->mem_areas;
429   while (mem_areas)
430     {
431       temp_area = mem_areas;
432       mem_areas = mem_areas->next;
433       g_free (temp_area);
434     }
435
436   if (rmem_chunk->next)
437     rmem_chunk->next->prev = rmem_chunk->prev;
438   if (rmem_chunk->prev)
439     rmem_chunk->prev->next = rmem_chunk->next;
440
441   if (rmem_chunk == mem_chunks)
442     mem_chunks = mem_chunks->next;
443
444   if (rmem_chunk->type == G_ALLOC_AND_FREE)
445     g_tree_destroy (rmem_chunk->mem_tree);
446
447   g_free (rmem_chunk);
448 }
449
450 gpointer
451 g_mem_chunk_alloc (GMemChunk *mem_chunk)
452 {
453   GRealMemChunk *rmem_chunk;
454   GMemArea *temp_area;
455   gpointer mem;
456
457   g_assert (mem_chunk != NULL);
458
459   rmem_chunk = (GRealMemChunk*) mem_chunk;
460
461   while (rmem_chunk->free_atoms)
462     {
463       /* Get the first piece of memory on the "free_atoms" list.
464        * We can go ahead and destroy the list node we used to keep
465        *  track of it with and to update the "free_atoms" list to
466        *  point to its next element.
467        */
468       mem = rmem_chunk->free_atoms;
469       rmem_chunk->free_atoms = rmem_chunk->free_atoms->next;
470
471       /* Determine which area this piece of memory is allocated from */
472       temp_area = g_tree_search (rmem_chunk->mem_tree,
473                                  (GSearchFunc) g_mem_chunk_area_search,
474                                  mem);
475
476       /* If the area has been marked, then it is being destroyed.
477        *  (ie marked to be destroyed).
478        * We check to see if all of the segments on the free list that
479        *  reference this area have been removed. This occurs when
480        *  the ammount of free memory is less than the allocatable size.
481        * If the chunk should be freed, then we place it in the "free_mem_area".
482        * This is so we make sure not to free the mem area here and then
483        *  allocate it again a few lines down.
484        * If we don't allocate a chunk a few lines down then the "free_mem_area"
485        *  will be freed.
486        * If there is already a "free_mem_area" then we'll just free this mem area.
487        */
488       if (temp_area->mark)
489         {
490           /* Update the "free" memory available in that area */
491           temp_area->free += rmem_chunk->atom_size;
492
493           if (temp_area->free == rmem_chunk->area_size)
494             {
495               if (temp_area == rmem_chunk->mem_area)
496                 rmem_chunk->mem_area = NULL;
497
498               if (rmem_chunk->free_mem_area)
499                 {
500                   rmem_chunk->num_mem_areas -= 1;
501
502                   if (temp_area->next)
503                     temp_area->next->prev = temp_area->prev;
504                   if (temp_area->prev)
505                     temp_area->prev->next = temp_area->next;
506                   if (temp_area == rmem_chunk->mem_areas)
507                     rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
508
509                   if (rmem_chunk->type == G_ALLOC_AND_FREE)
510                     g_tree_remove (rmem_chunk->mem_tree, temp_area);
511                   g_free (temp_area);
512                 }
513               else
514                 rmem_chunk->free_mem_area = temp_area;
515               
516               rmem_chunk->num_marked_areas -= 1;
517             }
518         }
519       else
520         {
521           /* Update the number of allocated atoms count.
522            */
523           temp_area->allocated += 1;
524
525           /* The area wasn't marked...return the memory
526            */
527           goto outa_here;
528         }
529     }
530
531   /* If there isn't a current mem area or the current mem area is out of space
532    *  then allocate a new mem area. We'll first check and see if we can use
533    *  the "free_mem_area". Otherwise we'll just malloc the mem area.
534    */
535   if ((!rmem_chunk->mem_area) ||
536       ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size))
537     {
538       if (rmem_chunk->free_mem_area)
539         {
540           rmem_chunk->mem_area = rmem_chunk->free_mem_area;
541           rmem_chunk->free_mem_area = NULL;
542         }
543       else
544         {
545           rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
546                                                        MEM_AREA_SIZE +
547                                                        rmem_chunk->area_size);
548
549           rmem_chunk->num_mem_areas += 1;
550           rmem_chunk->mem_area->next = rmem_chunk->mem_areas;
551           rmem_chunk->mem_area->prev = NULL;
552
553           if (rmem_chunk->mem_areas)
554             rmem_chunk->mem_areas->prev = rmem_chunk->mem_area;
555           rmem_chunk->mem_areas = rmem_chunk->mem_area;
556
557           if (rmem_chunk->type == G_ALLOC_AND_FREE)
558             g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area);
559         }
560
561       rmem_chunk->mem_area->index = 0;
562       rmem_chunk->mem_area->free = rmem_chunk->area_size;
563       rmem_chunk->mem_area->allocated = 0;
564       rmem_chunk->mem_area->mark = 0;
565     }
566
567   /* Get the memory and modify the state variables appropriately.
568    */
569   mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index];
570   rmem_chunk->mem_area->index += rmem_chunk->atom_size;
571   rmem_chunk->mem_area->free -= rmem_chunk->atom_size;
572   rmem_chunk->mem_area->allocated += 1;
573
574 outa_here:
575   return mem;
576 }
577
578 void
579 g_mem_chunk_free (GMemChunk *mem_chunk,
580                   gpointer   mem)
581 {
582   GRealMemChunk *rmem_chunk;
583   GMemArea *temp_area;
584   GFreeAtom *free_atom;
585
586   g_assert (mem_chunk != NULL);
587   g_assert (mem != NULL);
588
589   rmem_chunk = (GRealMemChunk*) mem_chunk;
590
591   /* Don't do anything if this is an ALLOC_ONLY chunk
592    */
593   if (rmem_chunk->type == G_ALLOC_AND_FREE)
594     {
595       /* Place the memory on the "free_atoms" list
596        */
597       free_atom = (GFreeAtom*) mem;
598       free_atom->next = rmem_chunk->free_atoms;
599       rmem_chunk->free_atoms = free_atom;
600
601       temp_area = g_tree_search (rmem_chunk->mem_tree,
602                                  (GSearchFunc) g_mem_chunk_area_search,
603                                  mem);
604
605       temp_area->allocated -= 1;
606
607       if (temp_area->allocated == 0)
608         {
609           temp_area->mark = 1;
610           rmem_chunk->num_marked_areas += 1;
611         }
612     }
613 }
614
615 /* This doesn't free the free_area if there is one */
616 void
617 g_mem_chunk_clean (GMemChunk *mem_chunk)
618 {
619   GRealMemChunk *rmem_chunk;
620   GMemArea *mem_area;
621   GFreeAtom *prev_free_atom;
622   GFreeAtom *temp_free_atom;
623   gpointer mem;
624
625   g_assert (mem_chunk != NULL);
626
627   rmem_chunk = (GRealMemChunk*) mem_chunk;
628
629   if (rmem_chunk->type == G_ALLOC_AND_FREE)
630     {
631       prev_free_atom = NULL;
632       temp_free_atom = rmem_chunk->free_atoms;
633
634       while (temp_free_atom)
635         {
636           mem = (gpointer) temp_free_atom;
637
638           mem_area = g_tree_search (rmem_chunk->mem_tree,
639                                     (GSearchFunc) g_mem_chunk_area_search,
640                                     mem);
641
642           /* If this mem area is marked for destruction then delete the
643            *  area and list node and decrement the free mem.
644            */
645           if (mem_area->mark)
646             {
647               if (prev_free_atom)
648                 prev_free_atom->next = temp_free_atom->next;
649               else
650                 rmem_chunk->free_atoms = temp_free_atom->next;
651               temp_free_atom = temp_free_atom->next;
652
653               mem_area->free += rmem_chunk->atom_size;
654               if (mem_area->free == rmem_chunk->area_size)
655                 {
656                   rmem_chunk->num_mem_areas -= 1;
657                   rmem_chunk->num_marked_areas -= 1;
658
659                   if (mem_area->next)
660                     mem_area->next->prev = mem_area->prev;
661                   if (mem_area->prev)
662                     mem_area->prev->next = mem_area->next;
663                   if (mem_area == rmem_chunk->mem_areas)
664                     rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
665                   if (mem_area == rmem_chunk->mem_area)
666                     rmem_chunk->mem_area = NULL;
667
668                   if (rmem_chunk->type == G_ALLOC_AND_FREE)
669                     g_tree_remove (rmem_chunk->mem_tree, mem_area);
670                   g_free (mem_area);
671                 }
672             }
673           else
674             {
675               prev_free_atom = temp_free_atom;
676               temp_free_atom = temp_free_atom->next;
677             }
678         }
679     }
680 }
681
682 void
683 g_mem_chunk_reset (GMemChunk *mem_chunk)
684 {
685   GRealMemChunk *rmem_chunk;
686   GMemArea *mem_areas;
687   GMemArea *temp_area;
688
689   g_assert (mem_chunk != NULL);
690
691   rmem_chunk = (GRealMemChunk*) mem_chunk;
692
693   mem_areas = rmem_chunk->mem_areas;
694   rmem_chunk->num_mem_areas = 0;
695   rmem_chunk->mem_areas = NULL;
696   rmem_chunk->mem_area = NULL;
697
698   while (mem_areas)
699     {
700       temp_area = mem_areas;
701       mem_areas = mem_areas->next;
702       g_free (temp_area);
703     }
704
705   rmem_chunk->free_atoms = NULL;
706
707   if (rmem_chunk->mem_tree)
708     g_tree_destroy (rmem_chunk->mem_tree);
709   rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
710 }
711
712 void
713 g_mem_chunk_print (GMemChunk *mem_chunk)
714 {
715   GRealMemChunk *rmem_chunk;
716   GMemArea *mem_areas;
717   gulong mem;
718
719   g_assert (mem_chunk != NULL);
720
721   rmem_chunk = (GRealMemChunk*) mem_chunk;
722   mem_areas = rmem_chunk->mem_areas;
723   mem = 0;
724
725   while (mem_areas)
726     {
727       mem += rmem_chunk->area_size - mem_areas->free;
728       mem_areas = mem_areas->next;
729     }
730
731   g_print ("%s: %ld bytes using %d mem areas", rmem_chunk->name, mem, rmem_chunk->num_mem_areas);
732 }
733
734 void
735 g_mem_chunk_info (void)
736 {
737   GRealMemChunk *mem_chunk;
738   gint count;
739
740   count = 0;
741   mem_chunk = mem_chunks;
742   while (mem_chunk)
743     {
744       count += 1;
745       mem_chunk = mem_chunk->next;
746     }
747
748   g_print ("%d mem chunks", count);
749
750   mem_chunk = mem_chunks;
751   while (mem_chunk)
752     {
753       g_mem_chunk_print ((GMemChunk*) mem_chunk);
754       mem_chunk = mem_chunk->next;
755     }
756 }
757
758 void
759 g_blow_chunks (void)
760 {
761   GRealMemChunk *mem_chunk;
762
763   mem_chunk = mem_chunks;
764   while (mem_chunk)
765     {
766       g_mem_chunk_clean ((GMemChunk*) mem_chunk);
767       mem_chunk = mem_chunk->next;
768     }
769 }
770
771
772 static gulong
773 g_mem_chunk_compute_size (gulong size)
774 {
775   gulong power_of_2;
776   gulong lower, upper;
777
778   power_of_2 = 16;
779   while (power_of_2 < size)
780     power_of_2 <<= 1;
781
782   lower = power_of_2 >> 1;
783   upper = power_of_2;
784
785   if ((size - lower) < (upper - size))
786     return lower;
787   return upper;
788 }
789
790 static gint
791 g_mem_chunk_area_compare (GMemArea *a,
792                           GMemArea *b)
793 {
794   return (a->mem - b->mem);
795 }
796
797 static gint
798 g_mem_chunk_area_search (GMemArea *a,
799                          gchar    *addr)
800 {
801   if (a->mem <= addr)
802     {
803       if (addr < &a->mem[a->index])
804         return 0;
805       return 1;
806     }
807   return -1;
808 }