Main Page | Class List | Directories | File List | Class Members | File Members

gmem.c

Go to the documentation of this file.
00001 /* GLIB - Library of useful routines for C programming
00002  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
00003  *
00004  * This library is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU Library General Public
00006  * License as published by the Free Software Foundation; either
00007  * version 2 of the License, or (at your option) any later version.
00008  *
00009  * This library is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * Library General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU Library General Public
00015  * License along with this library; if not, write to the
00016  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00017  * Boston, MA 02111-1307, USA.
00018  */
00019 
00020 /*
00021  * Modified by the GLib Team and others 1997-1999.  See the AUTHORS
00022  * file for a list of people on the GLib Team.  See the ChangeLog
00023  * files for a list of changes.  These files are distributed with
00024  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
00025  */
00026 
00027 /* 
00028  * MT safe
00029  */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034 
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include "glib.h"
00038 
00039 /* #define ENABLE_MEM_PROFILE */
00040 /* #define ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS */
00041 /* #define ENABLE_MEM_CHECK */
00042 #define MEM_PROFILE_TABLE_SIZE 8192
00043 
00044 /*
00045  * This library can check for some attempts to do illegal things to
00046  * memory (ENABLE_MEM_CHECK), and can do profiling
00047  * (ENABLE_MEM_PROFILE).  Both features are implemented by storing
00048  * words before the start of the memory chunk.
00049  *
00050  * The first, at offset -2*SIZEOF_LONG, is used only if
00051  * ENABLE_MEM_CHECK is set, and stores 0 after the memory has been
00052  * allocated and 1 when it has been freed.  The second, at offset
00053  * -SIZEOF_LONG, is used if either flag is set and stores the size of
00054  * the block.
00055  *
00056  * The MEM_CHECK flag is checked when memory is realloc'd and free'd,
00057  * and it can be explicitly checked before using a block by calling
00058  * g_mem_check().
00059  */
00060 
00061 #if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS)
00062 #define ENTER_MEM_CHUNK_ROUTINE() \
00063   g_private_set (allocating_for_mem_chunk, \
00064                 g_private_get (allocating_for_mem_chunk) + 1)
00065 #define LEAVE_MEM_CHUNK_ROUTINE() \
00066   g_private_set (allocating_for_mem_chunk, \
00067                 g_private_get (allocating_for_mem_chunk) - 1) 
00068 #else
00069 #define ENTER_MEM_CHUNK_ROUTINE()
00070 #define LEAVE_MEM_CHUNK_ROUTINE()
00071 #endif
00072 
00073 
00074 #define MEM_AREA_SIZE 4L
00075 
00076 #if SIZEOF_VOID_P > SIZEOF_LONG
00077 #define MEM_ALIGN     SIZEOF_VOID_P
00078 #else
00079 #define MEM_ALIGN     SIZEOF_LONG
00080 #endif
00081 
00082 
00083 typedef struct _GFreeAtom      GFreeAtom;
00084 typedef struct _GMemArea       GMemArea;
00085 typedef struct _GRealMemChunk  GRealMemChunk;
00086 
00087 struct _GFreeAtom
00088 {
00089   GFreeAtom *next;
00090 };
00091 
00092 struct _GMemArea
00093 {
00094   GMemArea *next;            /* the next mem area */
00095   GMemArea *prev;            /* the previous mem area */
00096   gulong index;              /* the current index into the "mem" array */
00097   gulong free;               /* the number of free bytes in this mem area */
00098   gulong allocated;          /* the number of atoms allocated from this area */
00099   gulong mark;               /* is this mem area marked for deletion */
00100   gchar mem[MEM_AREA_SIZE];  /* the mem array from which atoms get allocated
00101                               * the actual size of this array is determined by
00102                               *  the mem chunk "area_size". ANSI says that it
00103                               *  must be declared to be the maximum size it
00104                               *  can possibly be (even though the actual size
00105                               *  may be less).
00106                               */
00107 };
00108 
00109 struct _GRealMemChunk
00110 {
00111   gchar *name;               /* name of this MemChunk...used for debugging output */
00112   gint type;                 /* the type of MemChunk: ALLOC_ONLY or ALLOC_AND_FREE */
00113   gint num_mem_areas;        /* the number of memory areas */
00114   gint num_marked_areas;     /* the number of areas marked for deletion */
00115   guint atom_size;           /* the size of an atom */
00116   gulong area_size;          /* the size of a memory area */
00117   GMemArea *mem_area;        /* the current memory area */
00118   GMemArea *mem_areas;       /* a list of all the mem areas owned by this chunk */
00119   GMemArea *free_mem_area;   /* the free area...which is about to be destroyed */
00120   GFreeAtom *free_atoms;     /* the free atoms list */
00121   GTree *mem_tree;           /* tree of mem areas sorted by memory address */
00122   GRealMemChunk *next;       /* pointer to the next chunk */
00123   GRealMemChunk *prev;       /* pointer to the previous chunk */
00124 };
00125 
00126 
00127 static gulong g_mem_chunk_compute_size (gulong    size,
00128                                         gulong    min_size);
00129 static gint   g_mem_chunk_area_compare (GMemArea *a,
00130                                         GMemArea *b);
00131 static gint   g_mem_chunk_area_search  (GMemArea *a,
00132                                         gchar    *addr);
00133 
00134 
00135 /* here we can't use StaticMutexes, as they depend upon a working
00136  * g_malloc, the same holds true for StaticPrivate */
00137 static GMutex* mem_chunks_lock = NULL;
00138 static GRealMemChunk *mem_chunks = NULL;
00139 
00140 #ifdef ENABLE_MEM_PROFILE
00141 static GMutex* mem_profile_lock;
00142 static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 };
00143 static gulong allocated_mem = 0;
00144 static gulong freed_mem = 0;
00145 static GPrivate* allocating_for_mem_chunk = NULL;
00146 #define IS_IN_MEM_CHUNK_ROUTINE() \
00147   GPOINTER_TO_UINT (g_private_get (allocating_for_mem_chunk))
00148 #endif /* ENABLE_MEM_PROFILE */
00149 
00150 
00151 #ifndef USE_DMALLOC
00152 
00153 gpointer
00154 g_malloc (gulong size)
00155 {
00156   gpointer p;
00157   
00158   
00159 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00160   gulong *t;
00161 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00162   
00163   
00164   if (size == 0)
00165     return NULL;
00166   
00167   
00168 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00169   size += SIZEOF_LONG;
00170 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00171   
00172 #ifdef ENABLE_MEM_CHECK
00173   size += SIZEOF_LONG;
00174 #endif /* ENABLE_MEM_CHECK */
00175   
00176   
00177   p = (gpointer) malloc (size);
00178   if (!p)
00179     g_error ("could not allocate %ld bytes", size);
00180   
00181   
00182 #ifdef ENABLE_MEM_CHECK
00183   size -= SIZEOF_LONG;
00184   
00185   t = p;
00186   p = ((guchar*) p + SIZEOF_LONG);
00187   *t = 0;
00188 #endif /* ENABLE_MEM_CHECK */
00189   
00190 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00191   size -= SIZEOF_LONG;
00192   
00193   t = p;
00194   p = ((guchar*) p + SIZEOF_LONG);
00195   *t = size;
00196   
00197 #ifdef ENABLE_MEM_PROFILE
00198   g_mutex_lock (mem_profile_lock);
00199 #  ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00200   if(!IS_IN_MEM_CHUNK_ROUTINE()) {
00201 #  endif
00202     if (size <= MEM_PROFILE_TABLE_SIZE - 1)
00203       allocations[size-1] += 1;
00204     else
00205       allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
00206     allocated_mem += size;
00207 #  ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00208   }
00209 #  endif
00210   g_mutex_unlock (mem_profile_lock);
00211 #endif /* ENABLE_MEM_PROFILE */
00212 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00213   
00214   
00215   return p;
00216 }
00217 
00218 gpointer
00219 g_malloc0 (gulong size)
00220 {
00221   gpointer p;
00222   
00223   
00224 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00225   gulong *t;
00226 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00227   
00228   
00229   if (size == 0)
00230     return NULL;
00231   
00232   
00233 #if defined (ENABLE_MEM_PROFILE) || defined (ENABLE_MEM_CHECK)
00234   size += SIZEOF_LONG;
00235 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00236   
00237 #ifdef ENABLE_MEM_CHECK
00238   size += SIZEOF_LONG;
00239 #endif /* ENABLE_MEM_CHECK */
00240   
00241   
00242   p = (gpointer) calloc (size, 1);
00243   if (!p)
00244     g_error ("could not allocate %ld bytes", size);
00245   
00246   
00247 #ifdef ENABLE_MEM_CHECK
00248   size -= SIZEOF_LONG;
00249   
00250   t = p;
00251   p = ((guchar*) p + SIZEOF_LONG);
00252   *t = 0;
00253 #endif /* ENABLE_MEM_CHECK */
00254   
00255 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00256   size -= SIZEOF_LONG;
00257   
00258   t = p;
00259   p = ((guchar*) p + SIZEOF_LONG);
00260   *t = size;
00261   
00262 #  ifdef ENABLE_MEM_PROFILE
00263   g_mutex_lock (mem_profile_lock);
00264 #    ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00265   if(!IS_IN_MEM_CHUNK_ROUTINE()) {
00266 #    endif
00267     if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
00268       allocations[size-1] += 1;
00269     else
00270       allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
00271     allocated_mem += size;
00272 #    ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00273   }
00274 #    endif
00275   g_mutex_unlock (mem_profile_lock);
00276 #  endif /* ENABLE_MEM_PROFILE */
00277 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00278   
00279   
00280   return p;
00281 }
00282 
00283 gpointer
00284 g_realloc (gpointer mem,
00285            gulong   size)
00286 {
00287   gpointer p;
00288   
00289 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00290   gulong *t;
00291 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00292   
00293   
00294   if (size == 0)
00295     {
00296       g_free (mem);
00297     
00298       return NULL;
00299     }
00300   
00301   
00302 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00303   size += SIZEOF_LONG;
00304 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00305   
00306 #ifdef ENABLE_MEM_CHECK
00307   size += SIZEOF_LONG;
00308 #endif /* ENABLE_MEM_CHECK */
00309   
00310   
00311   if (!mem)
00312     {
00313 #ifdef REALLOC_0_WORKS
00314       p = (gpointer) realloc (NULL, size);
00315 #else /* !REALLOC_0_WORKS */
00316       p = (gpointer) malloc (size);
00317 #endif /* !REALLOC_0_WORKS */
00318     }
00319   else
00320     {
00321 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00322       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00323 #ifdef ENABLE_MEM_PROFILE
00324       g_mutex_lock (mem_profile_lock);
00325       freed_mem += *t;
00326       g_mutex_unlock (mem_profile_lock);
00327 #endif /* ENABLE_MEM_PROFILE */
00328       mem = t;
00329 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00330       
00331 #ifdef ENABLE_MEM_CHECK
00332       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00333       if (*t >= 1)
00334         g_warning ("trying to realloc freed memory\n");
00335       mem = t;
00336 #endif /* ENABLE_MEM_CHECK */
00337       
00338       p = (gpointer) realloc (mem, size);
00339     }
00340   
00341   if (!p)
00342     g_error ("could not reallocate %lu bytes", (gulong) size);
00343   
00344   
00345 #ifdef ENABLE_MEM_CHECK
00346   size -= SIZEOF_LONG;
00347   
00348   t = p;
00349   p = ((guchar*) p + SIZEOF_LONG);
00350   *t = 0;
00351 #endif /* ENABLE_MEM_CHECK */
00352   
00353 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00354   size -= SIZEOF_LONG;
00355   
00356   t = p;
00357   p = ((guchar*) p + SIZEOF_LONG);
00358   *t = size;
00359   
00360 #ifdef ENABLE_MEM_PROFILE
00361   g_mutex_lock (mem_profile_lock);
00362 #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00363   if(!IS_IN_MEM_CHUNK_ROUTINE()) {
00364 #endif
00365     if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
00366       allocations[size-1] += 1;
00367     else
00368       allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
00369     allocated_mem += size;
00370 #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00371   }
00372 #endif
00373   g_mutex_unlock (mem_profile_lock);
00374 #endif /* ENABLE_MEM_PROFILE */
00375 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00376   
00377   
00378   return p;
00379 }
00380 
00381 void
00382 g_free (gpointer mem)
00383 {
00384   if (mem)
00385     {
00386 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00387       gulong *t;
00388       gulong size;
00389 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00390       
00391 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00392       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00393       size = *t;
00394 #ifdef ENABLE_MEM_PROFILE     
00395       g_mutex_lock (mem_profile_lock);
00396       freed_mem += size;
00397       g_mutex_unlock (mem_profile_lock);
00398 #endif /* ENABLE_MEM_PROFILE */
00399       mem = t;
00400 #endif /* ENABLE_MEM_PROFILE || ENABLE_MEM_CHECK */
00401       
00402 #ifdef ENABLE_MEM_CHECK
00403       t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00404       if (*t >= 1)
00405         g_warning ("freeing previously freed (%lu times) memory\n", *t);
00406       *t += 1;
00407       mem = t;
00408       
00409       memset ((guchar*) mem + 2 * SIZEOF_LONG, 0, size);
00410 #else /* ENABLE_MEM_CHECK */
00411       free (mem);
00412 #endif /* ENABLE_MEM_CHECK */
00413     }
00414 }
00415 
00416 #endif /* ! USE_DMALLOC */
00417 
00418 
00419 void
00420 g_mem_profile (void)
00421 {
00422 #ifdef ENABLE_MEM_PROFILE
00423   gint i;
00424   gulong local_allocations[MEM_PROFILE_TABLE_SIZE];
00425   gulong local_allocated_mem;
00426   gulong local_freed_mem;  
00427 
00428   g_mutex_lock (mem_profile_lock);
00429   for (i = 0; i < MEM_PROFILE_TABLE_SIZE; i++)
00430     local_allocations[i] = allocations[i];
00431   local_allocated_mem = allocated_mem;
00432   local_freed_mem = freed_mem;
00433   g_mutex_unlock (mem_profile_lock);
00434 
00435   for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
00436     if (local_allocations[i] > 0)
00437       g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
00438              "%lu allocations of %d bytes", local_allocations[i], i + 1);
00439   
00440   if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
00441     g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
00442            "%lu allocations of greater than %d bytes",
00443            local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
00444   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated", local_allocated_mem);
00445   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed", local_freed_mem);
00446   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use", local_allocated_mem - local_freed_mem);
00447 #endif /* ENABLE_MEM_PROFILE */
00448 }
00449 
00450 void
00451 g_mem_check (gpointer mem)
00452 {
00453 #ifdef ENABLE_MEM_CHECK
00454   gulong *t;
00455   
00456   t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG);
00457   
00458   if (*t >= 1)
00459     g_warning ("mem: 0x%08lx has been freed %lu times\n", (gulong) mem, *t);
00460 #endif /* ENABLE_MEM_CHECK */
00461 }
00462 
00463 GMemChunk*
00464 g_mem_chunk_new (gchar  *name,
00465                  gint    atom_size,
00466                  gulong  area_size,
00467                  gint    type)
00468 {
00469   GRealMemChunk *mem_chunk;
00470   gulong rarea_size;
00471 
00472   g_return_val_if_fail (atom_size > 0, NULL);
00473   g_return_val_if_fail (area_size >= atom_size, NULL);
00474 
00475   ENTER_MEM_CHUNK_ROUTINE();
00476 
00477   area_size = (area_size + atom_size - 1) / atom_size;
00478   area_size *= atom_size;
00479 
00480   mem_chunk = g_new (struct _GRealMemChunk, 1);
00481   mem_chunk->name = name;
00482   mem_chunk->type = type;
00483   mem_chunk->num_mem_areas = 0;
00484   mem_chunk->num_marked_areas = 0;
00485   mem_chunk->mem_area = NULL;
00486   mem_chunk->free_mem_area = NULL;
00487   mem_chunk->free_atoms = NULL;
00488   mem_chunk->mem_tree = NULL;
00489   mem_chunk->mem_areas = NULL;
00490   mem_chunk->atom_size = atom_size;
00491   
00492   if (mem_chunk->type == G_ALLOC_AND_FREE)
00493     mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
00494   
00495   if (mem_chunk->atom_size % MEM_ALIGN)
00496     mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN);
00497 
00498   rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
00499   rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
00500   mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
00501 
00502   g_mutex_lock (mem_chunks_lock);
00503   mem_chunk->next = mem_chunks;
00504   mem_chunk->prev = NULL;
00505   if (mem_chunks)
00506     mem_chunks->prev = mem_chunk;
00507   mem_chunks = mem_chunk;
00508   g_mutex_unlock (mem_chunks_lock);
00509 
00510   LEAVE_MEM_CHUNK_ROUTINE();
00511 
00512   return ((GMemChunk*) mem_chunk);
00513 }
00514 
00515 void
00516 g_mem_chunk_destroy (GMemChunk *mem_chunk)
00517 {
00518   GRealMemChunk *rmem_chunk;
00519   GMemArea *mem_areas;
00520   GMemArea *temp_area;
00521   
00522   g_return_if_fail (mem_chunk != NULL);
00523 
00524   ENTER_MEM_CHUNK_ROUTINE();
00525 
00526   rmem_chunk = (GRealMemChunk*) mem_chunk;
00527   
00528   mem_areas = rmem_chunk->mem_areas;
00529   while (mem_areas)
00530     {
00531       temp_area = mem_areas;
00532       mem_areas = mem_areas->next;
00533       g_free (temp_area);
00534     }
00535   
00536   if (rmem_chunk->next)
00537     rmem_chunk->next->prev = rmem_chunk->prev;
00538   if (rmem_chunk->prev)
00539     rmem_chunk->prev->next = rmem_chunk->next;
00540   
00541   g_mutex_lock (mem_chunks_lock);
00542   if (rmem_chunk == mem_chunks)
00543     mem_chunks = mem_chunks->next;
00544   g_mutex_unlock (mem_chunks_lock);
00545   
00546   if (rmem_chunk->type == G_ALLOC_AND_FREE)
00547     g_tree_destroy (rmem_chunk->mem_tree);
00548   
00549   g_free (rmem_chunk);
00550 
00551   LEAVE_MEM_CHUNK_ROUTINE();
00552 }
00553 
00554 gpointer
00555 g_mem_chunk_alloc (GMemChunk *mem_chunk)
00556 {
00557   GRealMemChunk *rmem_chunk;
00558   GMemArea *temp_area;
00559   gpointer mem;
00560 
00561   ENTER_MEM_CHUNK_ROUTINE();
00562 
00563   g_return_val_if_fail (mem_chunk != NULL, NULL);
00564   
00565   rmem_chunk = (GRealMemChunk*) mem_chunk;
00566   
00567   while (rmem_chunk->free_atoms)
00568     {
00569       /* Get the first piece of memory on the "free_atoms" list.
00570        * We can go ahead and destroy the list node we used to keep
00571        *  track of it with and to update the "free_atoms" list to
00572        *  point to its next element.
00573        */
00574       mem = rmem_chunk->free_atoms;
00575       rmem_chunk->free_atoms = rmem_chunk->free_atoms->next;
00576       
00577       /* Determine which area this piece of memory is allocated from */
00578       temp_area = g_tree_search (rmem_chunk->mem_tree,
00579                                  (GSearchFunc) g_mem_chunk_area_search,
00580                                  mem);
00581       
00582       /* If the area has been marked, then it is being destroyed.
00583        *  (ie marked to be destroyed).
00584        * We check to see if all of the segments on the free list that
00585        *  reference this area have been removed. This occurs when
00586        *  the ammount of free memory is less than the allocatable size.
00587        * If the chunk should be freed, then we place it in the "free_mem_area".
00588        * This is so we make sure not to free the mem area here and then
00589        *  allocate it again a few lines down.
00590        * If we don't allocate a chunk a few lines down then the "free_mem_area"
00591        *  will be freed.
00592        * If there is already a "free_mem_area" then we'll just free this mem area.
00593        */
00594       if (temp_area->mark)
00595         {
00596           /* Update the "free" memory available in that area */
00597           temp_area->free += rmem_chunk->atom_size;
00598           
00599           if (temp_area->free == rmem_chunk->area_size)
00600             {
00601               if (temp_area == rmem_chunk->mem_area)
00602                 rmem_chunk->mem_area = NULL;
00603               
00604               if (rmem_chunk->free_mem_area)
00605                 {
00606                   rmem_chunk->num_mem_areas -= 1;
00607                   
00608                   if (temp_area->next)
00609                     temp_area->next->prev = temp_area->prev;
00610                   if (temp_area->prev)
00611                     temp_area->prev->next = temp_area->next;
00612                   if (temp_area == rmem_chunk->mem_areas)
00613                     rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
00614                   
00615                   if (rmem_chunk->type == G_ALLOC_AND_FREE)
00616                     g_tree_remove (rmem_chunk->mem_tree, temp_area);
00617                   g_free (temp_area);
00618                 }
00619               else
00620                 rmem_chunk->free_mem_area = temp_area;
00621               
00622               rmem_chunk->num_marked_areas -= 1;
00623             }
00624         }
00625       else
00626         {
00627           /* Update the number of allocated atoms count.
00628            */
00629           temp_area->allocated += 1;
00630           
00631           /* The area wasn't marked...return the memory
00632            */
00633           goto outa_here;
00634         }
00635     }
00636   
00637   /* If there isn't a current mem area or the current mem area is out of space
00638    *  then allocate a new mem area. We'll first check and see if we can use
00639    *  the "free_mem_area". Otherwise we'll just malloc the mem area.
00640    */
00641   if ((!rmem_chunk->mem_area) ||
00642       ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size))
00643     {
00644       if (rmem_chunk->free_mem_area)
00645         {
00646           rmem_chunk->mem_area = rmem_chunk->free_mem_area;
00647           rmem_chunk->free_mem_area = NULL;
00648         }
00649       else
00650         {
00651           rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
00652                                                        MEM_AREA_SIZE +
00653                                                        rmem_chunk->area_size);
00654           
00655           rmem_chunk->num_mem_areas += 1;
00656           rmem_chunk->mem_area->next = rmem_chunk->mem_areas;
00657           rmem_chunk->mem_area->prev = NULL;
00658           
00659           if (rmem_chunk->mem_areas)
00660             rmem_chunk->mem_areas->prev = rmem_chunk->mem_area;
00661           rmem_chunk->mem_areas = rmem_chunk->mem_area;
00662           
00663           if (rmem_chunk->type == G_ALLOC_AND_FREE)
00664             g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area);
00665         }
00666       
00667       rmem_chunk->mem_area->index = 0;
00668       rmem_chunk->mem_area->free = rmem_chunk->area_size;
00669       rmem_chunk->mem_area->allocated = 0;
00670       rmem_chunk->mem_area->mark = 0;
00671     }
00672   
00673   /* Get the memory and modify the state variables appropriately.
00674    */
00675   mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index];
00676   rmem_chunk->mem_area->index += rmem_chunk->atom_size;
00677   rmem_chunk->mem_area->free -= rmem_chunk->atom_size;
00678   rmem_chunk->mem_area->allocated += 1;
00679 
00680 outa_here:
00681 
00682   LEAVE_MEM_CHUNK_ROUTINE();
00683 
00684   return mem;
00685 }
00686 
00687 gpointer
00688 g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
00689 {
00690   gpointer mem;
00691 
00692   mem = g_mem_chunk_alloc (mem_chunk);
00693   if (mem)
00694     {
00695       GRealMemChunk *rmem_chunk = (GRealMemChunk*) mem_chunk;
00696 
00697       memset (mem, 0, rmem_chunk->atom_size);
00698     }
00699 
00700   return mem;
00701 }
00702 
00703 void
00704 g_mem_chunk_free (GMemChunk *mem_chunk,
00705                   gpointer   mem)
00706 {
00707   GRealMemChunk *rmem_chunk;
00708   GMemArea *temp_area;
00709   GFreeAtom *free_atom;
00710   
00711   g_return_if_fail (mem_chunk != NULL);
00712   g_return_if_fail (mem != NULL);
00713 
00714   ENTER_MEM_CHUNK_ROUTINE();
00715 
00716   rmem_chunk = (GRealMemChunk*) mem_chunk;
00717   
00718   /* Don't do anything if this is an ALLOC_ONLY chunk
00719    */
00720   if (rmem_chunk->type == G_ALLOC_AND_FREE)
00721     {
00722       /* Place the memory on the "free_atoms" list
00723        */
00724       free_atom = (GFreeAtom*) mem;
00725       free_atom->next = rmem_chunk->free_atoms;
00726       rmem_chunk->free_atoms = free_atom;
00727       
00728       temp_area = g_tree_search (rmem_chunk->mem_tree,
00729                                  (GSearchFunc) g_mem_chunk_area_search,
00730                                  mem);
00731       
00732       temp_area->allocated -= 1;
00733       
00734       if (temp_area->allocated == 0)
00735         {
00736           temp_area->mark = 1;
00737           rmem_chunk->num_marked_areas += 1;
00738         }
00739     }
00740 
00741   LEAVE_MEM_CHUNK_ROUTINE();
00742 }
00743 
00744 /* This doesn't free the free_area if there is one */
00745 void
00746 g_mem_chunk_clean (GMemChunk *mem_chunk)
00747 {
00748   GRealMemChunk *rmem_chunk;
00749   GMemArea *mem_area;
00750   GFreeAtom *prev_free_atom;
00751   GFreeAtom *temp_free_atom;
00752   gpointer mem;
00753   
00754   g_return_if_fail (mem_chunk != NULL);
00755   
00756   rmem_chunk = (GRealMemChunk*) mem_chunk;
00757   
00758   if (rmem_chunk->type == G_ALLOC_AND_FREE)
00759     {
00760       prev_free_atom = NULL;
00761       temp_free_atom = rmem_chunk->free_atoms;
00762       
00763       while (temp_free_atom)
00764         {
00765           mem = (gpointer) temp_free_atom;
00766           
00767           mem_area = g_tree_search (rmem_chunk->mem_tree,
00768                                     (GSearchFunc) g_mem_chunk_area_search,
00769                                     mem);
00770           
00771           /* If this mem area is marked for destruction then delete the
00772            *  area and list node and decrement the free mem.
00773            */
00774           if (mem_area->mark)
00775             {
00776               if (prev_free_atom)
00777                 prev_free_atom->next = temp_free_atom->next;
00778               else
00779                 rmem_chunk->free_atoms = temp_free_atom->next;
00780               temp_free_atom = temp_free_atom->next;
00781               
00782               mem_area->free += rmem_chunk->atom_size;
00783               if (mem_area->free == rmem_chunk->area_size)
00784                 {
00785                   rmem_chunk->num_mem_areas -= 1;
00786                   rmem_chunk->num_marked_areas -= 1;
00787                   
00788                   if (mem_area->next)
00789                     mem_area->next->prev = mem_area->prev;
00790                   if (mem_area->prev)
00791                     mem_area->prev->next = mem_area->next;
00792                   if (mem_area == rmem_chunk->mem_areas)
00793                     rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
00794                   if (mem_area == rmem_chunk->mem_area)
00795                     rmem_chunk->mem_area = NULL;
00796                   
00797                   if (rmem_chunk->type == G_ALLOC_AND_FREE)
00798                     g_tree_remove (rmem_chunk->mem_tree, mem_area);
00799                   g_free (mem_area);
00800                 }
00801             }
00802           else
00803             {
00804               prev_free_atom = temp_free_atom;
00805               temp_free_atom = temp_free_atom->next;
00806             }
00807         }
00808     }
00809 }
00810 
00811 void
00812 g_mem_chunk_reset (GMemChunk *mem_chunk)
00813 {
00814   GRealMemChunk *rmem_chunk;
00815   GMemArea *mem_areas;
00816   GMemArea *temp_area;
00817   
00818   g_return_if_fail (mem_chunk != NULL);
00819   
00820   rmem_chunk = (GRealMemChunk*) mem_chunk;
00821   
00822   mem_areas = rmem_chunk->mem_areas;
00823   rmem_chunk->num_mem_areas = 0;
00824   rmem_chunk->mem_areas = NULL;
00825   rmem_chunk->mem_area = NULL;
00826   
00827   while (mem_areas)
00828     {
00829       temp_area = mem_areas;
00830       mem_areas = mem_areas->next;
00831       g_free (temp_area);
00832     }
00833   
00834   rmem_chunk->free_atoms = NULL;
00835   
00836   if (rmem_chunk->mem_tree)
00837     g_tree_destroy (rmem_chunk->mem_tree);
00838   rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
00839 }
00840 
00841 void
00842 g_mem_chunk_print (GMemChunk *mem_chunk)
00843 {
00844   GRealMemChunk *rmem_chunk;
00845   GMemArea *mem_areas;
00846   gulong mem;
00847   
00848   g_return_if_fail (mem_chunk != NULL);
00849   
00850   rmem_chunk = (GRealMemChunk*) mem_chunk;
00851   mem_areas = rmem_chunk->mem_areas;
00852   mem = 0;
00853   
00854   while (mem_areas)
00855     {
00856       mem += rmem_chunk->area_size - mem_areas->free;
00857       mem_areas = mem_areas->next;
00858     }
00859   
00860   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
00861          "%s: %ld bytes using %d mem areas",
00862          rmem_chunk->name, mem, rmem_chunk->num_mem_areas);
00863 }
00864 
00865 void
00866 g_mem_chunk_info (void)
00867 {
00868   GRealMemChunk *mem_chunk;
00869   gint count;
00870   
00871   count = 0;
00872   g_mutex_lock (mem_chunks_lock);
00873   mem_chunk = mem_chunks;
00874   while (mem_chunk)
00875     {
00876       count += 1;
00877       mem_chunk = mem_chunk->next;
00878     }
00879   g_mutex_unlock (mem_chunks_lock);
00880   
00881   g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks", count);
00882   
00883   g_mutex_lock (mem_chunks_lock);
00884   mem_chunk = mem_chunks;
00885   g_mutex_unlock (mem_chunks_lock);
00886 
00887   while (mem_chunk)
00888     {
00889       g_mem_chunk_print ((GMemChunk*) mem_chunk);
00890       mem_chunk = mem_chunk->next;
00891     }  
00892 }
00893 
00894 void
00895 g_blow_chunks (void)
00896 {
00897   GRealMemChunk *mem_chunk;
00898   
00899   g_mutex_lock (mem_chunks_lock);
00900   mem_chunk = mem_chunks;
00901   g_mutex_unlock (mem_chunks_lock);
00902   while (mem_chunk)
00903     {
00904       g_mem_chunk_clean ((GMemChunk*) mem_chunk);
00905       mem_chunk = mem_chunk->next;
00906     }
00907 }
00908 
00909 
00910 static gulong
00911 g_mem_chunk_compute_size (gulong size,
00912                           gulong min_size)
00913 {
00914   gulong power_of_2;
00915   gulong lower, upper;
00916   
00917   power_of_2 = 16;
00918   while (power_of_2 < size)
00919     power_of_2 <<= 1;
00920   
00921   lower = power_of_2 >> 1;
00922   upper = power_of_2;
00923   
00924   if (size - lower < upper - size && lower >= min_size)
00925     return lower;
00926   else
00927     return upper;
00928 }
00929 
00930 static gint
00931 g_mem_chunk_area_compare (GMemArea *a,
00932                           GMemArea *b)
00933 {
00934   if (a->mem > b->mem)
00935         return 1;
00936   else if (a->mem < b->mem)
00937         return -1;
00938   return 0;
00939 }
00940 
00941 static gint
00942 g_mem_chunk_area_search (GMemArea *a,
00943                          gchar    *addr)
00944 {
00945   if (a->mem <= addr)
00946     {
00947       if (addr < &a->mem[a->index])
00948         return 0;
00949       return 1;
00950     }
00951   return -1;
00952 }
00953 
00954 /* generic allocators
00955  */
00956 struct _GAllocator /* from gmem.c */
00957 {
00958   gchar         *name;
00959   guint16        n_preallocs;
00960   guint          is_unused : 1;
00961   guint          type : 4;
00962   GAllocator    *last;
00963   GMemChunk     *mem_chunk;
00964   gpointer       dummy; /* implementation specific */
00965 };
00966 
00967 GAllocator*
00968 g_allocator_new (const gchar *name,
00969                  guint        n_preallocs)
00970 {
00971   GAllocator *allocator;
00972 
00973   g_return_val_if_fail (name != NULL, NULL);
00974 
00975   allocator = g_new0 (GAllocator, 1);
00976   allocator->name = g_strdup (name);
00977   allocator->n_preallocs = CLAMP (n_preallocs, 1, 65535);
00978   allocator->is_unused = TRUE;
00979   allocator->type = 0;
00980   allocator->last = NULL;
00981   allocator->mem_chunk = NULL;
00982   allocator->dummy = NULL;
00983 
00984   return allocator;
00985 }
00986 
00987 void
00988 g_allocator_free (GAllocator *allocator)
00989 {
00990   g_return_if_fail (allocator != NULL);
00991   g_return_if_fail (allocator->is_unused == TRUE);
00992 
00993   g_free (allocator->name);
00994   if (allocator->mem_chunk)
00995     g_mem_chunk_destroy (allocator->mem_chunk);
00996 
00997   g_free (allocator);
00998 }
00999 
01000 void
01001 g_mem_init (void)
01002 {
01003   mem_chunks_lock = g_mutex_new();
01004 #ifdef ENABLE_MEM_PROFILE
01005   mem_profile_lock = g_mutex_new();
01006   allocating_for_mem_chunk = g_private_new(NULL);
01007 #endif
01008 }

© sourcejam.com 2005-2008