00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif
00034
00035 #include <stdlib.h>
00036 #include <string.h>
00037 #include "glib.h"
00038
00039
00040
00041
00042 #define MEM_PROFILE_TABLE_SIZE 8192
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061 #if defined(ENABLE_MEM_PROFILE) && defined(ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS)
00062 #define ENTER_MEM_CHUNK_ROUTINE() \
00063 g_private_set (allocating_for_mem_chunk, \
00064 g_private_get (allocating_for_mem_chunk) + 1)
00065 #define LEAVE_MEM_CHUNK_ROUTINE() \
00066 g_private_set (allocating_for_mem_chunk, \
00067 g_private_get (allocating_for_mem_chunk) - 1)
00068 #else
00069 #define ENTER_MEM_CHUNK_ROUTINE()
00070 #define LEAVE_MEM_CHUNK_ROUTINE()
00071 #endif
00072
00073
00074 #define MEM_AREA_SIZE 4L
00075
00076 #if SIZEOF_VOID_P > SIZEOF_LONG
00077 #define MEM_ALIGN SIZEOF_VOID_P
00078 #else
00079 #define MEM_ALIGN SIZEOF_LONG
00080 #endif
00081
00082
00083 typedef struct _GFreeAtom GFreeAtom;
00084 typedef struct _GMemArea GMemArea;
00085 typedef struct _GRealMemChunk GRealMemChunk;
00086
00087 struct _GFreeAtom
00088 {
00089 GFreeAtom *next;
00090 };
00091
00092 struct _GMemArea
00093 {
00094 GMemArea *next;
00095 GMemArea *prev;
00096 gulong index;
00097 gulong free;
00098 gulong allocated;
00099 gulong mark;
00100 gchar mem[MEM_AREA_SIZE];
00101
00102
00103
00104
00105
00106
00107 };
00108
00109 struct _GRealMemChunk
00110 {
00111 gchar *name;
00112 gint type;
00113 gint num_mem_areas;
00114 gint num_marked_areas;
00115 guint atom_size;
00116 gulong area_size;
00117 GMemArea *mem_area;
00118 GMemArea *mem_areas;
00119 GMemArea *free_mem_area;
00120 GFreeAtom *free_atoms;
00121 GTree *mem_tree;
00122 GRealMemChunk *next;
00123 GRealMemChunk *prev;
00124 };
00125
00126
00127 static gulong g_mem_chunk_compute_size (gulong size,
00128 gulong min_size);
00129 static gint g_mem_chunk_area_compare (GMemArea *a,
00130 GMemArea *b);
00131 static gint g_mem_chunk_area_search (GMemArea *a,
00132 gchar *addr);
00133
00134
00135
00136
00137 static GMutex* mem_chunks_lock = NULL;
00138 static GRealMemChunk *mem_chunks = NULL;
00139
00140 #ifdef ENABLE_MEM_PROFILE
00141 static GMutex* mem_profile_lock;
00142 static gulong allocations[MEM_PROFILE_TABLE_SIZE] = { 0 };
00143 static gulong allocated_mem = 0;
00144 static gulong freed_mem = 0;
00145 static GPrivate* allocating_for_mem_chunk = NULL;
00146 #define IS_IN_MEM_CHUNK_ROUTINE() \
00147 GPOINTER_TO_UINT (g_private_get (allocating_for_mem_chunk))
00148 #endif
00149
00150
00151 #ifndef USE_DMALLOC
00152
00153 gpointer
00154 g_malloc (gulong size)
00155 {
00156 gpointer p;
00157
00158
00159 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00160 gulong *t;
00161 #endif
00162
00163
00164 if (size == 0)
00165 return NULL;
00166
00167
00168 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00169 size += SIZEOF_LONG;
00170 #endif
00171
00172 #ifdef ENABLE_MEM_CHECK
00173 size += SIZEOF_LONG;
00174 #endif
00175
00176
00177 p = (gpointer) malloc (size);
00178 if (!p)
00179 g_error ("could not allocate %ld bytes", size);
00180
00181
00182 #ifdef ENABLE_MEM_CHECK
00183 size -= SIZEOF_LONG;
00184
00185 t = p;
00186 p = ((guchar*) p + SIZEOF_LONG);
00187 *t = 0;
00188 #endif
00189
00190 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00191 size -= SIZEOF_LONG;
00192
00193 t = p;
00194 p = ((guchar*) p + SIZEOF_LONG);
00195 *t = size;
00196
00197 #ifdef ENABLE_MEM_PROFILE
00198 g_mutex_lock (mem_profile_lock);
00199 # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00200 if(!IS_IN_MEM_CHUNK_ROUTINE()) {
00201 # endif
00202 if (size <= MEM_PROFILE_TABLE_SIZE - 1)
00203 allocations[size-1] += 1;
00204 else
00205 allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
00206 allocated_mem += size;
00207 # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00208 }
00209 # endif
00210 g_mutex_unlock (mem_profile_lock);
00211 #endif
00212 #endif
00213
00214
00215 return p;
00216 }
00217
00218 gpointer
00219 g_malloc0 (gulong size)
00220 {
00221 gpointer p;
00222
00223
00224 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00225 gulong *t;
00226 #endif
00227
00228
00229 if (size == 0)
00230 return NULL;
00231
00232
00233 #if defined (ENABLE_MEM_PROFILE) || defined (ENABLE_MEM_CHECK)
00234 size += SIZEOF_LONG;
00235 #endif
00236
00237 #ifdef ENABLE_MEM_CHECK
00238 size += SIZEOF_LONG;
00239 #endif
00240
00241
00242 p = (gpointer) calloc (size, 1);
00243 if (!p)
00244 g_error ("could not allocate %ld bytes", size);
00245
00246
00247 #ifdef ENABLE_MEM_CHECK
00248 size -= SIZEOF_LONG;
00249
00250 t = p;
00251 p = ((guchar*) p + SIZEOF_LONG);
00252 *t = 0;
00253 #endif
00254
00255 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00256 size -= SIZEOF_LONG;
00257
00258 t = p;
00259 p = ((guchar*) p + SIZEOF_LONG);
00260 *t = size;
00261
00262 # ifdef ENABLE_MEM_PROFILE
00263 g_mutex_lock (mem_profile_lock);
00264 # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00265 if(!IS_IN_MEM_CHUNK_ROUTINE()) {
00266 # endif
00267 if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
00268 allocations[size-1] += 1;
00269 else
00270 allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
00271 allocated_mem += size;
00272 # ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00273 }
00274 # endif
00275 g_mutex_unlock (mem_profile_lock);
00276 # endif
00277 #endif
00278
00279
00280 return p;
00281 }
00282
00283 gpointer
00284 g_realloc (gpointer mem,
00285 gulong size)
00286 {
00287 gpointer p;
00288
00289 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00290 gulong *t;
00291 #endif
00292
00293
00294 if (size == 0)
00295 {
00296 g_free (mem);
00297
00298 return NULL;
00299 }
00300
00301
00302 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00303 size += SIZEOF_LONG;
00304 #endif
00305
00306 #ifdef ENABLE_MEM_CHECK
00307 size += SIZEOF_LONG;
00308 #endif
00309
00310
00311 if (!mem)
00312 {
00313 #ifdef REALLOC_0_WORKS
00314 p = (gpointer) realloc (NULL, size);
00315 #else
00316 p = (gpointer) malloc (size);
00317 #endif
00318 }
00319 else
00320 {
00321 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00322 t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00323 #ifdef ENABLE_MEM_PROFILE
00324 g_mutex_lock (mem_profile_lock);
00325 freed_mem += *t;
00326 g_mutex_unlock (mem_profile_lock);
00327 #endif
00328 mem = t;
00329 #endif
00330
00331 #ifdef ENABLE_MEM_CHECK
00332 t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00333 if (*t >= 1)
00334 g_warning ("trying to realloc freed memory\n");
00335 mem = t;
00336 #endif
00337
00338 p = (gpointer) realloc (mem, size);
00339 }
00340
00341 if (!p)
00342 g_error ("could not reallocate %lu bytes", (gulong) size);
00343
00344
00345 #ifdef ENABLE_MEM_CHECK
00346 size -= SIZEOF_LONG;
00347
00348 t = p;
00349 p = ((guchar*) p + SIZEOF_LONG);
00350 *t = 0;
00351 #endif
00352
00353 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00354 size -= SIZEOF_LONG;
00355
00356 t = p;
00357 p = ((guchar*) p + SIZEOF_LONG);
00358 *t = size;
00359
00360 #ifdef ENABLE_MEM_PROFILE
00361 g_mutex_lock (mem_profile_lock);
00362 #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00363 if(!IS_IN_MEM_CHUNK_ROUTINE()) {
00364 #endif
00365 if (size <= (MEM_PROFILE_TABLE_SIZE - 1))
00366 allocations[size-1] += 1;
00367 else
00368 allocations[MEM_PROFILE_TABLE_SIZE - 1] += 1;
00369 allocated_mem += size;
00370 #ifdef ENABLE_MEM_PROFILE_EXCLUDES_MEM_CHUNKS
00371 }
00372 #endif
00373 g_mutex_unlock (mem_profile_lock);
00374 #endif
00375 #endif
00376
00377
00378 return p;
00379 }
00380
00381 void
00382 g_free (gpointer mem)
00383 {
00384 if (mem)
00385 {
00386 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00387 gulong *t;
00388 gulong size;
00389 #endif
00390
00391 #if defined(ENABLE_MEM_PROFILE) || defined(ENABLE_MEM_CHECK)
00392 t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00393 size = *t;
00394 #ifdef ENABLE_MEM_PROFILE
00395 g_mutex_lock (mem_profile_lock);
00396 freed_mem += size;
00397 g_mutex_unlock (mem_profile_lock);
00398 #endif
00399 mem = t;
00400 #endif
00401
00402 #ifdef ENABLE_MEM_CHECK
00403 t = (gulong*) ((guchar*) mem - SIZEOF_LONG);
00404 if (*t >= 1)
00405 g_warning ("freeing previously freed (%lu times) memory\n", *t);
00406 *t += 1;
00407 mem = t;
00408
00409 memset ((guchar*) mem + 2 * SIZEOF_LONG, 0, size);
00410 #else
00411 free (mem);
00412 #endif
00413 }
00414 }
00415
00416 #endif
00417
00418
00419 void
00420 g_mem_profile (void)
00421 {
00422 #ifdef ENABLE_MEM_PROFILE
00423 gint i;
00424 gulong local_allocations[MEM_PROFILE_TABLE_SIZE];
00425 gulong local_allocated_mem;
00426 gulong local_freed_mem;
00427
00428 g_mutex_lock (mem_profile_lock);
00429 for (i = 0; i < MEM_PROFILE_TABLE_SIZE; i++)
00430 local_allocations[i] = allocations[i];
00431 local_allocated_mem = allocated_mem;
00432 local_freed_mem = freed_mem;
00433 g_mutex_unlock (mem_profile_lock);
00434
00435 for (i = 0; i < (MEM_PROFILE_TABLE_SIZE - 1); i++)
00436 if (local_allocations[i] > 0)
00437 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
00438 "%lu allocations of %d bytes", local_allocations[i], i + 1);
00439
00440 if (local_allocations[MEM_PROFILE_TABLE_SIZE - 1] > 0)
00441 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
00442 "%lu allocations of greater than %d bytes",
00443 local_allocations[MEM_PROFILE_TABLE_SIZE - 1], MEM_PROFILE_TABLE_SIZE - 1);
00444 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes allocated", local_allocated_mem);
00445 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes freed", local_freed_mem);
00446 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%lu bytes in use", local_allocated_mem - local_freed_mem);
00447 #endif
00448 }
00449
00450 void
00451 g_mem_check (gpointer mem)
00452 {
00453 #ifdef ENABLE_MEM_CHECK
00454 gulong *t;
00455
00456 t = (gulong*) ((guchar*) mem - SIZEOF_LONG - SIZEOF_LONG);
00457
00458 if (*t >= 1)
00459 g_warning ("mem: 0x%08lx has been freed %lu times\n", (gulong) mem, *t);
00460 #endif
00461 }
00462
00463 GMemChunk*
00464 g_mem_chunk_new (gchar *name,
00465 gint atom_size,
00466 gulong area_size,
00467 gint type)
00468 {
00469 GRealMemChunk *mem_chunk;
00470 gulong rarea_size;
00471
00472 g_return_val_if_fail (atom_size > 0, NULL);
00473 g_return_val_if_fail (area_size >= atom_size, NULL);
00474
00475 ENTER_MEM_CHUNK_ROUTINE();
00476
00477 area_size = (area_size + atom_size - 1) / atom_size;
00478 area_size *= atom_size;
00479
00480 mem_chunk = g_new (struct _GRealMemChunk, 1);
00481 mem_chunk->name = name;
00482 mem_chunk->type = type;
00483 mem_chunk->num_mem_areas = 0;
00484 mem_chunk->num_marked_areas = 0;
00485 mem_chunk->mem_area = NULL;
00486 mem_chunk->free_mem_area = NULL;
00487 mem_chunk->free_atoms = NULL;
00488 mem_chunk->mem_tree = NULL;
00489 mem_chunk->mem_areas = NULL;
00490 mem_chunk->atom_size = atom_size;
00491
00492 if (mem_chunk->type == G_ALLOC_AND_FREE)
00493 mem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
00494
00495 if (mem_chunk->atom_size % MEM_ALIGN)
00496 mem_chunk->atom_size += MEM_ALIGN - (mem_chunk->atom_size % MEM_ALIGN);
00497
00498 rarea_size = area_size + sizeof (GMemArea) - MEM_AREA_SIZE;
00499 rarea_size = g_mem_chunk_compute_size (rarea_size, atom_size + sizeof (GMemArea) - MEM_AREA_SIZE);
00500 mem_chunk->area_size = rarea_size - (sizeof (GMemArea) - MEM_AREA_SIZE);
00501
00502 g_mutex_lock (mem_chunks_lock);
00503 mem_chunk->next = mem_chunks;
00504 mem_chunk->prev = NULL;
00505 if (mem_chunks)
00506 mem_chunks->prev = mem_chunk;
00507 mem_chunks = mem_chunk;
00508 g_mutex_unlock (mem_chunks_lock);
00509
00510 LEAVE_MEM_CHUNK_ROUTINE();
00511
00512 return ((GMemChunk*) mem_chunk);
00513 }
00514
00515 void
00516 g_mem_chunk_destroy (GMemChunk *mem_chunk)
00517 {
00518 GRealMemChunk *rmem_chunk;
00519 GMemArea *mem_areas;
00520 GMemArea *temp_area;
00521
00522 g_return_if_fail (mem_chunk != NULL);
00523
00524 ENTER_MEM_CHUNK_ROUTINE();
00525
00526 rmem_chunk = (GRealMemChunk*) mem_chunk;
00527
00528 mem_areas = rmem_chunk->mem_areas;
00529 while (mem_areas)
00530 {
00531 temp_area = mem_areas;
00532 mem_areas = mem_areas->next;
00533 g_free (temp_area);
00534 }
00535
00536 if (rmem_chunk->next)
00537 rmem_chunk->next->prev = rmem_chunk->prev;
00538 if (rmem_chunk->prev)
00539 rmem_chunk->prev->next = rmem_chunk->next;
00540
00541 g_mutex_lock (mem_chunks_lock);
00542 if (rmem_chunk == mem_chunks)
00543 mem_chunks = mem_chunks->next;
00544 g_mutex_unlock (mem_chunks_lock);
00545
00546 if (rmem_chunk->type == G_ALLOC_AND_FREE)
00547 g_tree_destroy (rmem_chunk->mem_tree);
00548
00549 g_free (rmem_chunk);
00550
00551 LEAVE_MEM_CHUNK_ROUTINE();
00552 }
00553
00554 gpointer
00555 g_mem_chunk_alloc (GMemChunk *mem_chunk)
00556 {
00557 GRealMemChunk *rmem_chunk;
00558 GMemArea *temp_area;
00559 gpointer mem;
00560
00561 ENTER_MEM_CHUNK_ROUTINE();
00562
00563 g_return_val_if_fail (mem_chunk != NULL, NULL);
00564
00565 rmem_chunk = (GRealMemChunk*) mem_chunk;
00566
00567 while (rmem_chunk->free_atoms)
00568 {
00569
00570
00571
00572
00573
00574 mem = rmem_chunk->free_atoms;
00575 rmem_chunk->free_atoms = rmem_chunk->free_atoms->next;
00576
00577
00578 temp_area = g_tree_search (rmem_chunk->mem_tree,
00579 (GSearchFunc) g_mem_chunk_area_search,
00580 mem);
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594 if (temp_area->mark)
00595 {
00596
00597 temp_area->free += rmem_chunk->atom_size;
00598
00599 if (temp_area->free == rmem_chunk->area_size)
00600 {
00601 if (temp_area == rmem_chunk->mem_area)
00602 rmem_chunk->mem_area = NULL;
00603
00604 if (rmem_chunk->free_mem_area)
00605 {
00606 rmem_chunk->num_mem_areas -= 1;
00607
00608 if (temp_area->next)
00609 temp_area->next->prev = temp_area->prev;
00610 if (temp_area->prev)
00611 temp_area->prev->next = temp_area->next;
00612 if (temp_area == rmem_chunk->mem_areas)
00613 rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
00614
00615 if (rmem_chunk->type == G_ALLOC_AND_FREE)
00616 g_tree_remove (rmem_chunk->mem_tree, temp_area);
00617 g_free (temp_area);
00618 }
00619 else
00620 rmem_chunk->free_mem_area = temp_area;
00621
00622 rmem_chunk->num_marked_areas -= 1;
00623 }
00624 }
00625 else
00626 {
00627
00628
00629 temp_area->allocated += 1;
00630
00631
00632
00633 goto outa_here;
00634 }
00635 }
00636
00637
00638
00639
00640
00641 if ((!rmem_chunk->mem_area) ||
00642 ((rmem_chunk->mem_area->index + rmem_chunk->atom_size) > rmem_chunk->area_size))
00643 {
00644 if (rmem_chunk->free_mem_area)
00645 {
00646 rmem_chunk->mem_area = rmem_chunk->free_mem_area;
00647 rmem_chunk->free_mem_area = NULL;
00648 }
00649 else
00650 {
00651 rmem_chunk->mem_area = (GMemArea*) g_malloc (sizeof (GMemArea) -
00652 MEM_AREA_SIZE +
00653 rmem_chunk->area_size);
00654
00655 rmem_chunk->num_mem_areas += 1;
00656 rmem_chunk->mem_area->next = rmem_chunk->mem_areas;
00657 rmem_chunk->mem_area->prev = NULL;
00658
00659 if (rmem_chunk->mem_areas)
00660 rmem_chunk->mem_areas->prev = rmem_chunk->mem_area;
00661 rmem_chunk->mem_areas = rmem_chunk->mem_area;
00662
00663 if (rmem_chunk->type == G_ALLOC_AND_FREE)
00664 g_tree_insert (rmem_chunk->mem_tree, rmem_chunk->mem_area, rmem_chunk->mem_area);
00665 }
00666
00667 rmem_chunk->mem_area->index = 0;
00668 rmem_chunk->mem_area->free = rmem_chunk->area_size;
00669 rmem_chunk->mem_area->allocated = 0;
00670 rmem_chunk->mem_area->mark = 0;
00671 }
00672
00673
00674
00675 mem = (gpointer) &rmem_chunk->mem_area->mem[rmem_chunk->mem_area->index];
00676 rmem_chunk->mem_area->index += rmem_chunk->atom_size;
00677 rmem_chunk->mem_area->free -= rmem_chunk->atom_size;
00678 rmem_chunk->mem_area->allocated += 1;
00679
00680 outa_here:
00681
00682 LEAVE_MEM_CHUNK_ROUTINE();
00683
00684 return mem;
00685 }
00686
00687 gpointer
00688 g_mem_chunk_alloc0 (GMemChunk *mem_chunk)
00689 {
00690 gpointer mem;
00691
00692 mem = g_mem_chunk_alloc (mem_chunk);
00693 if (mem)
00694 {
00695 GRealMemChunk *rmem_chunk = (GRealMemChunk*) mem_chunk;
00696
00697 memset (mem, 0, rmem_chunk->atom_size);
00698 }
00699
00700 return mem;
00701 }
00702
00703 void
00704 g_mem_chunk_free (GMemChunk *mem_chunk,
00705 gpointer mem)
00706 {
00707 GRealMemChunk *rmem_chunk;
00708 GMemArea *temp_area;
00709 GFreeAtom *free_atom;
00710
00711 g_return_if_fail (mem_chunk != NULL);
00712 g_return_if_fail (mem != NULL);
00713
00714 ENTER_MEM_CHUNK_ROUTINE();
00715
00716 rmem_chunk = (GRealMemChunk*) mem_chunk;
00717
00718
00719
00720 if (rmem_chunk->type == G_ALLOC_AND_FREE)
00721 {
00722
00723
00724 free_atom = (GFreeAtom*) mem;
00725 free_atom->next = rmem_chunk->free_atoms;
00726 rmem_chunk->free_atoms = free_atom;
00727
00728 temp_area = g_tree_search (rmem_chunk->mem_tree,
00729 (GSearchFunc) g_mem_chunk_area_search,
00730 mem);
00731
00732 temp_area->allocated -= 1;
00733
00734 if (temp_area->allocated == 0)
00735 {
00736 temp_area->mark = 1;
00737 rmem_chunk->num_marked_areas += 1;
00738 }
00739 }
00740
00741 LEAVE_MEM_CHUNK_ROUTINE();
00742 }
00743
00744
00745 void
00746 g_mem_chunk_clean (GMemChunk *mem_chunk)
00747 {
00748 GRealMemChunk *rmem_chunk;
00749 GMemArea *mem_area;
00750 GFreeAtom *prev_free_atom;
00751 GFreeAtom *temp_free_atom;
00752 gpointer mem;
00753
00754 g_return_if_fail (mem_chunk != NULL);
00755
00756 rmem_chunk = (GRealMemChunk*) mem_chunk;
00757
00758 if (rmem_chunk->type == G_ALLOC_AND_FREE)
00759 {
00760 prev_free_atom = NULL;
00761 temp_free_atom = rmem_chunk->free_atoms;
00762
00763 while (temp_free_atom)
00764 {
00765 mem = (gpointer) temp_free_atom;
00766
00767 mem_area = g_tree_search (rmem_chunk->mem_tree,
00768 (GSearchFunc) g_mem_chunk_area_search,
00769 mem);
00770
00771
00772
00773
00774 if (mem_area->mark)
00775 {
00776 if (prev_free_atom)
00777 prev_free_atom->next = temp_free_atom->next;
00778 else
00779 rmem_chunk->free_atoms = temp_free_atom->next;
00780 temp_free_atom = temp_free_atom->next;
00781
00782 mem_area->free += rmem_chunk->atom_size;
00783 if (mem_area->free == rmem_chunk->area_size)
00784 {
00785 rmem_chunk->num_mem_areas -= 1;
00786 rmem_chunk->num_marked_areas -= 1;
00787
00788 if (mem_area->next)
00789 mem_area->next->prev = mem_area->prev;
00790 if (mem_area->prev)
00791 mem_area->prev->next = mem_area->next;
00792 if (mem_area == rmem_chunk->mem_areas)
00793 rmem_chunk->mem_areas = rmem_chunk->mem_areas->next;
00794 if (mem_area == rmem_chunk->mem_area)
00795 rmem_chunk->mem_area = NULL;
00796
00797 if (rmem_chunk->type == G_ALLOC_AND_FREE)
00798 g_tree_remove (rmem_chunk->mem_tree, mem_area);
00799 g_free (mem_area);
00800 }
00801 }
00802 else
00803 {
00804 prev_free_atom = temp_free_atom;
00805 temp_free_atom = temp_free_atom->next;
00806 }
00807 }
00808 }
00809 }
00810
00811 void
00812 g_mem_chunk_reset (GMemChunk *mem_chunk)
00813 {
00814 GRealMemChunk *rmem_chunk;
00815 GMemArea *mem_areas;
00816 GMemArea *temp_area;
00817
00818 g_return_if_fail (mem_chunk != NULL);
00819
00820 rmem_chunk = (GRealMemChunk*) mem_chunk;
00821
00822 mem_areas = rmem_chunk->mem_areas;
00823 rmem_chunk->num_mem_areas = 0;
00824 rmem_chunk->mem_areas = NULL;
00825 rmem_chunk->mem_area = NULL;
00826
00827 while (mem_areas)
00828 {
00829 temp_area = mem_areas;
00830 mem_areas = mem_areas->next;
00831 g_free (temp_area);
00832 }
00833
00834 rmem_chunk->free_atoms = NULL;
00835
00836 if (rmem_chunk->mem_tree)
00837 g_tree_destroy (rmem_chunk->mem_tree);
00838 rmem_chunk->mem_tree = g_tree_new ((GCompareFunc) g_mem_chunk_area_compare);
00839 }
00840
00841 void
00842 g_mem_chunk_print (GMemChunk *mem_chunk)
00843 {
00844 GRealMemChunk *rmem_chunk;
00845 GMemArea *mem_areas;
00846 gulong mem;
00847
00848 g_return_if_fail (mem_chunk != NULL);
00849
00850 rmem_chunk = (GRealMemChunk*) mem_chunk;
00851 mem_areas = rmem_chunk->mem_areas;
00852 mem = 0;
00853
00854 while (mem_areas)
00855 {
00856 mem += rmem_chunk->area_size - mem_areas->free;
00857 mem_areas = mem_areas->next;
00858 }
00859
00860 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO,
00861 "%s: %ld bytes using %d mem areas",
00862 rmem_chunk->name, mem, rmem_chunk->num_mem_areas);
00863 }
00864
00865 void
00866 g_mem_chunk_info (void)
00867 {
00868 GRealMemChunk *mem_chunk;
00869 gint count;
00870
00871 count = 0;
00872 g_mutex_lock (mem_chunks_lock);
00873 mem_chunk = mem_chunks;
00874 while (mem_chunk)
00875 {
00876 count += 1;
00877 mem_chunk = mem_chunk->next;
00878 }
00879 g_mutex_unlock (mem_chunks_lock);
00880
00881 g_log (g_log_domain_glib, G_LOG_LEVEL_INFO, "%d mem chunks", count);
00882
00883 g_mutex_lock (mem_chunks_lock);
00884 mem_chunk = mem_chunks;
00885 g_mutex_unlock (mem_chunks_lock);
00886
00887 while (mem_chunk)
00888 {
00889 g_mem_chunk_print ((GMemChunk*) mem_chunk);
00890 mem_chunk = mem_chunk->next;
00891 }
00892 }
00893
00894 void
00895 g_blow_chunks (void)
00896 {
00897 GRealMemChunk *mem_chunk;
00898
00899 g_mutex_lock (mem_chunks_lock);
00900 mem_chunk = mem_chunks;
00901 g_mutex_unlock (mem_chunks_lock);
00902 while (mem_chunk)
00903 {
00904 g_mem_chunk_clean ((GMemChunk*) mem_chunk);
00905 mem_chunk = mem_chunk->next;
00906 }
00907 }
00908
00909
00910 static gulong
00911 g_mem_chunk_compute_size (gulong size,
00912 gulong min_size)
00913 {
00914 gulong power_of_2;
00915 gulong lower, upper;
00916
00917 power_of_2 = 16;
00918 while (power_of_2 < size)
00919 power_of_2 <<= 1;
00920
00921 lower = power_of_2 >> 1;
00922 upper = power_of_2;
00923
00924 if (size - lower < upper - size && lower >= min_size)
00925 return lower;
00926 else
00927 return upper;
00928 }
00929
00930 static gint
00931 g_mem_chunk_area_compare (GMemArea *a,
00932 GMemArea *b)
00933 {
00934 if (a->mem > b->mem)
00935 return 1;
00936 else if (a->mem < b->mem)
00937 return -1;
00938 return 0;
00939 }
00940
00941 static gint
00942 g_mem_chunk_area_search (GMemArea *a,
00943 gchar *addr)
00944 {
00945 if (a->mem <= addr)
00946 {
00947 if (addr < &a->mem[a->index])
00948 return 0;
00949 return 1;
00950 }
00951 return -1;
00952 }
00953
00954
00955
00956 struct _GAllocator
00957 {
00958 gchar *name;
00959 guint16 n_preallocs;
00960 guint is_unused : 1;
00961 guint type : 4;
00962 GAllocator *last;
00963 GMemChunk *mem_chunk;
00964 gpointer dummy;
00965 };
00966
00967 GAllocator*
00968 g_allocator_new (const gchar *name,
00969 guint n_preallocs)
00970 {
00971 GAllocator *allocator;
00972
00973 g_return_val_if_fail (name != NULL, NULL);
00974
00975 allocator = g_new0 (GAllocator, 1);
00976 allocator->name = g_strdup (name);
00977 allocator->n_preallocs = CLAMP (n_preallocs, 1, 65535);
00978 allocator->is_unused = TRUE;
00979 allocator->type = 0;
00980 allocator->last = NULL;
00981 allocator->mem_chunk = NULL;
00982 allocator->dummy = NULL;
00983
00984 return allocator;
00985 }
00986
00987 void
00988 g_allocator_free (GAllocator *allocator)
00989 {
00990 g_return_if_fail (allocator != NULL);
00991 g_return_if_fail (allocator->is_unused == TRUE);
00992
00993 g_free (allocator->name);
00994 if (allocator->mem_chunk)
00995 g_mem_chunk_destroy (allocator->mem_chunk);
00996
00997 g_free (allocator);
00998 }
00999
01000 void
01001 g_mem_init (void)
01002 {
01003 mem_chunks_lock = g_mutex_new();
01004 #ifdef ENABLE_MEM_PROFILE
01005 mem_profile_lock = g_mutex_new();
01006 allocating_for_mem_chunk = g_private_new(NULL);
01007 #endif
01008 }