glib/glib/gmem.c
changeset 18 47c74d1534e1
equal deleted inserted replaced
0:e4d67989cc36 18:47c74d1534e1
       
     1 /* GLIB - Library of useful routines for C programming
       
     2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       
     3  * Portions copyright (c) 2006-2009 Nokia Corporation.  All rights reserved.
       
     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 #ifdef __SYMBIAN32__
       
    37 #include <errno.h>
       
    38 #endif /* __SYMBIAN32__ */
       
    39 
       
    40 #include "glib.h"
       
    41 #include "gthreadprivate.h"
       
    42 #include "galias.h"
       
    43 
       
    44 #define MEM_PROFILE_TABLE_SIZE 4096
       
    45 #ifdef __SYMBIAN32__
       
    46 #include "glib_wsd.h"
       
    47 #endif /* __SYMBIAN32__ */
       
    48 
       
    49 #if EMULATOR
       
    50 #define g_thread_functions_for_glib_use (*_g_thread_functions_for_glib_use())
       
    51 #define g_thread_use_default_impl (*_g_thread_use_default_impl())
       
    52 #endif /* EMULATOR */
       
    53 
       
    54 #ifdef MOBILE_PORT
       
    55 #include <glowmem.h>
       
    56 #endif /* MOBILE_PORT */
       
    57 
       
    58 /* notes on macros:
       
    59  * having G_DISABLE_CHECKS defined disables use of glib_mem_profiler_table and
       
    60  * g_mem_profile().
       
    61  * REALLOC_0_WORKS is defined if g_realloc (NULL, x) works.
       
    62  * SANE_MALLOC_PROTOS is defined if the systems malloc() and friends functions
       
    63  * match the corresponding GLib prototypes, keep configure.in and gmem.h in sync here.
       
    64  * g_mem_gc_friendly is TRUE, freed memory should be 0-wiped.
       
    65  */
       
    66 
       
    67 /* --- prototypes --- */
       
    68 #if (EMULATOR)
       
    69 
       
    70 PLS(g_mem_initialized ,gmem,gboolean)
       
    71 #define g_mem_initialized  (*FUNCTION_NAME(g_mem_initialized ,gmem)())
       
    72 
       
    73 #else
       
    74 
       
    75 static gboolean g_mem_initialized = FALSE;
       
    76 
       
    77 #endif /* EMULATOR */
       
    78 
       
    79 static void     g_mem_init_nomessage (void);
       
    80 
       
    81 
       
    82 /* --- malloc wrappers --- */
       
    83 #ifndef	REALLOC_0_WORKS
       
    84 static gpointer
       
    85 standard_realloc (gpointer mem,
       
    86 		  gsize    n_bytes)
       
    87 {
       
    88   if (!mem)
       
    89     return malloc (n_bytes);
       
    90   else
       
    91     return realloc (mem, n_bytes);
       
    92 }
       
    93 #endif	/* !REALLOC_0_WORKS */
       
    94 
       
    95 #ifdef SANE_MALLOC_PROTOS
       
    96 #  define standard_malloc	malloc
       
    97 #  ifdef REALLOC_0_WORKS
       
    98 #    define standard_realloc	realloc
       
    99 #  endif /* REALLOC_0_WORKS */
       
   100 #  define standard_free		free
       
   101 #  define standard_calloc	calloc
       
   102 #  define standard_try_malloc	malloc
       
   103 #  define standard_try_realloc	realloc
       
   104 #else	/* !SANE_MALLOC_PROTOS */
       
   105 static gpointer
       
   106 standard_malloc (gsize n_bytes)
       
   107 {
       
   108   return malloc (n_bytes);
       
   109 }
       
   110 #  ifdef REALLOC_0_WORKS
       
   111 static gpointer
       
   112 standard_realloc (gpointer mem,
       
   113 		  gsize    n_bytes)
       
   114 {
       
   115   return realloc (mem, n_bytes);
       
   116 }
       
   117 #  endif /* REALLOC_0_WORKS */
       
   118 static void
       
   119 standard_free (gpointer mem)
       
   120 {
       
   121   free (mem);
       
   122 }
       
   123 static gpointer
       
   124 standard_calloc (gsize n_blocks,
       
   125 		 gsize n_bytes)
       
   126 {
       
   127   return calloc (n_blocks, n_bytes);
       
   128 }
       
   129 #define	standard_try_malloc	standard_malloc
       
   130 #define	standard_try_realloc	standard_realloc
       
   131 #endif	/* !SANE_MALLOC_PROTOS */
       
   132 
       
   133 
       
   134 /* --- variables --- */
       
   135 #if (EMULATOR)
       
   136 
       
   137 PLS(glib_mem_vtable,gmem,GMemVTable)
       
   138 #define glib_mem_vtable (*FUNCTION_NAME(glib_mem_vtable,gmem)())
       
   139 #else
       
   140 static GMemVTable glib_mem_vtable = {
       
   141   NULL,//standard_malloc,
       
   142   NULL,//standard_realloc,
       
   143   NULL,//standard_free,
       
   144   NULL,//standard_calloc,
       
   145   NULL,//standard_try_malloc,
       
   146   NULL,//standard_try_realloc,
       
   147 };
       
   148 #endif /* EMULATOR */
       
   149 #ifdef __SYMBIAN32__
       
   150 const GMemVTable glib_mem_vtable_temp = {
       
   151   standard_malloc,
       
   152   standard_realloc,
       
   153   standard_free,
       
   154   standard_calloc,
       
   155   standard_try_malloc,
       
   156   standard_try_realloc,
       
   157 };
       
   158 #endif//__SYMBIAN32__
       
   159 
       
   160 /* --- functions --- */
       
   161 EXPORT_C gpointer
       
   162 g_malloc (gsize n_bytes)
       
   163 {
       
   164 #ifdef MOBILE_PORT
       
   165 
       
   166   	return g_try_malloc(n_bytes);
       
   167 
       
   168 #else
       
   169 
       
   170   if (G_UNLIKELY (!g_mem_initialized))
       
   171     g_mem_init_nomessage();
       
   172   if (G_LIKELY (n_bytes))
       
   173     {
       
   174       gpointer mem;
       
   175 
       
   176       mem = glib_mem_vtable.malloc (n_bytes);
       
   177       if (mem)
       
   178 	return mem;
       
   179 
       
   180       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
       
   181                G_STRLOC, n_bytes);
       
   182     }
       
   183 
       
   184   return NULL;
       
   185   
       
   186 #endif /* MOBILE_PORT*/
       
   187 }
       
   188 
       
   189 EXPORT_C gpointer
       
   190 g_malloc0 (gsize n_bytes)
       
   191 {
       
   192   #ifdef MOBILE_PORT
       
   193   	return g_try_malloc0(n_bytes);
       
   194   #else
       
   195   
       
   196   if (G_UNLIKELY (!g_mem_initialized))
       
   197     g_mem_init_nomessage();
       
   198   if (G_LIKELY (n_bytes))
       
   199     {
       
   200       gpointer mem;
       
   201 
       
   202       mem = glib_mem_vtable.calloc (1, n_bytes);
       
   203       if (mem)
       
   204 	return mem;
       
   205 
       
   206       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
       
   207                G_STRLOC, n_bytes);
       
   208     }
       
   209 
       
   210   return NULL;
       
   211   
       
   212   #endif  /* MOBILE_PORT*/
       
   213 }
       
   214 
       
   215 EXPORT_C gpointer
       
   216 g_realloc (gpointer mem,
       
   217 	   gsize    n_bytes)
       
   218 {
       
   219   #ifdef MOBILE_PORT
       
   220   
       
   221   	return g_try_realloc(mem,n_bytes);
       
   222   
       
   223   #else 
       
   224   if (G_UNLIKELY (!g_mem_initialized))
       
   225     g_mem_init_nomessage();
       
   226   if (G_LIKELY (n_bytes))
       
   227     {
       
   228       mem = glib_mem_vtable.realloc (mem, n_bytes);
       
   229       if (mem)
       
   230 	return mem;
       
   231 
       
   232       g_error ("%s: failed to allocate %"G_GSIZE_FORMAT" bytes",
       
   233                G_STRLOC, n_bytes);
       
   234     }
       
   235 
       
   236   if (mem)
       
   237     glib_mem_vtable.free (mem);
       
   238 
       
   239   return NULL;
       
   240   #endif  /* MOBILE_PORT*/
       
   241 }
       
   242 
       
   243 EXPORT_C void
       
   244 g_free (gpointer mem)
       
   245 {
       
   246   if (G_UNLIKELY (!g_mem_initialized))
       
   247     g_mem_init_nomessage();
       
   248   if (G_LIKELY (mem))
       
   249   {
       
   250 #ifdef MOBILE_PORT
       
   251   {
       
   252   	mem_info * m = _get_thread_specific_data();
       
   253   	if(m && m->is_setjmp_called)
       
   254   		_findAndDestroy(&(m->stack),mem);
       
   255 #endif /* MOBILE_PORT */
       
   256     glib_mem_vtable.free (mem);
       
   257 #ifdef MOBILE_PORT
       
   258   }
       
   259 #endif /* MOBILE_PORT */   
       
   260 	}
       
   261 }
       
   262 EXPORT_C gpointer
       
   263 g_try_malloc (gsize n_bytes)
       
   264 {
       
   265 #ifdef MOBILE_PORT
       
   266   gpointer ptr;
       
   267 #endif /* MOBILE_PORT */
       
   268   
       
   269   if (G_UNLIKELY (!g_mem_initialized))
       
   270     g_mem_init_nomessage();
       
   271   if (G_LIKELY (n_bytes))
       
   272 #ifdef MOBILE_PORT
       
   273   {
       
   274 	errno = 0;
       
   275 
       
   276   		ptr = glib_mem_vtable.try_malloc (n_bytes);
       
   277   	if(ENOMEM == errno)
       
   278   	{
       
   279   		mem_info *m = _get_thread_specific_data();
       
   280   		if(!m)
       
   281   			return NULL;
       
   282   		
       
   283   		if(TRUE == m->is_setjmp_called)
       
   284   		{
       
   285   			longjmp(m->buf,1);
       
   286   		}
       
   287   	}
       
   288   	else
       
   289   	{
       
   290   		mem_info *m = _get_thread_specific_data();
       
   291   		
       
   292   		if(m && m->is_setjmp_called)
       
   293   		{
       
   294   			if(_push(&(m->stack),ptr))
       
   295 			{	
       
   296 				free(ptr);
       
   297 				longjmp(m->buf,1);
       
   298 			}	
       
   299   		}
       
   300   	}
       
   301   	return ptr;
       
   302 #else
       
   303 	{
       
   304     return glib_mem_vtable.try_malloc (n_bytes);
       
   305   else
       
   306 	}
       
   307 #endif /* MOBILE_PORT */
       
   308 #ifdef MOBILE_PORT
       
   309   }
       
   310 #endif /* MOBILE_PORT */
       
   311   else
       
   312     return NULL;
       
   313 }
       
   314 
       
   315 EXPORT_C gpointer
       
   316 g_try_malloc0 (gsize n_bytes)
       
   317 { 
       
   318   gpointer mem;
       
   319 
       
   320   mem = g_try_malloc (n_bytes);
       
   321   
       
   322   if (mem)
       
   323     memset (mem, 0, n_bytes);
       
   324 
       
   325   return mem;
       
   326 }
       
   327 
       
   328 EXPORT_C gpointer
       
   329 g_try_realloc (gpointer mem,
       
   330 	       gsize    n_bytes)
       
   331 {
       
   332   if (G_UNLIKELY (!g_mem_initialized))
       
   333     g_mem_init_nomessage();
       
   334   if (G_LIKELY (n_bytes))
       
   335     return glib_mem_vtable.try_realloc (mem, n_bytes);
       
   336 
       
   337   if (mem)
       
   338     glib_mem_vtable.free (mem);
       
   339 
       
   340   return NULL;
       
   341 }
       
   342 
       
   343 static gpointer
       
   344 fallback_calloc (gsize n_blocks,
       
   345 		 gsize n_block_bytes)
       
   346 {
       
   347   gsize l = n_blocks * n_block_bytes;
       
   348   gpointer mem = glib_mem_vtable.malloc (l);
       
   349 
       
   350   if (mem)
       
   351     memset (mem, 0, l);
       
   352 
       
   353   return mem;
       
   354 }
       
   355 
       
   356 #if (EMULATOR)
       
   357 
       
   358 PLS(vtable_set ,gmem,gboolean )
       
   359 #define vtable_set  (*FUNCTION_NAME(vtable_set ,gmem)())
       
   360 
       
   361 #else
       
   362 
       
   363 static gboolean vtable_set = FALSE;
       
   364 
       
   365 #endif /* EMULATOR */
       
   366 
       
   367 /**
       
   368  * g_mem_is_system_malloc
       
   369  * 
       
   370  * Checks whether the allocator used by g_malloc() is the system's
       
   371  * malloc implementation. If it returns %TRUE memory allocated with
       
   372  * malloc() can be used interchangeable with memory allocated using g_malloc(). 
       
   373  * This function is useful for avoiding an extra copy of allocated memory returned
       
   374  * by a non-GLib-based API.
       
   375  *
       
   376  * A different allocator can be set using g_mem_set_vtable().
       
   377  *
       
   378  * Return value: if %TRUE, malloc() and g_malloc() can be mixed.
       
   379  **/
       
   380 EXPORT_C gboolean
       
   381 g_mem_is_system_malloc (void)
       
   382 {
       
   383   return !vtable_set;
       
   384 }
       
   385 
       
   386 EXPORT_C void
       
   387 g_mem_set_vtable (GMemVTable *vtable)
       
   388 {
       
   389   if (!vtable_set)
       
   390     {
       
   391       if (vtable->malloc && vtable->realloc && vtable->free)
       
   392 	{
       
   393 	  glib_mem_vtable.malloc = vtable->malloc;
       
   394 	  glib_mem_vtable.realloc = vtable->realloc;
       
   395 	  glib_mem_vtable.free = vtable->free;
       
   396 	  glib_mem_vtable.calloc = vtable->calloc ? vtable->calloc : fallback_calloc;
       
   397 	  glib_mem_vtable.try_malloc = vtable->try_malloc ? vtable->try_malloc : glib_mem_vtable.malloc;
       
   398 	  glib_mem_vtable.try_realloc = vtable->try_realloc ? vtable->try_realloc : glib_mem_vtable.realloc;
       
   399 	  vtable_set = TRUE;
       
   400 	}
       
   401       else
       
   402 	g_warning (G_STRLOC ": memory allocation vtable lacks one of malloc(), realloc() or free()");
       
   403     }
       
   404   else
       
   405     g_warning (G_STRLOC ": memory allocation vtable can only be set once at startup");
       
   406 }
       
   407 
       
   408 
       
   409 /* --- memory profiling and checking --- */
       
   410 #if (EMULATOR)
       
   411 
       
   412 PLS(glib_mem_profiler_table,gmem,GMemVTable *)
       
   413 #define glib_mem_profiler_table  (*FUNCTION_NAME(glib_mem_profiler_table,gmem)())
       
   414 
       
   415 #endif /* EMULATOR */
       
   416 
       
   417 #ifdef	G_DISABLE_CHECKS
       
   418 #if !(EMULATOR)
       
   419 GMemVTable *glib_mem_profiler_table = &glib_mem_vtable;
       
   420 #endif /* EMULATOR */
       
   421 
       
   422 EXPORT_C void
       
   423 g_mem_profile (void)
       
   424 {
       
   425 }
       
   426 #else	/* !G_DISABLE_CHECKS */
       
   427 typedef enum {
       
   428   PROFILER_FREE		= 0,
       
   429   PROFILER_ALLOC	= 1,
       
   430   PROFILER_RELOC	= 2,
       
   431   PROFILER_ZINIT	= 4
       
   432 } ProfilerJob;
       
   433 
       
   434 #if (EMULATOR)
       
   435 
       
   436 PLS(profile_data ,gmem,guint *)
       
   437 PLS(profile_allocs  ,gmem,gulong)
       
   438 PLS(profile_zinit ,gmem,gulong)
       
   439 PLS(profile_frees  ,gmem,gulong)
       
   440 PLS(gmem_profile_mutex  ,gmem,GMutex *)
       
   441 
       
   442 #define profile_data (*FUNCTION_NAME(profile_data ,gmem)())
       
   443 #define profile_allocs (*FUNCTION_NAME(profile_allocs,gmem)())
       
   444 #define profile_zinit (*FUNCTION_NAME(profile_zinit,gmem)())
       
   445 #define profile_frees (*FUNCTION_NAME(profile_frees,gmem)())
       
   446 #define gmem_profile_mutex (*FUNCTION_NAME(gmem_profile_mutex,gmem)())
       
   447 
       
   448 #else
       
   449 
       
   450 static guint *profile_data = NULL;
       
   451 static gsize profile_allocs = 0;
       
   452 static gsize profile_zinit = 0;
       
   453 static gsize profile_frees = 0;
       
   454 static GMutex *gmem_profile_mutex = NULL;
       
   455 
       
   456 #endif /* EMULATOR */
       
   457 
       
   458 #ifdef  G_ENABLE_DEBUG
       
   459 #if (EMULATOR)
       
   460 PLS(g_trap_free_size ,gmem,gsize)
       
   461 PLS(g_trap_realloc_size  ,gmem,gsize)
       
   462 PLS(g_trap_malloc_size ,gmem,gsize)
       
   463 
       
   464 #define g_trap_free_size (*FUNCTION_NAME(g_trap_free_size ,gmem)())
       
   465 #define g_trap_realloc_size (*FUNCTION_NAME(g_trap_realloc_size,gmem)())
       
   466 #define g_trap_malloc_size (*FUNCTION_NAME(g_trap_malloc_size,gmem)())
       
   467 #else
       
   468 static volatile gsize g_trap_free_size = 0;
       
   469 static volatile gsize g_trap_realloc_size = 0;
       
   470 static volatile gsize g_trap_malloc_size = 0;
       
   471 #endif//EMULATOR
       
   472 #endif  /* G_ENABLE_DEBUG */
       
   473 
       
   474 #define	PROFILE_TABLE(f1,f2,f3)   ( ( ((f3) << 2) | ((f2) << 1) | (f1) ) * (MEM_PROFILE_TABLE_SIZE + 1))
       
   475 
       
   476 static void
       
   477 profiler_log (ProfilerJob job,
       
   478 	      gsize       n_bytes,
       
   479 	      gboolean    success)
       
   480 {
       
   481   g_mutex_lock (gmem_profile_mutex);
       
   482   if (!profile_data)
       
   483     {
       
   484       profile_data = standard_calloc ((MEM_PROFILE_TABLE_SIZE + 1) * 8, 
       
   485                                       sizeof (profile_data[0]));
       
   486       if (!profile_data)	/* memory system kiddin' me, eh? */
       
   487 	{
       
   488 	  g_mutex_unlock (gmem_profile_mutex);
       
   489 	  return;
       
   490 	}
       
   491     }
       
   492 
       
   493   if (n_bytes < MEM_PROFILE_TABLE_SIZE)
       
   494     profile_data[n_bytes + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
       
   495                                           (job & PROFILER_RELOC) != 0,
       
   496                                           success != 0)] += 1;
       
   497   else
       
   498     profile_data[MEM_PROFILE_TABLE_SIZE + PROFILE_TABLE ((job & PROFILER_ALLOC) != 0,
       
   499                                                          (job & PROFILER_RELOC) != 0,
       
   500                                                          success != 0)] += 1;
       
   501   if (success)
       
   502     {
       
   503       if (job & PROFILER_ALLOC)
       
   504         {
       
   505           profile_allocs += n_bytes;
       
   506           if (job & PROFILER_ZINIT)
       
   507             profile_zinit += n_bytes;
       
   508         }
       
   509       else
       
   510         profile_frees += n_bytes;
       
   511     }
       
   512   g_mutex_unlock (gmem_profile_mutex);
       
   513 }
       
   514 
       
   515 static void
       
   516 profile_print_locked (guint   *local_data,
       
   517 		      gboolean success)
       
   518 {
       
   519   gboolean need_header = TRUE;
       
   520   guint i;
       
   521 
       
   522   for (i = 0; i <= MEM_PROFILE_TABLE_SIZE; i++)
       
   523     {
       
   524       glong t_malloc = local_data[i + PROFILE_TABLE (1, 0, success)];
       
   525       glong t_realloc = local_data[i + PROFILE_TABLE (1, 1, success)];
       
   526       glong t_free = local_data[i + PROFILE_TABLE (0, 0, success)];
       
   527       glong t_refree = local_data[i + PROFILE_TABLE (0, 1, success)];
       
   528       
       
   529       if (!t_malloc && !t_realloc && !t_free && !t_refree)
       
   530 	continue;
       
   531       else if (need_header)
       
   532 	{
       
   533 	  need_header = FALSE;
       
   534 	  g_print (" blocks of | allocated  | freed      | allocated  | freed      | n_bytes   \n");
       
   535 	  g_print ("  n_bytes  | n_times by | n_times by | n_times by | n_times by | remaining \n");
       
   536 	  g_print ("           | malloc()   | free()     | realloc()  | realloc()  |           \n");
       
   537 	  g_print ("===========|============|============|============|============|===========\n");
       
   538 	}
       
   539       if (i < MEM_PROFILE_TABLE_SIZE)
       
   540 	g_print ("%10u | %10ld | %10ld | %10ld | %10ld |%+11ld\n",
       
   541 		 i, t_malloc, t_free, t_realloc, t_refree,
       
   542 		 (t_malloc - t_free + t_realloc - t_refree) * i);
       
   543       else if (i >= MEM_PROFILE_TABLE_SIZE)
       
   544 	g_print ("   >%6u | %10ld | %10ld | %10ld | %10ld |        ***\n",
       
   545 		 i, t_malloc, t_free, t_realloc, t_refree);
       
   546     }
       
   547   if (need_header)
       
   548     g_print (" --- none ---\n");
       
   549 }
       
   550 
       
   551 EXPORT_C void
       
   552 g_mem_profile (void)
       
   553 {
       
   554   guint local_data[(MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0])];
       
   555   gsize local_allocs;
       
   556   gsize local_zinit;
       
   557   gsize local_frees;
       
   558 
       
   559   if (G_UNLIKELY (!g_mem_initialized))
       
   560     g_mem_init_nomessage();
       
   561 
       
   562   g_mutex_lock (gmem_profile_mutex);
       
   563 
       
   564   local_allocs = profile_allocs;
       
   565   local_zinit = profile_zinit;
       
   566   local_frees = profile_frees;
       
   567 
       
   568   if (!profile_data)
       
   569     {
       
   570       g_mutex_unlock (gmem_profile_mutex);
       
   571       return;
       
   572     }
       
   573 
       
   574   memcpy (local_data, profile_data, 
       
   575 	  (MEM_PROFILE_TABLE_SIZE + 1) * 8 * sizeof (profile_data[0]));
       
   576   
       
   577   g_mutex_unlock (gmem_profile_mutex);
       
   578 
       
   579   g_print ("GLib Memory statistics (successful operations):\n");
       
   580   profile_print_locked (local_data, TRUE);
       
   581   g_print ("GLib Memory statistics (failing operations):\n");
       
   582   profile_print_locked (local_data, FALSE);
       
   583   g_print ("Total bytes: allocated=%"G_GSIZE_FORMAT", "
       
   584            "zero-initialized=%"G_GSIZE_FORMAT" (%.2f%%), "
       
   585            "freed=%"G_GSIZE_FORMAT" (%.2f%%), "
       
   586            "remaining=%"G_GSIZE_FORMAT"\n",
       
   587 	   local_allocs,
       
   588 	   local_zinit,
       
   589 	   ((gdouble) local_zinit) / local_allocs * 100.0,
       
   590 	   local_frees,
       
   591 	   ((gdouble) local_frees) / local_allocs * 100.0,
       
   592 	   local_allocs - local_frees);
       
   593 }
       
   594 
       
   595 static gpointer
       
   596 profiler_try_malloc (gsize n_bytes)
       
   597 {
       
   598   gsize *p;
       
   599 
       
   600 #ifdef  G_ENABLE_DEBUG
       
   601   if (g_trap_malloc_size == n_bytes)
       
   602     G_BREAKPOINT ();
       
   603 #endif  /* G_ENABLE_DEBUG */
       
   604 
       
   605   p = standard_malloc (sizeof (gsize) * 2 + n_bytes);
       
   606 
       
   607   if (p)
       
   608     {
       
   609       p[0] = 0;		/* free count */
       
   610       p[1] = n_bytes;	/* length */
       
   611       profiler_log (PROFILER_ALLOC, n_bytes, TRUE);
       
   612       p += 2;
       
   613     }
       
   614   else
       
   615     profiler_log (PROFILER_ALLOC, n_bytes, FALSE);
       
   616   
       
   617   return p;
       
   618 }
       
   619 
       
   620 static gpointer
       
   621 profiler_malloc (gsize n_bytes)
       
   622 {
       
   623   gpointer mem = profiler_try_malloc (n_bytes);
       
   624 
       
   625   if (!mem)
       
   626     g_mem_profile ();
       
   627 
       
   628   return mem;
       
   629 }
       
   630 
       
   631 static gpointer
       
   632 profiler_calloc (gsize n_blocks,
       
   633 		 gsize n_block_bytes)
       
   634 {
       
   635   gsize l = n_blocks * n_block_bytes;
       
   636   gsize *p;
       
   637 
       
   638 #ifdef  G_ENABLE_DEBUG
       
   639   if (g_trap_malloc_size == l)
       
   640     G_BREAKPOINT ();
       
   641 #endif  /* G_ENABLE_DEBUG */
       
   642   
       
   643   p = standard_calloc (1, sizeof (gsize) * 2 + l);
       
   644 
       
   645   if (p)
       
   646     {
       
   647       p[0] = 0;		/* free count */
       
   648       p[1] = l;		/* length */
       
   649       profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, TRUE);
       
   650       p += 2;
       
   651     }
       
   652   else
       
   653     {
       
   654       profiler_log (PROFILER_ALLOC | PROFILER_ZINIT, l, FALSE);
       
   655       g_mem_profile ();
       
   656     }
       
   657 
       
   658   return p;
       
   659 }
       
   660 
       
   661 static void
       
   662 profiler_free (gpointer mem)
       
   663 {
       
   664   gsize *p = mem;
       
   665 
       
   666   p -= 2;
       
   667   if (p[0])	/* free count */
       
   668     {
       
   669       g_warning ("free(%p): memory has been freed %"G_GSIZE_FORMAT" times already",
       
   670                  p + 2, p[0]);
       
   671       profiler_log (PROFILER_FREE,
       
   672 		    p[1],	/* length */
       
   673 		    FALSE);
       
   674     }
       
   675   else
       
   676     {
       
   677 #ifdef  G_ENABLE_DEBUG
       
   678       if (g_trap_free_size == p[1])
       
   679 	G_BREAKPOINT ();
       
   680 #endif  /* G_ENABLE_DEBUG */
       
   681 
       
   682       profiler_log (PROFILER_FREE,
       
   683 		    p[1],	/* length */
       
   684 		    TRUE);
       
   685       memset (p + 2, 0xaa, p[1]);
       
   686 
       
   687       /* for all those that miss standard_free (p); in this place, yes,
       
   688        * we do leak all memory when profiling, and that is intentional
       
   689        * to catch double frees. patch submissions are futile.
       
   690        */
       
   691     }
       
   692   p[0] += 1;
       
   693 }
       
   694 
       
   695 static gpointer
       
   696 profiler_try_realloc (gpointer mem,
       
   697 		      gsize    n_bytes)
       
   698 {
       
   699   gsize *p = mem;
       
   700 
       
   701   p -= 2;
       
   702 
       
   703 #ifdef  G_ENABLE_DEBUG
       
   704   if (g_trap_realloc_size == n_bytes)
       
   705     G_BREAKPOINT ();
       
   706 #endif  /* G_ENABLE_DEBUG */
       
   707   
       
   708   if (mem && p[0])	/* free count */
       
   709     {
       
   710       g_warning ("realloc(%p, %"G_GSIZE_FORMAT"): "
       
   711                  "memory has been freed %"G_GSIZE_FORMAT" times already",
       
   712                  p + 2, (gsize) n_bytes, p[0]);
       
   713       profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
       
   714 
       
   715       return NULL;
       
   716     }
       
   717   else
       
   718     {
       
   719       p = standard_realloc (mem ? p : NULL, sizeof (gsize) * 2 + n_bytes);
       
   720 
       
   721       if (p)
       
   722 	{
       
   723 	  if (mem)
       
   724 	    profiler_log (PROFILER_FREE | PROFILER_RELOC, p[1], TRUE);
       
   725 	  p[0] = 0;
       
   726 	  p[1] = n_bytes;
       
   727 	  profiler_log (PROFILER_ALLOC | PROFILER_RELOC, p[1], TRUE);
       
   728 	  p += 2;
       
   729 	}
       
   730       else
       
   731 	profiler_log (PROFILER_ALLOC | PROFILER_RELOC, n_bytes, FALSE);
       
   732 
       
   733       return p;
       
   734     }
       
   735 }
       
   736 
       
   737 static gpointer
       
   738 profiler_realloc (gpointer mem,
       
   739 		  gsize    n_bytes)
       
   740 {
       
   741   mem = profiler_try_realloc (mem, n_bytes);
       
   742 
       
   743   if (!mem)
       
   744     g_mem_profile ();
       
   745 
       
   746   return mem;
       
   747 }
       
   748 
       
   749 #if EMULATOR
       
   750 
       
   751 PLS(profiler_table,gmem,GMemVTable)
       
   752 #define profiler_table (*FUNCTION_NAME(profiler_table,gmem)())
       
   753 
       
   754 const GMemVTable temp_profiler_table = {
       
   755   profiler_malloc,
       
   756   profiler_realloc,
       
   757   profiler_free,
       
   758   profiler_calloc,
       
   759   profiler_try_malloc,
       
   760   profiler_try_realloc,
       
   761 };
       
   762 
       
   763 
       
   764 #else
       
   765 
       
   766 static GMemVTable profiler_table = {
       
   767   profiler_malloc,
       
   768   profiler_realloc,
       
   769   profiler_free,
       
   770   profiler_calloc,
       
   771   profiler_try_malloc,
       
   772   profiler_try_realloc,
       
   773 };
       
   774 
       
   775 #endif /* EMULATOR */
       
   776 #if !(EMULATOR)
       
   777 GMemVTable *glib_mem_profiler_table = &profiler_table;
       
   778 #endif /* EMULATOR */
       
   779 
       
   780 #ifdef __SYMBIAN32__
       
   781 EXPORT_C GMemVTable ** _glib_mem_profiler_table(void)
       
   782 {
       
   783 	return &glib_mem_profiler_table;
       
   784 }
       
   785 #endif /* __SYMBIAN32__ */
       
   786 
       
   787 #endif	/* !G_DISABLE_CHECKS */
       
   788 
       
   789 /* --- MemChunks --- */
       
   790 #ifndef G_ALLOC_AND_FREE
       
   791 typedef struct _GAllocator GAllocator;
       
   792 typedef struct _GMemChunk  GMemChunk;
       
   793 #define G_ALLOC_ONLY	  1
       
   794 #define G_ALLOC_AND_FREE  2
       
   795 #endif
       
   796 
       
   797 struct _GMemChunk {
       
   798   guint alloc_size;           /* the size of an atom */
       
   799 };
       
   800 
       
   801 EXPORT_C GMemChunk*
       
   802 g_mem_chunk_new (const gchar  *name,
       
   803 		 gint          atom_size,
       
   804 		 gsize         area_size,
       
   805 		 gint          type)
       
   806 {
       
   807   GMemChunk *mem_chunk;
       
   808   g_return_val_if_fail (atom_size > 0, NULL);
       
   809 
       
   810   mem_chunk = g_slice_new (GMemChunk);
       
   811   mem_chunk->alloc_size = atom_size;
       
   812   return mem_chunk;
       
   813 }
       
   814 
       
   815 EXPORT_C void
       
   816 g_mem_chunk_destroy (GMemChunk *mem_chunk)
       
   817 {
       
   818   g_return_if_fail (mem_chunk != NULL);
       
   819   
       
   820   g_slice_free (GMemChunk, mem_chunk);
       
   821 }
       
   822 
       
   823 EXPORT_C gpointer
       
   824 g_mem_chunk_alloc (GMemChunk *mem_chunk)
       
   825 {
       
   826   g_return_val_if_fail (mem_chunk != NULL, NULL);
       
   827   
       
   828   return g_slice_alloc (mem_chunk->alloc_size);
       
   829 }
       
   830 
       
   831 EXPORT_C gpointer
       
   832 g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
       
   833 {
       
   834   g_return_val_if_fail (mem_chunk != NULL, NULL);
       
   835   
       
   836   return g_slice_alloc0 (mem_chunk->alloc_size);
       
   837 }
       
   838 
       
   839 EXPORT_C void
       
   840 g_mem_chunk_free (GMemChunk *mem_chunk,
       
   841 		  gpointer   mem)
       
   842 {
       
   843   g_return_if_fail (mem_chunk != NULL);
       
   844   
       
   845   g_slice_free1 (mem_chunk->alloc_size, mem);
       
   846 }
       
   847 
       
   848 EXPORT_C void	g_mem_chunk_clean	(GMemChunk *mem_chunk)	{}
       
   849 EXPORT_C void	g_mem_chunk_reset	(GMemChunk *mem_chunk)	{}
       
   850 EXPORT_C void	g_mem_chunk_print	(GMemChunk *mem_chunk)	{}
       
   851 EXPORT_C void	g_mem_chunk_info	(void)			{}
       
   852 EXPORT_C void	g_blow_chunks		(void)			{}
       
   853 
       
   854 #if EMULATOR
       
   855 
       
   856 PLS(dummy ,g_allocator_new,struct _GAllocator)
       
   857 #define dummy  (*FUNCTION_NAME(dummy ,g_allocator_new)())
       
   858 
       
   859 #endif /* EMULATOR */
       
   860 
       
   861 EXPORT_C GAllocator*
       
   862 g_allocator_new (const gchar *name,
       
   863 		 guint        n_preallocs)
       
   864 {
       
   865   #if !(EMULATOR)
       
   866   static struct _GAllocator {
       
   867     gchar      *name;
       
   868     guint16     n_preallocs;
       
   869     guint       is_unused : 1;
       
   870     guint       type : 4;
       
   871     GAllocator *last;
       
   872     GMemChunk  *mem_chunk;
       
   873     gpointer    free_list;
       
   874   } dummy = {
       
   875     "GAllocator is deprecated", 1, TRUE, 0, NULL, NULL, NULL,
       
   876   };
       
   877   #endif /* !(EMULATOR)
       
   878   /* some (broken) GAllocator uses depend on non-NULL allocators */
       
   879   return (void*) &dummy;
       
   880 }
       
   881 
       
   882 #if EMULATOR
       
   883 #undef dummy
       
   884 #endif /* EMULATOR */
       
   885 
       
   886 EXPORT_C void
       
   887 g_allocator_free (GAllocator *allocator)
       
   888 {
       
   889 }
       
   890 
       
   891 #if EMULATOR
       
   892 
       
   893 PLS(g_mem_gc_friendly ,gmem,gboolean)
       
   894 #define g_mem_gc_friendly  (*FUNCTION_NAME(g_mem_gc_friendly ,gmem)())
       
   895 
       
   896 #else
       
   897 
       
   898 #ifdef ENABLE_GC_FRIENDLY_DEFAULT
       
   899 gboolean g_mem_gc_friendly = TRUE;
       
   900 #else
       
   901 gboolean g_mem_gc_friendly = FALSE;
       
   902 #endif
       
   903 
       
   904 #endif /* EMULATOR */
       
   905 
       
   906 #ifdef __SYMBIAN32__
       
   907 EXPORT_C gboolean * _g_mem_gc_friendly(void)
       
   908 {
       
   909 	return &g_mem_gc_friendly;
       
   910 }
       
   911 #endif /* __SYMBIAN32__ */
       
   912 static void
       
   913 g_mem_init_nomessage (void)
       
   914 {
       
   915   gchar buffer[1024];
       
   916   const gchar *val;
       
   917   const GDebugKey keys[] = {
       
   918     { "gc-friendly", 1 },
       
   919   };
       
   920   gint flags;
       
   921   #ifdef __SYMBIAN32__
       
   922   memcpy(&glib_mem_vtable, &glib_mem_vtable_temp, sizeof(GMemVTable));
       
   923   #endif//__SYMBIAN32__
       
   924   if (g_mem_initialized)
       
   925     return;
       
   926   /* don't use g_malloc/g_message here */
       
   927   val = _g_getenv_nomalloc ("G_DEBUG", buffer);
       
   928   flags = !val ? 0 : g_parse_debug_string (val, keys, G_N_ELEMENTS (keys));
       
   929   if (flags & 1)        /* gc-friendly */
       
   930     {
       
   931       g_mem_gc_friendly = TRUE;
       
   932     }
       
   933   g_mem_initialized = TRUE;
       
   934 }
       
   935 
       
   936 void
       
   937 _g_mem_thread_init_noprivate_nomessage (void)
       
   938 {
       
   939   /* we may only create mutexes here, locking/
       
   940    * unlocking a mutex does not yet work.
       
   941    */
       
   942   g_mem_init_nomessage();
       
   943 #ifndef G_DISABLE_CHECKS
       
   944   gmem_profile_mutex = g_mutex_new ();
       
   945 #endif
       
   946 }
       
   947 
       
   948 #define __G_MEM_C__
       
   949 #include "galiasdef.c"