Home | History | Annotate | Download | only in glib
      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 Lesser 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  * Lesser General Public License for more details.
     13  *
     14  * You should have received a copy of the GNU Lesser 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 
     20 /*
     21  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
     22  * file for a list of people on the GLib Team.  See the ChangeLog
     23  * files for a list of changes.  These files are distributed with
     24  * GLib at ftp://ftp.gtk.org/pub/gtk/.
     25  */
     26 
     27 /*
     28  * MT safe
     29  */
     30 
     31 #include "config.h"
     32 
     33 #include <stdlib.h>
     34 #include <string.h>
     35 #include <signal.h>
     36 
     37 #include "glib.h"
     38 #include "gthreadprivate.h"
     39 #include "galias.h"
     40 
     41 #define MEM_PROFILE_TABLE_SIZE 4096
     42 
     43 
     44 /* notes on macros:
     45  * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
     46  * g_mem_profile().
     47  * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works.
     48  * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions
     49  * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here.
     50  * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped.
     51  */
     52 
     53 /* --- prototypes --- */
     54 static gboolean g_mem_initialized = FALSE;
     55 static void     g_mem_init_nomessage (void);
     56 
     57 
     58 /* --- malloc wrappers --- */
     59 #ifndef	REALLOC_0_WORKS
     60 static gpointer
     61 standard_realloc (gpointer mem,
     62 		  gsize    n_bytes)
     63 {
     64   if (!mem)
     65     return malloc (n_bytes);
     66   else
     67     return realloc (mem, n_bytes);
     68 }
     69 #endif	/* !REALLOC_0_WORKS */
     70 
     71 #ifdef SANE_MALLOC_PROTOS
     72 #  define standard_malloc	malloc
     73 #  ifdef REALLOC_0_WORKS
     74 #    define standard_realloc	realloc
     75 #  endif /* REALLOC_0_WORKS */
     76 #  define standard_free		free
     77 #  define standard_calloc	calloc
     78 #  define standard_try_malloc	malloc
     79 #  define standard_try_realloc	realloc
     80 #else	/* !SANE_MALLOC_PROTOS */
     81 static gpointer
     82 standard_malloc (gsize n_bytes)
     83 {
     84   return malloc (n_bytes);
     85 }
     86 #  ifdef REALLOC_0_WORKS
     87 static gpointer
     88 standard_realloc (gpointer mem,
     89 		  gsize    n_bytes)
     90 {
     91   return realloc (mem, n_bytes);
     92 }
     93 #  endif /* REALLOC_0_WORKS */
     94 static void
     95 standard_free (gpointer mem)
     96 {
     97   free (mem);
     98 }
     99 static gpointer
    100 standard_calloc (gsize n_blocks,
    101 		 gsize n_bytes)
    102 {
    103   return calloc (n_blocks, n_bytes);
    104 }
    105 #define	standard_try_malloc	standard_malloc
    106 #define	standard_try_realloc	standard_realloc
    107 #endif	/* !SANE_MALLOC_PROTOS */
    108 
    109 
    110 /* --- variables --- */
    111 static GMemVTable glib_mem_vtable = {
    112   standard_malloc,
    113   standard_realloc,
    114   standard_free,
    115   standard_calloc,
    116   standard_try_malloc,
    117   standard_try_realloc,
    118 };
    119 
    120 
    121 /* --- functions --- */
    122 gpointer
    123 g_malloc (gsize n_bytes)
    124 {
    125   if (G_UNLIKELY (!g_mem_initialized))
    126     g_mem_init_nomessage();
    127   if (G_LIKELY (n_bytes))
    128     {
    129       gpointer mem;
    130 
    131       mem = glib_mem_vtable.malloc (n_bytes);
    132       if (mem)
    133 	return mem;
    134 
    135       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
    136                G_STRLOC, n_bytes);
    137     }
    138 
    139   return NULL;
    140 }
    141 
    142 gpointer
    143 g_malloc0 (gsize n_bytes)
    144 {
    145   if (G_UNLIKELY (!g_mem_initialized))
    146     g_mem_init_nomessage();
    147   if (G_LIKELY (n_bytes))
    148     {
    149       gpointer mem;
    150 
    151       mem = glib_mem_vtable.calloc (1, n_bytes);
    152       if (mem)
    153 	return mem;
    154 
    155       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
    156                G_STRLOC, n_bytes);
    157     }
    158 
    159   return NULL;
    160 }
    161 
    162 gpointer
    163 g_realloc (gpointer mem,
    164 	   gsize    n_bytes)
    165 {
    166   if (G_UNLIKELY (!g_mem_initialized))
    167     g_mem_init_nomessage();
    168   if (G_LIKELY (n_bytes))
    169     {
    170       mem = glib_mem_vtable.realloc (mem, n_bytes);
    171       if (mem)
    172 	return mem;
    173 
    174       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
    175                G_STRLOC, n_bytes);
    176     }
    177 
    178   if (mem)
    179     glib_mem_vtable.free (mem);
    180 
    181   return NULL;
    182 }
    183 
    184 void
    185 g_free (gpointer mem)
    186 {
    187   if (G_UNLIKELY (!g_mem_initialized))
    188     g_mem_init_nomessage();
    189   if (G_LIKELY (mem))
    190     glib_mem_vtable.free (mem);
    191 }
    192 
    193 gpointer
    194 g_try_malloc (gsize n_bytes)
    195 {
    196   if (G_UNLIKELY (!g_mem_initialized))
    197     g_mem_init_nomessage();
    198   if (G_LIKELY (n_bytes))
    199     return glib_mem_vtable.try_malloc (n_bytes);
    200   else
    201     return NULL;
    202 }
    203 
    204 gpointer
    205 g_try_malloc0 (gsize n_bytes)
    206 {
    207   gpointer mem;
    208 
    209   mem = g_try_malloc (n_bytes);
    210 
    211   if (mem)
    212     memset (mem, 0, n_bytes);
    213 
    214   return mem;
    215 }
    216 
    217 gpointer
    218 g_try_realloc (gpointer mem,
    219 	       gsize    n_bytes)
    220 {
    221   if (G_UNLIKELY (!g_mem_initialized))
    222     g_mem_init_nomessage();
    223   if (G_LIKELY (n_bytes))
    224     return glib_mem_vtable.try_realloc (mem, n_bytes);
    225 
    226   if (mem)
    227     glib_mem_vtable.free (mem);
    228 
    229   return NULL;
    230 }
    231 
    232 static gpointer
    233 fallback_calloc (gsize n_blocks,
    234 		 gsize n_block_bytes)
    235 {
    236   gsize l = n_blocks * n_block_bytes;
    237   gpointer mem = glib_mem_vtable.malloc (l);
    238 
    239   if (mem)
    240     memset (mem, 0, l);
    241 
    242   return mem;
    243 }
    244 
    245 static gboolean vtable_set = FALSE;
    246 
    247 /**
    248  * g_mem_is_system_malloc
    249  *
    250  * Checks whether the allocator used by g_malloc() is the system's
    251  * malloc implementation. If it returns %TRUE memory allocated with
    252  * malloc() can be used interchangeable with memory allocated using g_malloc().
    253  * This function is useful for avoiding an extra copy of allocated memory returned
    254  * by a non-GLib-based API.
    255  *
    256  * A different allocator can be set using g_mem_set_vtable().
    257  *
    258  * Return value: if %TRUE, malloc() and g_malloc() can be mixed.
    259  **/
    260 gboolean
    261 g_mem_is_system_malloc (void)
    262 {
    263   return !vtable_set;
    264 }
    265 
    266 void
    267 g_mem_set_vtable (GMemVTable *vtable)
    268 {
    269   if (!vtable_set)
    270     {
    271       if (vtable->malloc && vtable->realloc && vtable->free)
    272 	{
    273 	  glib_mem_vtable.malloc = vtable->malloc;
    274 	  glib_mem_vtable.realloc = vtable->realloc;
    275 	  glib_mem_vtable.free = vtable->free;
    276 	  glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc;
    277 	  glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc;
    278 	  glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc;
    279 	  vtable_set = TRUE;
    280 	}
    281       else
    282 	g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
    283     }
    284   else
    285     g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
    286 }
    287 
    288 
    289 /* --- memory profiling and checking --- */
    290 #ifdef	G_DISABLE_CHECKS
    291 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
    292 void
    293 g_mem_profile (void)
    294 {
    295 }
    296 #else	/* !G_DISABLE_CHECKS */
    297 typedef enum {
    298   PROFILER_FREE		= 0,
    299   PROFILER_ALLOC	= 1,
    300   PROFILER_RELOC	= 2,
    301   PROFILER_ZINIT	= 4
    302 } ProfilerJob;
    303 static guint *profile_data = NULL;
    304 static gsize profile_allocs = 0;
    305 static gsize profile_zinit = 0;
    306 static gsize profile_frees = 0;
    307 static GMutex *gmem_profile_mutex = NULL;
    308 #ifdef  G_ENABLE_DEBUG
    309 static volatile gsize g_trap_free_size = 0;
    310 static volatile gsize g_trap_realloc_size = 0;
    311 static volatile gsize g_trap_malloc_size = 0;
    312 #endif  /* G_ENABLE_DEBUG */
    313 
    314 #define	PROFILE_TABLE(f1,f2,f3)   ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1))
    315 
    316 static void
    317 profiler_log (ProfilerJob job,
    318 	      gsize       n_bytes,
    319 	      gboolean    success)
    320 {
    321   g_mutex_lock (gmem_profile_mutex);
    322   if (!profile_data)
    323     {
    324       profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8,
    325                                       sizeof (profile_data[0]));
    326       if (!profile_data)	/* memory system kiddin' me, eh? */
    327 	{
    328 	  g_mutex_unlock (gmem_profile_mutex);
    329 	  return;
    330 	}
    331     }
    332 
    333   if (n_bytes < MEM_PROFILE_TABLE_SIZE)
    334     profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
    335                                           (job & PROFILER_RELOC) != 0,
    336                                           success != 0)] += 1;
    337   else
    338     profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
    339                                                          (job & PROFILER_RELOC) != 0,
    340                                                          success != 0)] += 1;
    341   if (success)
    342     {
    343       if (job & PROFILER_ALLOC)
    344         {
    345           profile_allocs += n_bytes;
    346           if (job & PROFILER_ZINIT)
    347             profile_zinit += n_bytes;
    348         }
    349       else
    350         profile_frees += n_bytes;
    351     }
    352   g_mutex_unlock (gmem_profile_mutex);
    353 }
    354 
    355 static void
    356 profile_print_locked (guint   *local_data,
    357 		      gboolean success)
    358 {
    359   gboolean need_header = TRUE;
    360   guint i;
    361 
    362   for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
    363     {
    364       glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
    365       glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
    366       glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
    367       glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
    368 
    369       if (!t_malloc && !t_realloc && !t_free && !t_refree)
    370 	continue;
    371       else if (need_header)
    372 	{
    373 	  need_header = FALSE;
    374 	  g_print (" blocks of | allocated  | freed      | allocated  | freed      | n_bytes   \n");
    375 	  g_print ("  n_bytes  | n_times by | n_times by | n_times by | n_times by | remaining \n");
    376 	  g_print ("           | malloc()   | free()     | realloc()  | realloc()  |           \n");
    377 	  g_print ("===========|============|============|============|============|===========\n");
    378 	}
    379       if (i < MEM_PROFILE_TABLE_SIZE)
    380 	g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
    381 		 i, t_malloc, t_free, t_realloc, t_refree,
    382 		 (t_malloc - t_free + t_realloc - t_refree) * i);
    383       else if (i >= MEM_PROFILE_TABLE_SIZE)
    384 	g_print ("   >%6u | %10ld | %10ld | %10ld | %10ld |        ***\n",
    385 		 i, t_malloc, t_free, t_realloc, t_refree);
    386     }
    387   if (need_header)
    388     g_print (" --- none ---\n");
    389 }
    390 
    391 void
    392 g_mem_profile (void)
    393 {
    394   guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])];
    395   gsize local_allocs;
    396   gsize local_zinit;
    397   gsize local_frees;
    398 
    399   if (G_UNLIKELY (!g_mem_initialized))
    400     g_mem_init_nomessage();
    401 
    402   g_mutex_lock (gmem_profile_mutex);
    403 
    404   local_allocs = profile_allocs;
    405   local_zinit = profile_zinit;
    406   local_frees = profile_frees;
    407 
    408   if (!profile_data)
    409     {
    410       g_mutex_unlock (gmem_profile_mutex);
    411       return;
    412     }
    413 
    414   memcpy (local_data, profile_data,
    415 	  (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
    416 
    417   g_mutex_unlock (gmem_profile_mutex);
    418 
    419   g_print ("GLib Memory statistics (successful operations):\n");
    420   profile_print_locked (local_data, TRUE);
    421   g_print ("GLib Memory statistics (failing operations):\n");
    422   profile_print_locked (local_data, FALSE);
    423   g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
    424            "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
    425            "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
    426            "remaining=%"G_GSIZE_FORMAT"\n",
    427 	   local_allocs,
    428 	   local_zinit,
    429 	   ((gdouble) local_zinit) / local_allocs * 100.0,
    430 	   local_frees,
    431 	   ((gdouble) local_frees) / local_allocs * 100.0,
    432 	   local_allocs - local_frees);
    433 }
    434 
    435 static gpointer
    436 profiler_try_malloc (gsize n_bytes)
    437 {
    438   gsize *p;
    439 
    440 #ifdef  G_ENABLE_DEBUG
    441   if (g_trap_malloc_size == n_bytes)
    442     G_BREAKPOINT ();
    443 #endif  /* G_ENABLE_DEBUG */
    444 
    445   p = standard_malloc (sizeof (gsize) * 2 + n_bytes);
    446 
    447   if (p)
    448     {
    449       p[0] = 0;		/* free count */
    450       p[1] = n_bytes;	/* length */
    451       profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
    452       p += 2;
    453     }
    454   else
    455     profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
    456 
    457   return p;
    458 }
    459 
    460 static gpointer
    461 profiler_malloc (gsize n_bytes)
    462 {
    463   gpointer mem = profiler_try_malloc (n_bytes);
    464 
    465   if (!mem)
    466     g_mem_profile ();
    467 
    468   return mem;
    469 }
    470 
    471 static gpointer
    472 profiler_calloc (gsize n_blocks,
    473 		 gsize n_block_bytes)
    474 {
    475   gsize l = n_blocks * n_block_bytes;
    476   gsize *p;
    477 
    478 #ifdef  G_ENABLE_DEBUG
    479   if (g_trap_malloc_size == l)
    480     G_BREAKPOINT ();
    481 #endif  /* G_ENABLE_DEBUG */
    482 
    483   p = standard_calloc (1, sizeof (gsize) * 2 + l);
    484 
    485   if (p)
    486     {
    487       p[0] = 0;		/* free count */
    488       p[1] = l;		/* length */
    489       profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
    490       p += 2;
    491     }
    492   else
    493     {
    494       profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
    495       g_mem_profile ();
    496     }
    497 
    498   return p;
    499 }
    500 
    501 static void
    502 profiler_free (gpointer mem)
    503 {
    504   gsize *p = mem;
    505 
    506   p -= 2;
    507   if (p[0])	/* free count */
    508     {
    509       g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
    510                  p + 2, p[0]);
    511       profiler_log (PROFILER_FREE,
    512 		    p[1],	/* length */
    513 		    FALSE);
    514     }
    515   else
    516     {
    517 #ifdef  G_ENABLE_DEBUG
    518       if (g_trap_free_size == p[1])
    519 	G_BREAKPOINT ();
    520 #endif  /* G_ENABLE_DEBUG */
    521 
    522       profiler_log (PROFILER_FREE,
    523 		    p[1],	/* length */
    524 		    TRUE);
    525       memset (p + 2, 0xaa, p[1]);
    526 
    527       /* for all those that miss standard_free (p); in this place, yes,
    528        * we do leak all memory when profiling, and that is intentional
    529        * to catch double frees. patch submissions are futile.
    530        */
    531     }
    532   p[0] += 1;
    533 }
    534 
    535 static gpointer
    536 profiler_try_realloc (gpointer mem,
    537 		      gsize    n_bytes)
    538 {
    539   gsize *p = mem;
    540 
    541   p -= 2;
    542 
    543 #ifdef  G_ENABLE_DEBUG
    544   if (g_trap_realloc_size == n_bytes)
    545     G_BREAKPOINT ();
    546 #endif  /* G_ENABLE_DEBUG */
    547 
    548   if (mem && p[0])	/* free count */
    549     {
    550       g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
    551                  "memory has been freed %"G_GSIZE_FORMAT" times already",
    552                  p + 2, (gsize) n_bytes, p[0]);
    553       profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
    554 
    555       return NULL;
    556     }
    557   else
    558     {
    559       p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
    560 
    561       if (p)
    562 	{
    563 	  if (mem)
    564 	    profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
    565 	  p[0] = 0;
    566 	  p[1] = n_bytes;
    567 	  profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
    568 	  p += 2;
    569 	}
    570       else
    571 	profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
    572 
    573       return p;
    574     }
    575 }
    576 
    577 static gpointer
    578 profiler_realloc (gpointer mem,
    579 		  gsize    n_bytes)
    580 {
    581   mem = profiler_try_realloc (mem, n_bytes);
    582 
    583   if (!mem)
    584     g_mem_profile ();
    585 
    586   return mem;
    587 }
    588 
    589 static GMemVTable profiler_table = {
    590   profiler_malloc,
    591   profiler_realloc,
    592   profiler_free,
    593   profiler_calloc,
    594   profiler_try_malloc,
    595   profiler_try_realloc,
    596 };
    597 GMemVTable *glib_mem_profiler_table = &profiler_table;
    598 
    599 #endif	/* !G_DISABLE_CHECKS */
    600 
    601 /* --- MemChunks --- */
    602 #ifndef G_ALLOC_AND_FREE
    603 typedef struct _GAllocator GAllocator;
    604 typedef struct _GMemChunk  GMemChunk;
    605 #define G_ALLOC_ONLY	  1
    606 #define G_ALLOC_AND_FREE  2
    607 #endif
    608 
    609 struct _GMemChunk {
    610   guint alloc_size;           /* the size of an atom */
    611 };
    612 
    613 GMemChunk*
    614 g_mem_chunk_new (const gchar  *name,
    615 		 gint          atom_size,
    616 		 gsize         area_size,
    617 		 gint          type)
    618 {
    619   GMemChunk *mem_chunk;
    620   g_return_val_if_fail (atom_size > 0, NULL);
    621 
    622   mem_chunk = g_slice_new (GMemChunk);
    623   mem_chunk->alloc_size = atom_size;
    624   return mem_chunk;
    625 }
    626 
    627 void
    628 g_mem_chunk_destroy (GMemChunk *mem_chunk)
    629 {
    630   g_return_if_fail (mem_chunk != NULL);
    631 
    632   g_slice_free (GMemChunk, mem_chunk);
    633 }
    634 
    635 gpointer
    636 g_mem_chunk_alloc (GMemChunk *mem_chunk)
    637 {
    638   g_return_val_if_fail (mem_chunk != NULL, NULL);
    639 
    640   return g_slice_alloc (mem_chunk->alloc_size);
    641 }
    642 
    643 gpointer
    644 g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
    645 {
    646   g_return_val_if_fail (mem_chunk != NULL, NULL);
    647 
    648   return g_slice_alloc0 (mem_chunk->alloc_size);
    649 }
    650 
    651 void
    652 g_mem_chunk_free (GMemChunk *mem_chunk,
    653 		  gpointer   mem)
    654 {
    655   g_return_if_fail (mem_chunk != NULL);
    656 
    657   g_slice_free1 (mem_chunk->alloc_size, mem);
    658 }
    659 
    660 void	g_mem_chunk_clean	(GMemChunk *mem_chunk)	{}
    661 void	g_mem_chunk_reset	(GMemChunk *mem_chunk)	{}
    662 void	g_mem_chunk_print	(GMemChunk *mem_chunk)	{}
    663 void	g_mem_chunk_info	(void)			{}
    664 void	g_blow_chunks		(void)			{}
    665 
    666 GAllocator*
    667 g_allocator_new (const gchar *name,
    668 		 guint        n_preallocs)
    669 {
    670   static struct _GAllocator {
    671     gchar      *name;
    672     guint16     n_preallocs;
    673     guint       is_unused : 1;
    674     guint       type : 4;
    675     GAllocator *last;
    676     GMemChunk  *mem_chunk;
    677     gpointer    free_list;
    678   } dummy = {
    679     "GAllocator is deprecated", 1, TRUE, 0, NULL, NULL, NULL,
    680   };
    681   /* some (broken) GAllocator uses depend on non-NULL allocators */
    682   return (void*) &dummy;
    683 }
    684 
    685 void
    686 g_allocator_free (GAllocator *allocator)
    687 {
    688 }
    689 
    690 #ifdef ENABLE_GC_FRIENDLY_DEFAULT
    691 gboolean g_mem_gc_friendly = TRUE;
    692 #else
    693 gboolean g_mem_gc_friendly = FALSE;
    694 #endif
    695 
    696 static void
    697 g_mem_init_nomessage (void)
    698 {
    699   gchar buffer[1024];
    700   const gchar *val;
    701   const GDebugKey keys[] = {
    702     { "gc-friendly", 1 },
    703   };
    704   gint flags;
    705   if (g_mem_initialized)
    706     return;
    707   /* don't use g_malloc/g_message here */
    708   val = _g_getenv_nomalloc ("G_DEBUG", buffer);
    709   flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
    710   if (flags & 1)        /* gc-friendly */
    711     {
    712       g_mem_gc_friendly = TRUE;
    713     }
    714   g_mem_initialized = TRUE;
    715 }
    716 
    717 void
    718 _g_mem_thread_init_noprivate_nomessage (void)
    719 {
    720   /* we may only create mutexes here, locking/
    721    * unlocking a mutex does not yet work.
    722    */
    723   g_mem_init_nomessage();
    724 #ifndef G_DISABLE_CHECKS
    725   gmem_profile_mutex = g_mutex_new ();
    726 #endif
    727 }
    728 
    729 #define __G_MEM_C__
    730 #include "galiasdef.c"
    731