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