|
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" |