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