Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenftdbgmem.c
Go to the documentation of this file.
00001 /***************************************************************************/ 00002 /* */ 00003 /* ftdbgmem.c */ 00004 /* */ 00005 /* Memory debugger (body). */ 00006 /* */ 00007 /* Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2009 by */ 00008 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 00009 /* */ 00010 /* This file is part of the FreeType project, and may only be used, */ 00011 /* modified, and distributed under the terms of the FreeType project */ 00012 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 00013 /* this file you indicate that you have read the license and */ 00014 /* understand and accept it fully. */ 00015 /* */ 00016 /***************************************************************************/ 00017 00018 00019 #include <ft2build.h> 00020 #include FT_CONFIG_CONFIG_H 00021 #include FT_INTERNAL_DEBUG_H 00022 #include FT_INTERNAL_MEMORY_H 00023 #include FT_SYSTEM_H 00024 #include FT_ERRORS_H 00025 #include FT_TYPES_H 00026 00027 00028 #ifdef FT_DEBUG_MEMORY 00029 00030 #define KEEPALIVE /* `Keep alive' means that freed blocks aren't released 00031 * to the heap. This is useful to detect double-frees 00032 * or weird heap corruption, but it uses large amounts of 00033 * memory, however. 00034 */ 00035 00036 #include FT_CONFIG_STANDARD_LIBRARY_H 00037 00038 FT_BASE_DEF( const char* ) _ft_debug_file = 0; 00039 FT_BASE_DEF( long ) _ft_debug_lineno = 0; 00040 00041 extern void 00042 FT_DumpMemory( FT_Memory memory ); 00043 00044 00045 typedef struct FT_MemSourceRec_* FT_MemSource; 00046 typedef struct FT_MemNodeRec_* FT_MemNode; 00047 typedef struct FT_MemTableRec_* FT_MemTable; 00048 00049 00050 #define FT_MEM_VAL( addr ) ((FT_PtrDist)(FT_Pointer)( addr )) 00051 00052 /* 00053 * This structure holds statistics for a single allocation/release 00054 * site. This is useful to know where memory operations happen the 00055 * most. 00056 */ 00057 typedef struct FT_MemSourceRec_ 00058 { 00059 const char* file_name; 00060 long line_no; 00061 00062 FT_Long cur_blocks; /* current number of allocated blocks */ 00063 FT_Long max_blocks; /* max. number of allocated blocks */ 00064 FT_Long all_blocks; /* total number of blocks allocated */ 00065 00066 FT_Long cur_size; /* current cumulative allocated size */ 00067 FT_Long max_size; /* maximum cumulative allocated size */ 00068 FT_Long all_size; /* total cumulative allocated size */ 00069 00070 FT_Long cur_max; /* current maximum allocated size */ 00071 00072 FT_UInt32 hash; 00073 FT_MemSource link; 00074 00075 } FT_MemSourceRec; 00076 00077 00078 /* 00079 * We don't need a resizable array for the memory sources, because 00080 * their number is pretty limited within FreeType. 00081 */ 00082 #define FT_MEM_SOURCE_BUCKETS 128 00083 00084 /* 00085 * This structure holds information related to a single allocated 00086 * memory block. If KEEPALIVE is defined, blocks that are freed by 00087 * FreeType are never released to the system. Instead, their `size' 00088 * field is set to -size. This is mainly useful to detect double frees, 00089 * at the price of large memory footprint during execution. 00090 */ 00091 typedef struct FT_MemNodeRec_ 00092 { 00093 FT_Byte* address; 00094 FT_Long size; /* < 0 if the block was freed */ 00095 00096 FT_MemSource source; 00097 00098 #ifdef KEEPALIVE 00099 const char* free_file_name; 00100 FT_Long free_line_no; 00101 #endif 00102 00103 FT_MemNode link; 00104 00105 } FT_MemNodeRec; 00106 00107 00108 /* 00109 * The global structure, containing compound statistics and all hash 00110 * tables. 00111 */ 00112 typedef struct FT_MemTableRec_ 00113 { 00114 FT_ULong size; 00115 FT_ULong nodes; 00116 FT_MemNode* buckets; 00117 00118 FT_ULong alloc_total; 00119 FT_ULong alloc_current; 00120 FT_ULong alloc_max; 00121 FT_ULong alloc_count; 00122 00123 FT_Bool bound_total; 00124 FT_ULong alloc_total_max; 00125 00126 FT_Bool bound_count; 00127 FT_ULong alloc_count_max; 00128 00129 FT_MemSource sources[FT_MEM_SOURCE_BUCKETS]; 00130 00131 FT_Bool keep_alive; 00132 00133 FT_Memory memory; 00134 FT_Pointer memory_user; 00135 FT_Alloc_Func alloc; 00136 FT_Free_Func free; 00137 FT_Realloc_Func realloc; 00138 00139 } FT_MemTableRec; 00140 00141 00142 #define FT_MEM_SIZE_MIN 7 00143 #define FT_MEM_SIZE_MAX 13845163 00144 00145 #define FT_FILENAME( x ) ((x) ? (x) : "unknown file") 00146 00147 00148 /* 00149 * Prime numbers are ugly to handle. It would be better to implement 00150 * L-Hashing, which is 10% faster and doesn't require divisions. 00151 */ 00152 static const FT_UInt ft_mem_primes[] = 00153 { 00154 7, 00155 11, 00156 19, 00157 37, 00158 73, 00159 109, 00160 163, 00161 251, 00162 367, 00163 557, 00164 823, 00165 1237, 00166 1861, 00167 2777, 00168 4177, 00169 6247, 00170 9371, 00171 14057, 00172 21089, 00173 31627, 00174 47431, 00175 71143, 00176 106721, 00177 160073, 00178 240101, 00179 360163, 00180 540217, 00181 810343, 00182 1215497, 00183 1823231, 00184 2734867, 00185 4102283, 00186 6153409, 00187 9230113, 00188 13845163, 00189 }; 00190 00191 00192 static FT_ULong 00193 ft_mem_closest_prime( FT_ULong num ) 00194 { 00195 FT_UInt i; 00196 00197 00198 for ( i = 0; 00199 i < sizeof ( ft_mem_primes ) / sizeof ( ft_mem_primes[0] ); i++ ) 00200 if ( ft_mem_primes[i] > num ) 00201 return ft_mem_primes[i]; 00202 00203 return FT_MEM_SIZE_MAX; 00204 } 00205 00206 00207 extern void 00208 ft_mem_debug_panic( const char* fmt, 00209 ... ) 00210 { 00211 va_list ap; 00212 00213 00214 printf( "FreeType.Debug: " ); 00215 00216 va_start( ap, fmt ); 00217 vprintf( fmt, ap ); 00218 va_end( ap ); 00219 00220 printf( "\n" ); 00221 exit( EXIT_FAILURE ); 00222 } 00223 00224 00225 static FT_Pointer 00226 ft_mem_table_alloc( FT_MemTable table, 00227 FT_Long size ) 00228 { 00229 FT_Memory memory = table->memory; 00230 FT_Pointer block; 00231 00232 00233 memory->user = table->memory_user; 00234 block = table->alloc( memory, size ); 00235 memory->user = table; 00236 00237 return block; 00238 } 00239 00240 00241 static void 00242 ft_mem_table_free( FT_MemTable table, 00243 FT_Pointer block ) 00244 { 00245 FT_Memory memory = table->memory; 00246 00247 00248 memory->user = table->memory_user; 00249 table->free( memory, block ); 00250 memory->user = table; 00251 } 00252 00253 00254 static void 00255 ft_mem_table_resize( FT_MemTable table ) 00256 { 00257 FT_ULong new_size; 00258 00259 00260 new_size = ft_mem_closest_prime( table->nodes ); 00261 if ( new_size != table->size ) 00262 { 00263 FT_MemNode* new_buckets; 00264 FT_ULong i; 00265 00266 00267 new_buckets = (FT_MemNode *) 00268 ft_mem_table_alloc( table, 00269 new_size * sizeof ( FT_MemNode ) ); 00270 if ( new_buckets == NULL ) 00271 return; 00272 00273 FT_ARRAY_ZERO( new_buckets, new_size ); 00274 00275 for ( i = 0; i < table->size; i++ ) 00276 { 00277 FT_MemNode node, next, *pnode; 00278 FT_PtrDist hash; 00279 00280 00281 node = table->buckets[i]; 00282 while ( node ) 00283 { 00284 next = node->link; 00285 hash = FT_MEM_VAL( node->address ) % new_size; 00286 pnode = new_buckets + hash; 00287 00288 node->link = pnode[0]; 00289 pnode[0] = node; 00290 00291 node = next; 00292 } 00293 } 00294 00295 if ( table->buckets ) 00296 ft_mem_table_free( table, table->buckets ); 00297 00298 table->buckets = new_buckets; 00299 table->size = new_size; 00300 } 00301 } 00302 00303 00304 static FT_MemTable 00305 ft_mem_table_new( FT_Memory memory ) 00306 { 00307 FT_MemTable table; 00308 00309 00310 table = (FT_MemTable)memory->alloc( memory, sizeof ( *table ) ); 00311 if ( table == NULL ) 00312 goto Exit; 00313 00314 FT_ZERO( table ); 00315 00316 table->size = FT_MEM_SIZE_MIN; 00317 table->nodes = 0; 00318 00319 table->memory = memory; 00320 00321 table->memory_user = memory->user; 00322 00323 table->alloc = memory->alloc; 00324 table->realloc = memory->realloc; 00325 table->free = memory->free; 00326 00327 table->buckets = (FT_MemNode *) 00328 memory->alloc( memory, 00329 table->size * sizeof ( FT_MemNode ) ); 00330 if ( table->buckets ) 00331 FT_ARRAY_ZERO( table->buckets, table->size ); 00332 else 00333 { 00334 memory->free( memory, table ); 00335 table = NULL; 00336 } 00337 00338 Exit: 00339 return table; 00340 } 00341 00342 00343 static void 00344 ft_mem_table_destroy( FT_MemTable table ) 00345 { 00346 FT_ULong i; 00347 00348 00349 FT_DumpMemory( table->memory ); 00350 00351 if ( table ) 00352 { 00353 FT_Long leak_count = 0; 00354 FT_ULong leaks = 0; 00355 00356 00357 /* remove all blocks from the table, revealing leaked ones */ 00358 for ( i = 0; i < table->size; i++ ) 00359 { 00360 FT_MemNode *pnode = table->buckets + i, next, node = *pnode; 00361 00362 00363 while ( node ) 00364 { 00365 next = node->link; 00366 node->link = 0; 00367 00368 if ( node->size > 0 ) 00369 { 00370 printf( 00371 "leaked memory block at address %p, size %8ld in (%s:%ld)\n", 00372 node->address, node->size, 00373 FT_FILENAME( node->source->file_name ), 00374 node->source->line_no ); 00375 00376 leak_count++; 00377 leaks += node->size; 00378 00379 ft_mem_table_free( table, node->address ); 00380 } 00381 00382 node->address = NULL; 00383 node->size = 0; 00384 00385 ft_mem_table_free( table, node ); 00386 node = next; 00387 } 00388 table->buckets[i] = 0; 00389 } 00390 00391 ft_mem_table_free( table, table->buckets ); 00392 table->buckets = NULL; 00393 00394 table->size = 0; 00395 table->nodes = 0; 00396 00397 /* remove all sources */ 00398 for ( i = 0; i < FT_MEM_SOURCE_BUCKETS; i++ ) 00399 { 00400 FT_MemSource source, next; 00401 00402 00403 for ( source = table->sources[i]; source != NULL; source = next ) 00404 { 00405 next = source->link; 00406 ft_mem_table_free( table, source ); 00407 } 00408 00409 table->sources[i] = NULL; 00410 } 00411 00412 printf( 00413 "FreeType: total memory allocations = %ld\n", table->alloc_total ); 00414 printf( 00415 "FreeType: maximum memory footprint = %ld\n", table->alloc_max ); 00416 00417 ft_mem_table_free( table, table ); 00418 00419 if ( leak_count > 0 ) 00420 ft_mem_debug_panic( 00421 "FreeType: %ld bytes of memory leaked in %ld blocks\n", 00422 leaks, leak_count ); 00423 00424 printf( "FreeType: no memory leaks detected\n" ); 00425 } 00426 } 00427 00428 00429 static FT_MemNode* 00430 ft_mem_table_get_nodep( FT_MemTable table, 00431 FT_Byte* address ) 00432 { 00433 FT_PtrDist hash; 00434 FT_MemNode *pnode, node; 00435 00436 00437 hash = FT_MEM_VAL( address ); 00438 pnode = table->buckets + ( hash % table->size ); 00439 00440 for (;;) 00441 { 00442 node = pnode[0]; 00443 if ( !node ) 00444 break; 00445 00446 if ( node->address == address ) 00447 break; 00448 00449 pnode = &node->link; 00450 } 00451 return pnode; 00452 } 00453 00454 00455 static FT_MemSource 00456 ft_mem_table_get_source( FT_MemTable table ) 00457 { 00458 FT_UInt32 hash; 00459 FT_MemSource node, *pnode; 00460 00461 00462 /* cast to FT_PtrDist first since void* can be larger */ 00463 /* than FT_UInt32 and GCC 4.1.1 emits a warning */ 00464 hash = (FT_UInt32)(FT_PtrDist)(void*)_ft_debug_file + 00465 (FT_UInt32)( 5 * _ft_debug_lineno ); 00466 pnode = &table->sources[hash % FT_MEM_SOURCE_BUCKETS]; 00467 00468 for ( ;; ) 00469 { 00470 node = *pnode; 00471 if ( node == NULL ) 00472 break; 00473 00474 if ( node->file_name == _ft_debug_file && 00475 node->line_no == _ft_debug_lineno ) 00476 goto Exit; 00477 00478 pnode = &node->link; 00479 } 00480 00481 node = (FT_MemSource)ft_mem_table_alloc( table, sizeof ( *node ) ); 00482 if ( node == NULL ) 00483 ft_mem_debug_panic( 00484 "not enough memory to perform memory debugging\n" ); 00485 00486 node->file_name = _ft_debug_file; 00487 node->line_no = _ft_debug_lineno; 00488 00489 node->cur_blocks = 0; 00490 node->max_blocks = 0; 00491 node->all_blocks = 0; 00492 00493 node->cur_size = 0; 00494 node->max_size = 0; 00495 node->all_size = 0; 00496 00497 node->cur_max = 0; 00498 00499 node->link = NULL; 00500 node->hash = hash; 00501 *pnode = node; 00502 00503 Exit: 00504 return node; 00505 } 00506 00507 00508 static void 00509 ft_mem_table_set( FT_MemTable table, 00510 FT_Byte* address, 00511 FT_ULong size, 00512 FT_Long delta ) 00513 { 00514 FT_MemNode *pnode, node; 00515 00516 00517 if ( table ) 00518 { 00519 FT_MemSource source; 00520 00521 00522 pnode = ft_mem_table_get_nodep( table, address ); 00523 node = *pnode; 00524 if ( node ) 00525 { 00526 if ( node->size < 0 ) 00527 { 00528 /* This block was already freed. Our memory is now completely */ 00529 /* corrupted! */ 00530 /* This can only happen in keep-alive mode. */ 00531 ft_mem_debug_panic( 00532 "memory heap corrupted (allocating freed block)" ); 00533 } 00534 else 00535 { 00536 /* This block was already allocated. This means that our memory */ 00537 /* is also corrupted! */ 00538 ft_mem_debug_panic( 00539 "memory heap corrupted (re-allocating allocated block at" 00540 " %p, of size %ld)\n" 00541 "org=%s:%d new=%s:%d\n", 00542 node->address, node->size, 00543 FT_FILENAME( node->source->file_name ), node->source->line_no, 00544 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno ); 00545 } 00546 } 00547 00548 /* we need to create a new node in this table */ 00549 node = (FT_MemNode)ft_mem_table_alloc( table, sizeof ( *node ) ); 00550 if ( node == NULL ) 00551 ft_mem_debug_panic( "not enough memory to run memory tests" ); 00552 00553 node->address = address; 00554 node->size = size; 00555 node->source = source = ft_mem_table_get_source( table ); 00556 00557 if ( delta == 0 ) 00558 { 00559 /* this is an allocation */ 00560 source->all_blocks++; 00561 source->cur_blocks++; 00562 if ( source->cur_blocks > source->max_blocks ) 00563 source->max_blocks = source->cur_blocks; 00564 } 00565 00566 if ( size > (FT_ULong)source->cur_max ) 00567 source->cur_max = size; 00568 00569 if ( delta != 0 ) 00570 { 00571 /* we are growing or shrinking a reallocated block */ 00572 source->cur_size += delta; 00573 table->alloc_current += delta; 00574 } 00575 else 00576 { 00577 /* we are allocating a new block */ 00578 source->cur_size += size; 00579 table->alloc_current += size; 00580 } 00581 00582 source->all_size += size; 00583 00584 if ( source->cur_size > source->max_size ) 00585 source->max_size = source->cur_size; 00586 00587 node->free_file_name = NULL; 00588 node->free_line_no = 0; 00589 00590 node->link = pnode[0]; 00591 00592 pnode[0] = node; 00593 table->nodes++; 00594 00595 table->alloc_total += size; 00596 00597 if ( table->alloc_current > table->alloc_max ) 00598 table->alloc_max = table->alloc_current; 00599 00600 if ( table->nodes * 3 < table->size || 00601 table->size * 3 < table->nodes ) 00602 ft_mem_table_resize( table ); 00603 } 00604 } 00605 00606 00607 static void 00608 ft_mem_table_remove( FT_MemTable table, 00609 FT_Byte* address, 00610 FT_Long delta ) 00611 { 00612 if ( table ) 00613 { 00614 FT_MemNode *pnode, node; 00615 00616 00617 pnode = ft_mem_table_get_nodep( table, address ); 00618 node = *pnode; 00619 if ( node ) 00620 { 00621 FT_MemSource source; 00622 00623 00624 if ( node->size < 0 ) 00625 ft_mem_debug_panic( 00626 "freeing memory block at %p more than once at (%s:%ld)\n" 00627 "block allocated at (%s:%ld) and released at (%s:%ld)", 00628 address, 00629 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno, 00630 FT_FILENAME( node->source->file_name ), node->source->line_no, 00631 FT_FILENAME( node->free_file_name ), node->free_line_no ); 00632 00633 /* scramble the node's content for additional safety */ 00634 FT_MEM_SET( address, 0xF3, node->size ); 00635 00636 if ( delta == 0 ) 00637 { 00638 source = node->source; 00639 00640 source->cur_blocks--; 00641 source->cur_size -= node->size; 00642 00643 table->alloc_current -= node->size; 00644 } 00645 00646 if ( table->keep_alive ) 00647 { 00648 /* we simply invert the node's size to indicate that the node */ 00649 /* was freed. */ 00650 node->size = -node->size; 00651 node->free_file_name = _ft_debug_file; 00652 node->free_line_no = _ft_debug_lineno; 00653 } 00654 else 00655 { 00656 table->nodes--; 00657 00658 *pnode = node->link; 00659 00660 node->size = 0; 00661 node->source = NULL; 00662 00663 ft_mem_table_free( table, node ); 00664 00665 if ( table->nodes * 3 < table->size || 00666 table->size * 3 < table->nodes ) 00667 ft_mem_table_resize( table ); 00668 } 00669 } 00670 else 00671 ft_mem_debug_panic( 00672 "trying to free unknown block at %p in (%s:%ld)\n", 00673 address, 00674 FT_FILENAME( _ft_debug_file ), _ft_debug_lineno ); 00675 } 00676 } 00677 00678 00679 extern FT_Pointer 00680 ft_mem_debug_alloc( FT_Memory memory, 00681 FT_Long size ) 00682 { 00683 FT_MemTable table = (FT_MemTable)memory->user; 00684 FT_Byte* block; 00685 00686 00687 if ( size <= 0 ) 00688 ft_mem_debug_panic( "negative block size allocation (%ld)", size ); 00689 00690 /* return NULL if the maximum number of allocations was reached */ 00691 if ( table->bound_count && 00692 table->alloc_count >= table->alloc_count_max ) 00693 return NULL; 00694 00695 /* return NULL if this allocation would overflow the maximum heap size */ 00696 if ( table->bound_total && 00697 table->alloc_total_max - table->alloc_current > (FT_ULong)size ) 00698 return NULL; 00699 00700 block = (FT_Byte *)ft_mem_table_alloc( table, size ); 00701 if ( block ) 00702 { 00703 ft_mem_table_set( table, block, (FT_ULong)size, 0 ); 00704 00705 table->alloc_count++; 00706 } 00707 00708 _ft_debug_file = "<unknown>"; 00709 _ft_debug_lineno = 0; 00710 00711 return (FT_Pointer)block; 00712 } 00713 00714 00715 extern void 00716 ft_mem_debug_free( FT_Memory memory, 00717 FT_Pointer block ) 00718 { 00719 FT_MemTable table = (FT_MemTable)memory->user; 00720 00721 00722 if ( block == NULL ) 00723 ft_mem_debug_panic( "trying to free NULL in (%s:%ld)", 00724 FT_FILENAME( _ft_debug_file ), 00725 _ft_debug_lineno ); 00726 00727 ft_mem_table_remove( table, (FT_Byte*)block, 0 ); 00728 00729 if ( !table->keep_alive ) 00730 ft_mem_table_free( table, block ); 00731 00732 table->alloc_count--; 00733 00734 _ft_debug_file = "<unknown>"; 00735 _ft_debug_lineno = 0; 00736 } 00737 00738 00739 extern FT_Pointer 00740 ft_mem_debug_realloc( FT_Memory memory, 00741 FT_Long cur_size, 00742 FT_Long new_size, 00743 FT_Pointer block ) 00744 { 00745 FT_MemTable table = (FT_MemTable)memory->user; 00746 FT_MemNode node, *pnode; 00747 FT_Pointer new_block; 00748 FT_Long delta; 00749 00750 const char* file_name = FT_FILENAME( _ft_debug_file ); 00751 FT_Long line_no = _ft_debug_lineno; 00752 00753 00754 /* unlikely, but possible */ 00755 if ( new_size == cur_size ) 00756 return block; 00757 00758 /* the following is valid according to ANSI C */ 00759 #if 0 00760 if ( block == NULL || cur_size == 0 ) 00761 ft_mem_debug_panic( "trying to reallocate NULL in (%s:%ld)", 00762 file_name, line_no ); 00763 #endif 00764 00765 /* while the following is allowed in ANSI C also, we abort since */ 00766 /* such case should be handled by FreeType. */ 00767 if ( new_size <= 0 ) 00768 ft_mem_debug_panic( 00769 "trying to reallocate %p to size 0 (current is %ld) in (%s:%ld)", 00770 block, cur_size, file_name, line_no ); 00771 00772 /* check `cur_size' value */ 00773 pnode = ft_mem_table_get_nodep( table, (FT_Byte*)block ); 00774 node = *pnode; 00775 if ( !node ) 00776 ft_mem_debug_panic( 00777 "trying to reallocate unknown block at %p in (%s:%ld)", 00778 block, file_name, line_no ); 00779 00780 if ( node->size <= 0 ) 00781 ft_mem_debug_panic( 00782 "trying to reallocate freed block at %p in (%s:%ld)", 00783 block, file_name, line_no ); 00784 00785 if ( node->size != cur_size ) 00786 ft_mem_debug_panic( "invalid ft_realloc request for %p. cur_size is " 00787 "%ld instead of %ld in (%s:%ld)", 00788 block, cur_size, node->size, file_name, line_no ); 00789 00790 /* return NULL if the maximum number of allocations was reached */ 00791 if ( table->bound_count && 00792 table->alloc_count >= table->alloc_count_max ) 00793 return NULL; 00794 00795 delta = (FT_Long)( new_size - cur_size ); 00796 00797 /* return NULL if this allocation would overflow the maximum heap size */ 00798 if ( delta > 0 && 00799 table->bound_total && 00800 table->alloc_current + (FT_ULong)delta > table->alloc_total_max ) 00801 return NULL; 00802 00803 new_block = (FT_Byte *)ft_mem_table_alloc( table, new_size ); 00804 if ( new_block == NULL ) 00805 return NULL; 00806 00807 ft_mem_table_set( table, (FT_Byte*)new_block, new_size, delta ); 00808 00809 ft_memcpy( new_block, block, cur_size < new_size ? cur_size : new_size ); 00810 00811 ft_mem_table_remove( table, (FT_Byte*)block, delta ); 00812 00813 _ft_debug_file = "<unknown>"; 00814 _ft_debug_lineno = 0; 00815 00816 if ( !table->keep_alive ) 00817 ft_mem_table_free( table, block ); 00818 00819 return new_block; 00820 } 00821 00822 00823 extern FT_Int 00824 ft_mem_debug_init( FT_Memory memory ) 00825 { 00826 FT_MemTable table; 00827 FT_Int result = 0; 00828 00829 00830 if ( getenv( "FT2_DEBUG_MEMORY" ) ) 00831 { 00832 table = ft_mem_table_new( memory ); 00833 if ( table ) 00834 { 00835 const char* p; 00836 00837 00838 memory->user = table; 00839 memory->alloc = ft_mem_debug_alloc; 00840 memory->realloc = ft_mem_debug_realloc; 00841 memory->free = ft_mem_debug_free; 00842 00843 p = getenv( "FT2_ALLOC_TOTAL_MAX" ); 00844 if ( p != NULL ) 00845 { 00846 FT_Long total_max = ft_atol( p ); 00847 00848 00849 if ( total_max > 0 ) 00850 { 00851 table->bound_total = 1; 00852 table->alloc_total_max = (FT_ULong)total_max; 00853 } 00854 } 00855 00856 p = getenv( "FT2_ALLOC_COUNT_MAX" ); 00857 if ( p != NULL ) 00858 { 00859 FT_Long total_count = ft_atol( p ); 00860 00861 00862 if ( total_count > 0 ) 00863 { 00864 table->bound_count = 1; 00865 table->alloc_count_max = (FT_ULong)total_count; 00866 } 00867 } 00868 00869 p = getenv( "FT2_KEEP_ALIVE" ); 00870 if ( p != NULL ) 00871 { 00872 FT_Long keep_alive = ft_atol( p ); 00873 00874 00875 if ( keep_alive > 0 ) 00876 table->keep_alive = 1; 00877 } 00878 00879 result = 1; 00880 } 00881 } 00882 return result; 00883 } 00884 00885 00886 extern void 00887 ft_mem_debug_done( FT_Memory memory ) 00888 { 00889 FT_MemTable table = (FT_MemTable)memory->user; 00890 00891 00892 if ( table ) 00893 { 00894 memory->free = table->free; 00895 memory->realloc = table->realloc; 00896 memory->alloc = table->alloc; 00897 00898 ft_mem_table_destroy( table ); 00899 memory->user = NULL; 00900 } 00901 } 00902 00903 00904 00905 static int 00906 ft_mem_source_compare( const void* p1, 00907 const void* p2 ) 00908 { 00909 FT_MemSource s1 = *(FT_MemSource*)p1; 00910 FT_MemSource s2 = *(FT_MemSource*)p2; 00911 00912 00913 if ( s2->max_size > s1->max_size ) 00914 return 1; 00915 else if ( s2->max_size < s1->max_size ) 00916 return -1; 00917 else 00918 return 0; 00919 } 00920 00921 00922 extern void 00923 FT_DumpMemory( FT_Memory memory ) 00924 { 00925 FT_MemTable table = (FT_MemTable)memory->user; 00926 00927 00928 if ( table ) 00929 { 00930 FT_MemSource* bucket = table->sources; 00931 FT_MemSource* limit = bucket + FT_MEM_SOURCE_BUCKETS; 00932 FT_MemSource* sources; 00933 FT_UInt nn, count; 00934 const char* fmt; 00935 00936 00937 count = 0; 00938 for ( ; bucket < limit; bucket++ ) 00939 { 00940 FT_MemSource source = *bucket; 00941 00942 00943 for ( ; source; source = source->link ) 00944 count++; 00945 } 00946 00947 sources = (FT_MemSource*)ft_mem_table_alloc( 00948 table, sizeof ( *sources ) * count ); 00949 00950 count = 0; 00951 for ( bucket = table->sources; bucket < limit; bucket++ ) 00952 { 00953 FT_MemSource source = *bucket; 00954 00955 00956 for ( ; source; source = source->link ) 00957 sources[count++] = source; 00958 } 00959 00960 ft_qsort( sources, count, sizeof ( *sources ), ft_mem_source_compare ); 00961 00962 printf( "FreeType Memory Dump: " 00963 "current=%ld max=%ld total=%ld count=%ld\n", 00964 table->alloc_current, table->alloc_max, 00965 table->alloc_total, table->alloc_count ); 00966 printf( " block block sizes sizes sizes source\n" ); 00967 printf( " count high sum highsum max location\n" ); 00968 printf( "-------------------------------------------------\n" ); 00969 00970 fmt = "%6ld %6ld %8ld %8ld %8ld %s:%d\n"; 00971 00972 for ( nn = 0; nn < count; nn++ ) 00973 { 00974 FT_MemSource source = sources[nn]; 00975 00976 00977 printf( fmt, 00978 source->cur_blocks, source->max_blocks, 00979 source->cur_size, source->max_size, source->cur_max, 00980 FT_FILENAME( source->file_name ), 00981 source->line_no ); 00982 } 00983 printf( "------------------------------------------------\n" ); 00984 00985 ft_mem_table_free( table, sources ); 00986 } 00987 } 00988 00989 #else /* !FT_DEBUG_MEMORY */ 00990 00991 /* ANSI C doesn't like empty source files */ 00992 typedef int _debug_mem_dummy; 00993 00994 #endif /* !FT_DEBUG_MEMORY */ 00995 00996 00997 /* END */ Generated on Tue May 22 2012 04:37:46 for ReactOS by
1.7.6.1
|