Open64 (mfef90, whirl2f, and IR tools)
TAG: version-openad; SVN changeset: 916
|
00001 /* 00002 00003 Copyright (C) 2000, 2001 Silicon Graphics, Inc. All Rights Reserved. 00004 00005 This program is free software; you can redistribute it and/or modify it 00006 under the terms of version 2 of the GNU General Public License as 00007 published by the Free Software Foundation. 00008 00009 This program is distributed in the hope that it would be useful, but 00010 WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 00012 00013 Further, this software is distributed without any warranty that it is 00014 free of the rightful claim of any third person regarding infringement 00015 or the like. Any license provided herein, whether implied or 00016 otherwise, applies only to this software file. Patent licenses, if 00017 any, provided herein do not apply to combinations of this program with 00018 other software, or any other product whatsoever. 00019 00020 You should have received a copy of the GNU General Public License along 00021 with this program; if not, write the Free Software Foundation, Inc., 59 00022 Temple Place - Suite 330, Boston MA 02111-1307, USA. 00023 00024 Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pky, 00025 Mountain View, CA 94043, or: 00026 00027 http://www.sgi.com 00028 00029 For further information regarding this notice, see: 00030 00031 http://oss.sgi.com/projects/GenInfo/NoticeExplan 00032 00033 */ 00034 00035 00036 00037 #include <sys/types.h> 00038 #include <stdlib.h> 00039 #include <string.h> /* for memset() and memmove() */ 00040 00041 #include "defs.h" 00042 #include "mempool.h" 00043 #include "tracing.h" 00044 #include "erglob.h" 00045 00046 /* The value of the following macro must be distinct from TRUE and FALSE 00047 * as defined in defs.h. The macro is used only in the case that 00048 * PURIFY_MEMPOOLS is switched on (ON, ON-TRACE, or ON-TRACE-X). 00049 */ 00050 #define MEM_POOL_INIT_IN_PROGRESS (-1) 00051 00052 /* ----------------------------------------------------------------- 00053 * Compile time parameters 00054 * ----------------------------------------------------------------- */ 00055 /* BLOCK_SIZE - This is the size of blocks for small object 00056 */ 00057 #define BLOCK_SIZE 0x2000 00058 00059 /* MIN_LARGE_BLOCK_SIZE - objects larger than this size goes to the large 00060 block list 00061 */ 00062 #define MIN_LARGE_BLOCK_SIZE 0x800 00063 00064 /* if ZAP_ON_FREE is defined, we fill freed memory with garbage 00065 */ 00066 #ifdef Is_True_On 00067 #define ZAP_ON_FREE (1) 00068 #endif 00069 00070 00071 /* ----------------------------------------------------------------- 00072 * Exported variables 00073 * ----------------------------------------------------------------- 00074 */ 00075 00076 /* These pools zero newly-allocated memory. 00077 */ 00078 MEM_POOL MEM_local_pool; 00079 MEM_POOL MEM_src_pool; 00080 MEM_POOL MEM_pu_pool; 00081 MEM_POOL MEM_phase_pool; 00082 00083 MEM_POOL *MEM_local_pool_ptr = &MEM_local_pool; 00084 MEM_POOL *MEM_src_pool_ptr = &MEM_src_pool; 00085 MEM_POOL *MEM_pu_pool_ptr = &MEM_pu_pool; 00086 MEM_POOL *MEM_phase_pool_ptr = &MEM_phase_pool; 00087 00088 /* These pools don't zero newly-allocated memory, and hence allocation 00089 * is faster than the zeroed pools above. These should be used whenever 00090 * appropriate. 00091 */ 00092 MEM_POOL MEM_local_nz_pool; 00093 MEM_POOL MEM_src_nz_pool; 00094 MEM_POOL MEM_pu_nz_pool; 00095 MEM_POOL MEM_phase_nz_pool; 00096 00097 MEM_POOL *MEM_local_nz_pool_ptr = &MEM_local_nz_pool; 00098 MEM_POOL *MEM_src_nz_pool_ptr = &MEM_src_nz_pool; 00099 MEM_POOL *MEM_pu_nz_pool_ptr = &MEM_pu_nz_pool; 00100 MEM_POOL *MEM_phase_nz_pool_ptr = &MEM_phase_nz_pool; 00101 00102 00103 /* ----------------------------------------------------------------- 00104 * Data structures 00105 * ----------------------------------------------------------------- 00106 */ 00107 00108 /* MEM_BLOCK - this is really the header for a memory block allocated 00109 * by this package. Space after the final field is used for user 00110 * allocations. 00111 */ 00112 struct mem_block { 00113 size_t avail; /* Number of bytes still available in the 00114 * block 00115 */ 00116 MEM_PTR ptr; /* Points at the next byte to be allocated. 00117 */ 00118 MEM_BLOCK *rest; /* Points at the rest of the rest of the 00119 * blocks in an internally linked list. 00120 */ 00121 }; 00122 00123 #define MEM_BLOCK_avail(x) ((x)->avail) 00124 #define MEM_BLOCK_ptr(x) ((x)->ptr) 00125 #define MEM_BLOCK_rest(x) ((x)->rest) 00126 00127 #define MEM_BLOCK_first_ptr(x) \ 00128 (MEM_PTR) (((char *) (x)) + PAD_TO_ALIGN(sizeof(MEM_BLOCK))) 00129 00130 /* MEM_LARGE_BLOCK - this is really the header for a large memory block 00131 (blocks larger than BLOCK_SIZE) allocated by this package. Space 00132 after the final field (after rounding up for alignment) is for user's 00133 storage 00134 */ 00135 typedef struct mem_large_block MEM_LARGE_BLOCK; 00136 struct mem_large_block { 00137 MEM_LARGE_BLOCK *next; /* doubly-linked list */ 00138 MEM_LARGE_BLOCK *prev; 00139 MEM_POOL_BLOCKS *base; /* points back to the head of list */ 00140 MEM_PTR ptr; /* points to the user memory block */ 00141 }; 00142 00143 #define MEM_LARGE_BLOCK_next(x) ((x)->next) 00144 #define MEM_LARGE_BLOCK_prev(x) ((x)->prev) 00145 #define MEM_LARGE_BLOCK_base(x) ((x)->base) 00146 #define MEM_LARGE_BLOCK_ptr(x) ((x)->ptr) 00147 #define MEM_LARGE_BLOCK_OVERHEAD (PAD_TO_ALIGN(sizeof(MEM_LARGE_BLOCK))) 00148 00149 /* When we free a large block we must also erase fields that identify it 00150 * as a valid large block. Subsequent to being freed as a large block, 00151 * the memory may be malloc'ed as a "small" block for some other mempool. 00152 * If this "small" block is not initialized (and neither is the 00153 * MEM_LARGE_BLOCK_OVERHEADT preceeding it), then when we call MEMPOOL_FREE 00154 * on this "small" block it may be interpreted as a large block and 00155 * its successor blocks (freed and possibly reallocated) may be added 00156 * to the large block list of this other mempool. This can cause all kinds 00157 * of havoc and is *very* hard to track down. The MEM_LARGE_BLOCK_zap() 00158 * is intended to avoid this kind of scenario (a real bug we encountered)! 00159 */ 00160 static void 00161 MEM_LARGE_BLOCK_zap(MEM_LARGE_BLOCK *block) 00162 { 00163 MEM_LARGE_BLOCK_base(block) = NULL; 00164 MEM_LARGE_BLOCK_ptr(block) = NULL; 00165 } 00166 00167 static void 00168 MEM_LARGE_BLOCK_free(MEM_LARGE_BLOCK *block) 00169 { 00170 MEM_LARGE_BLOCK_zap(block); 00171 free(block); 00172 } 00173 00174 static MEM_LARGE_BLOCK * 00175 MEM_LARGE_BLOCK_realloc(MEM_LARGE_BLOCK *old_block, INT64 new_size) 00176 { 00177 MEM_POOL_BLOCKS * const base = MEM_LARGE_BLOCK_base(old_block); 00178 MEM_PTR const ptr = MEM_LARGE_BLOCK_ptr(old_block); 00179 MEM_LARGE_BLOCK * new_block; 00180 00181 MEM_LARGE_BLOCK_zap(old_block); /* In case old_block != new_block */ 00182 new_block = (MEM_LARGE_BLOCK *)realloc(old_block, new_size); 00183 if (new_block != NULL) 00184 { 00185 MEM_LARGE_BLOCK_base(new_block) = base; 00186 MEM_LARGE_BLOCK_ptr(new_block) = ptr; 00187 } 00188 return new_block; 00189 } 00190 00191 00192 /* INT_LIST - Kind of a drag, a list of integers used to implement a 00193 * stack of current space allocated in the MEM_STATs. 00194 */ 00195 typedef struct int_list INT_LIST; 00196 00197 struct int_list { 00198 INT32 first; /* First element 00199 */ 00200 INT_LIST *rest; /* All the rest 00201 */ 00202 }; 00203 00204 #define INT_LIST_first(x) ((x)->first) 00205 #define INT_LIST_rest(x) ((x)->rest) 00206 00207 static INT_LIST *free_int_lists; /* Free list of INT_LISTs. 00208 */ 00209 00210 /* MEM_STAT - Per call-site information. Used to keep track of how 00211 * the clients of this package use it. 00212 */ 00213 00214 struct mem_stat { 00215 const char *file; /* File called from 00216 */ 00217 INT32 line; /* Line called from 00218 */ 00219 INT32 total; /* Total memory allocated from 00220 * this site. 00221 */ 00222 INT32 current; /* Memory currently allocated from 00223 * this site 00224 */ 00225 INT32 max_t; /* Maximum memory ever in use and 00226 * allocated from this site (maximum 00227 * value of current.) 00228 */ 00229 size_t max_s; /* Maximum memory ever allocated 00230 * from this site in a single call to 00231 * malloc 00232 */ 00233 INT32 last; /* Last amount of memory allocated 00234 * from this site 00235 */ 00236 INT32 last_grew; /* Count of times the amount of 00237 * memory grew for one call to the 00238 * next 00239 */ 00240 INT32 last_shrank; /* Count of times the amount of 00241 * memory shrank from once call to the 00242 * next 00243 */ 00244 INT32 count; /* How many calls from this callsite 00245 */ 00246 MEM_STAT *hash_list_rest; /* Used to keep the list of 00247 * elements in the hash bucket 00248 */ 00249 MEM_STAT *pool_list_rest; /* Used to keep the list of 00250 * elements associates with each pool 00251 */ 00252 INT_LIST *saved_current; /* Stack of previous values of 00253 * current, pushed when the pool is 00254 * pushed. 00255 */ 00256 MEM_POOL *pool; /* Pool the allocation is from. 00257 */ 00258 }; 00259 00260 #define MEM_STAT_file(x) ((x)->file) 00261 #define MEM_STAT_line(x) ((x)->line) 00262 #define MEM_STAT_total(x) ((x)->total) 00263 #define MEM_STAT_current(x) ((x)->current) 00264 #define MEM_STAT_max_t(x) ((x)->max_t) 00265 #define MEM_STAT_max_s(x) ((x)->max_s) 00266 #define MEM_STAT_last(x) ((x)->last) 00267 #define MEM_STAT_last_grew(x) ((x)->last_grew) 00268 #define MEM_STAT_last_shrank(x) ((x)->last_shrank) 00269 #define MEM_STAT_count(x) ((x)->count) 00270 #define MEM_STAT_hash_list_rest(x) ((x)->hash_list_rest) 00271 #define MEM_STAT_pool_list_rest(x) ((x)->pool_list_rest) 00272 #define MEM_STAT_saved_current(x) ((x)->saved_current) 00273 #define MEM_STAT_pool(x) ((x)->pool) 00274 00275 00276 /* MEM_POOL_BLOCKS - This represents a particular level of allocation 00277 * for the pool. As the pool is Push'ed and Pop'ed (Mark'ed and 00278 * Free'ed in old parlance) we'll push and pop a list of these, 00279 * free'ing any used blocks. 00280 */ 00281 struct mem_pool_blocks { 00282 MEM_BLOCK *block; /* list of memory blocks */ 00283 00284 MEM_LARGE_BLOCK *large_block; /* list of large memory blocks */ 00285 00286 MEM_BLOCK *base_block; /* points to the block when this is 00287 pushed */ 00288 00289 MEM_PTR *base_ptr; /* MEM_BLOCK_ptr when this is pushed */ 00290 00291 size_t base_avail; /* MEM_BLOCK_avail when this is 00292 pushed */ 00293 00294 MEM_POOL_BLOCKS *rest; /* When active, used to keep 00295 * stack of allocation levels. 00296 * When inactive, used to keep 00297 * free list of these object. 00298 */ 00299 }; 00300 00301 #define MEM_POOL_BLOCKS_block(x) ((x)->block) 00302 #define MEM_POOL_BLOCKS_large_block(x) ((x)->large_block) 00303 #define MEM_POOL_BLOCKS_base_block(x) ((x)->base_block) 00304 #define MEM_POOL_BLOCKS_base_ptr(x) ((x)->base_ptr) 00305 #define MEM_POOL_BLOCKS_base_avail(x) ((x)->base_avail) 00306 #define MEM_POOL_BLOCKS_rest(x) ((x)->rest) 00307 00308 /*********************************************************************** 00309 * The purify option: 00310 * ------------------ 00311 * Based on a tt flag you can choose that your mem-pools actually 00312 * do a malloc/free. Push, Pop, Alloc, Free, Realloc, Freeze, Unfreeze, 00313 * continue to work as before for the user, but their implementation 00314 * does real malloc/free for each piece of storage. So purify should be 00315 * a lot more useful. 00316 * 00317 * Unless this flag is given, memory pools should behave exactly as 00318 * before, except that each memory pool will have a pointer (8 bytes) 00319 * of wasted storage. 00320 * 00321 * Implementation: 00322 * --------------- 00323 * 1. We need to keep track of all the memory allocated, so that when the 00324 * memory pool is popped we can actually do the free. 00325 * 2. We need to do (1) for each push-level for a memory pool, so that we 00326 * only pop the current push level. 00327 * 00328 * We therefore have 00329 * (a) a stack of pointers of the memory allocated, and 00330 * (b) a stack of stacks(a), one for each push-level. 00331 * 00332 * The implementation of these stack of stacks is as follows: 00333 * Each memory pool has an extra pointer that points to a 00334 * struct mem_pure_stack (see below). This struct corresponds to the 00335 * most recent push-level. It contains a pointer to the struct for the 00336 * previous push-level, and it contains a pointer to the last memory 00337 * allocated in this push-level. 00338 * 00339 * The memory allocated for a particular push-level is strung together 00340 * by allocating an extra 8 bytes of storage, and using the double-word 00341 * before the pointer to store the pointer to the next piece of memory 00342 * allocated. 00343 * 00344 ***********************************************************************/ 00345 00346 /* MEM_PURE_STACKS - This struct stores 00347 * (a) a pointer to the latest allocation in this push-level 00348 * (b) a pointer to the corresponding struct from the previous push level. 00349 */ 00350 struct mem_pure_stack { 00351 MEM_PTR last_alloc; /* latest alloc'd storage */ 00352 MEM_PURE_STACK *prev_stack; /* pointer to push-stack of 00353 * previous push level. 00354 */ 00355 }; 00356 00357 #define MEM_PURE_STACK_last_alloc(x) ((x)->last_alloc) 00358 #define MEM_PURE_STACK_prev_stack(x) ((x)->prev_stack) 00359 #define MEM_POOL_last_alloc(x) \ 00360 MEM_PURE_STACK_last_alloc(MEM_POOL_pure_stack(x)) 00361 #define MEM_POOL_prev_stack(x) \ 00362 MEM_PURE_STACK_prev_stack(MEM_POOL_pure_stack(x)) 00363 BOOL purify_pools = FALSE; 00364 static BOOL purify_pools_trace = FALSE; 00365 static BOOL purify_pools_trace_x = FALSE; 00366 00367 #define MAGIC_NUM 0xabcd 00368 00369 /* Accessing POOL fields. This is defined here, as these fields are 00370 * all private. 00371 */ 00372 #define MEM_POOL_name(x) ((x)->name) 00373 #define MEM_POOL_blocks(x) ((x)->blocks) 00374 #define MEM_POOL_bz(x) ((x)->bz) 00375 #define MEM_POOL_rest(x) ((x)->rest) 00376 #define MEM_POOL_pure_stack(x) ((x)->pure_stack) 00377 #define MEM_POOL_frozen(x) ((x)->frozen) 00378 #define MEM_POOL_magic_num(x) ((x)->magic_num) 00379 #define MEM_POOL_alloc_site_list(x) ((x)->alloc_site_list) 00380 00381 #define MEM_POOL_block(x) \ 00382 MEM_POOL_BLOCKS_block(MEM_POOL_blocks(x)) 00383 #define MEM_POOL_large_block(x) \ 00384 MEM_POOL_BLOCKS_large_block(MEM_POOL_blocks(x)) 00385 00386 /* ----------------------------------------------------------------- 00387 * Local variables 00388 * ----------------------------------------------------------------- 00389 */ 00390 static MEM_POOL_BLOCKS *free_mem_pool_blocks_list; 00391 /* Free list of MEM_PPOOL_BLOCKS 00392 */ 00393 00394 static MEM_POOL_BLOCKS overhead_blocks; 00395 /* Used to initialize the overhead 00396 * pool below. 00397 */ 00398 static MEM_POOL mem_overhead_pool = /* Used to allocate stuff for this 00399 * package 00400 */ 00401 { 00402 "memory overhead", 00403 &overhead_blocks, 00404 NULL, 00405 NULL, 00406 TRUE, 00407 FALSE, 00408 MAGIC_NUM, 00409 NULL 00410 }; 00411 00412 static MEM_POOL *The_Default_Mem_Pool; 00413 00414 /* PAD_TO_ALIGN - Pad up a given size to double word alignment. 00415 */ 00416 #define PAD_TO_ALIGN(size) (((size) + 7) & (~0U << 3)) 00417 00418 00419 /* Implementation of memory statististics tracking mechanism 00420 */ 00421 static BOOL mem_tracing_enabled = FALSE; 00422 #ifdef Is_True_On 00423 static MEM_POOL *initialized_pools =/* List of pools, used for memory 00424 * statistics reporting. 00425 */ 00426 &mem_overhead_pool; 00427 #endif 00428 00429 #define N_BUCKETS 503 00430 00431 static MEM_STAT *call_site_hash_tab[N_BUCKETS]; 00432 00433 00434 /* ==================================================================== 00435 * 00436 * Hash 00437 * 00438 * Compute a hash key for a alloc callsite. 00439 * 00440 * 'line' - line number in file of callsite 00441 * 'file' - filename containing callsite 00442 * 00443 * ==================================================================== 00444 */ 00445 00446 static UINT32 00447 Hash( 00448 INT32 line, 00449 const char *file 00450 ) 00451 { 00452 const char *p; 00453 UINT32 result = line; 00454 00455 /* Somebody once told me this was a good idea. It probably spreads 00456 * the bits around OK. 00457 */ 00458 for ( p = file; *p; ++p ) 00459 result = ((result << 1) ^ (result >> 1) ^ *p) + *p; 00460 00461 return result % N_BUCKETS; 00462 } 00463 00464 /* ==================================================================== 00465 * 00466 * Hash_Get 00467 * 00468 * Find the MEM_STAT for a callsite if there is one. Return NULL, 00469 * otherwise. 00470 * 00471 * 'hn' - hash number (as returned by Hash). 00472 * 'line' - line number of callsite 00473 * 'file' - filename with callsite 00474 * 00475 * ==================================================================== 00476 */ 00477 00478 static MEM_STAT* 00479 Hash_Get( 00480 UINT32 hn, 00481 MEM_POOL *pool, 00482 INT32 line, 00483 const char *file 00484 ) 00485 { 00486 MEM_STAT *as; 00487 00488 for ( as = call_site_hash_tab[hn]; 00489 as != NULL; 00490 as = MEM_STAT_hash_list_rest(as) 00491 ) { 00492 if ( MEM_STAT_line(as) == line 00493 && strcmp(MEM_STAT_file(as),file) == 0 00494 && MEM_STAT_pool(as) == pool 00495 ) { 00496 return as; 00497 } 00498 } 00499 00500 return NULL; 00501 } 00502 00503 /* ==================================================================== 00504 * 00505 * Site_Account_Alloc 00506 * 00507 * Record a memory (re)allocation event. 00508 * 00509 * 'pool' - In which MEM_POOL 00510 * 'old_size' - If a realloc, memory that was allocated, else 0. 00511 * 'new_size' - Amount of memory allocated. 00512 * 'line' - Line in file of the callsite. 00513 * 'file' - Name of the file containing the callsite. 00514 * 00515 * ==================================================================== 00516 */ 00517 00518 static void 00519 Site_Account_Alloc( 00520 MEM_POOL *pool, 00521 size_t old_size, 00522 size_t new_size 00523 MEM_STAT_ARGS(line,file) 00524 ) 00525 { 00526 INT32 size = new_size - old_size; 00527 UINT32 hn = Hash(line,file); 00528 MEM_STAT *ms = Hash_Get(hn,pool,line,file); 00529 00530 if ( ms == NULL ) { 00531 ms = (MEM_STAT *) calloc(1,sizeof(MEM_STAT)); 00532 00533 MEM_STAT_pool(ms) = pool; 00534 MEM_STAT_line(ms) = line; 00535 MEM_STAT_file(ms) = file; 00536 MEM_STAT_hash_list_rest(ms) = call_site_hash_tab[hn]; 00537 call_site_hash_tab[hn] = ms; 00538 MEM_STAT_pool_list_rest(ms) = MEM_POOL_alloc_site_list(pool); 00539 MEM_POOL_alloc_site_list(pool) = ms; 00540 } 00541 00542 MEM_STAT_current(ms) += size; 00543 MEM_STAT_total(ms) += size; 00544 if ( size > MEM_STAT_last(ms) ) 00545 ++MEM_STAT_last_grew(ms); 00546 else if ( size < MEM_STAT_last(ms) ) 00547 ++MEM_STAT_last_shrank(ms); 00548 MEM_STAT_max_t(ms) = Max(MEM_STAT_max_t(ms),MEM_STAT_current(ms)); 00549 MEM_STAT_max_s(ms) = Max(MEM_STAT_max_s(ms),size); 00550 MEM_STAT_last(ms) = size; 00551 ++MEM_STAT_count(ms); 00552 } 00553 00554 /* ==================================================================== 00555 * 00556 * Site_Account_Pop 00557 * 00558 * Record a memory pool poping event (which frees its memory.) 00559 * 00560 * 'pool' - is the pool being poped. 00561 * 'line' - is the line number of the callsite 00562 * 'file' - is the filename with the callsite 00563 * 00564 * ==================================================================== 00565 */ 00566 00567 static void 00568 Site_Account_Pop( 00569 MEM_POOL *pool 00570 MEM_STAT_ARGS(line,file) 00571 ) 00572 { 00573 MEM_STAT *ms; 00574 00575 for ( ms = MEM_POOL_alloc_site_list(pool); 00576 ms != NULL; 00577 ms = MEM_STAT_pool_list_rest(ms) 00578 ) { 00579 INT_LIST *tmp = MEM_STAT_saved_current(ms); 00580 00581 if ( tmp == NULL ) { 00582 /* Wasn't on the list at the time of the push, hence current 00583 * will now be 0 00584 */ 00585 MEM_STAT_current(ms) = 0; 00586 } 00587 else { 00588 MEM_STAT_current(ms) = INT_LIST_first(tmp); 00589 MEM_STAT_saved_current(ms) = INT_LIST_rest(tmp); 00590 INT_LIST_rest(tmp) = free_int_lists; 00591 free_int_lists = tmp; 00592 } 00593 } 00594 } 00595 00596 /* ==================================================================== 00597 * 00598 * Site_Account_Push 00599 * 00600 * Record a memory pool pushing event. 00601 * 00602 * 'pool' - is the pool being pushed. 00603 * 00604 * ==================================================================== 00605 */ 00606 00607 static void 00608 Site_Account_Push( 00609 MEM_POOL *pool 00610 MEM_STAT_ARGS(line,file) 00611 ) 00612 { 00613 MEM_STAT *ms; 00614 00615 for ( ms = MEM_POOL_alloc_site_list(pool); 00616 ms != NULL; 00617 ms = MEM_STAT_pool_list_rest(ms) 00618 ) { 00619 INT_LIST *il; 00620 00621 if ( free_int_lists == NULL ) 00622 il = TYPE_MEM_POOL_ALLOC(INT_LIST,&mem_overhead_pool); 00623 else { 00624 il = free_int_lists; 00625 00626 free_int_lists = INT_LIST_rest(il); 00627 } 00628 00629 INT_LIST_rest(il) = MEM_STAT_saved_current(ms); 00630 MEM_STAT_saved_current(ms) = il; 00631 INT_LIST_first(il) = MEM_STAT_current(ms); 00632 } 00633 } 00634 00635 /* ==================================================================== 00636 * 00637 * Field_Size 00638 * 00639 * How wide a field to print an integer 'i'? 00640 * 00641 * ==================================================================== 00642 */ 00643 00644 static INT32 00645 Field_Size( 00646 INT32 i 00647 ) 00648 { 00649 char buff[100]; 00650 00651 /* Could certainly be more winning, but who cares. This will only 00652 * be compiled for collecting memory stats. 00653 */ 00654 sprintf(buff,"%d",i); 00655 return strlen(buff); 00656 } 00657 00658 /* ==================================================================== 00659 * 00660 * MEM_STAT_Sort 00661 * 00662 * Qsort comparison function for ordering MEM_STATs in descending 00663 * order of the maximum amount of space they ever had outstanding. 00664 * 00665 * 'as1p' - pointers to MEM_STAT *s 00666 * 'as2p' 00667 * 00668 * ==================================================================== 00669 */ 00670 00671 typedef INT (*QSORT_FUNC) (const void *, const void *); 00672 00673 static INT 00674 MEM_STAT_Sort( 00675 MEM_STAT **as1p, 00676 MEM_STAT **as2p 00677 ) 00678 { 00679 MEM_STAT *as1 = *as1p; 00680 MEM_STAT *as2 = *as2p; 00681 00682 return MEM_STAT_max_t(as2) - MEM_STAT_max_t(as1); 00683 } 00684 00685 /* ==================================================================== 00686 * 00687 * MEM_STAT_In_List 00688 * 00689 * Determine if the pool is already in the list. 00690 * 00691 * ==================================================================== 00692 */ 00693 00694 static BOOL 00695 MEM_STAT_In_List( 00696 MEM_POOL *list, 00697 MEM_POOL *pool 00698 ) 00699 { 00700 for ( ; 00701 list != NULL; 00702 list = MEM_POOL_rest(list) 00703 ) { 00704 if ( list == pool ) 00705 return ( TRUE ); 00706 } 00707 00708 return ( FALSE ); 00709 } 00710 00711 /* ==================================================================== 00712 * 00713 * MEM_POOL_Report 00714 * 00715 * Print statistics for the given MEM_POOL. 00716 * 00717 * 'pool' - The pool to report on. 00718 * 'used_total' - The total current amount of memory allocated. 00719 * 00720 * ==================================================================== 00721 */ 00722 00723 INT32 00724 MEM_POOL_Report( 00725 MEM_POOL *pool, 00726 INT32 used_total 00727 ) 00728 { 00729 MEM_STAT *as; 00730 MEM_STAT **as_vec; 00731 INT32 i; 00732 INT32 total_current = 0; 00733 INT32 total_allocated = 0; 00734 INT32 max_allocated = 0; 00735 INT32 current_fs = 3; 00736 INT32 total_fs = 3; 00737 INT32 max_t_fs = 4; 00738 INT32 max_s_fs = 4; 00739 INT32 count_fs = 5; 00740 INT32 last_grew_fs = 4; 00741 INT32 last_shrank_fs = 6; 00742 INT32 site_count = 0; 00743 00744 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 00745 ("Report from un-initialized MEM_POOL %s\n", MEM_POOL_name(pool))); 00746 00747 fprintf(TFile,"----- %s callsites\n",MEM_POOL_name(pool)); 00748 00749 /* Prepass to count records, figure out size of fields. 00750 */ 00751 for ( as = MEM_POOL_alloc_site_list(pool); 00752 as != NULL; 00753 as = MEM_STAT_pool_list_rest(as) 00754 ) { 00755 current_fs = Max(current_fs,Field_Size(MEM_STAT_current(as))); 00756 total_fs = Max(total_fs,Field_Size(MEM_STAT_total(as))); 00757 max_t_fs = Max(max_t_fs,Field_Size(MEM_STAT_max_t(as))); 00758 max_s_fs = Max(max_s_fs,Field_Size(MEM_STAT_max_s(as))); 00759 count_fs = Max(count_fs,Field_Size(MEM_STAT_count(as))); 00760 last_grew_fs = Max(last_grew_fs, 00761 Field_Size(MEM_STAT_last_grew(as))); 00762 last_shrank_fs = Max(last_shrank_fs, 00763 Field_Size(MEM_STAT_last_shrank(as))); 00764 00765 ++site_count; 00766 } 00767 00768 /* Now sort by maximum allocated memory: 00769 */ 00770 MEM_POOL_Push(&mem_overhead_pool); 00771 as_vec = TYPE_MEM_POOL_ALLOC_N(MEM_STAT *,&mem_overhead_pool, 00772 site_count); 00773 00774 for ( as = MEM_POOL_alloc_site_list(pool), i = 0; 00775 as != NULL; 00776 as = MEM_STAT_pool_list_rest(as), ++i 00777 ) { 00778 as_vec[i] = as; 00779 } 00780 00781 qsort((void*)as_vec,site_count, 00782 sizeof(MEM_STAT*), 00783 (QSORT_FUNC) MEM_STAT_Sort); 00784 00785 /* Print the column headers. 00786 */ 00787 fprintf(TFile,"%*s %*s %*s %*s %*s %*s %*s Site\n", 00788 max_t_fs, 00789 "maxt", 00790 current_fs, 00791 "cur", 00792 total_fs, 00793 "tot", 00794 max_s_fs, 00795 "maxs", 00796 count_fs, 00797 "count", 00798 last_grew_fs, 00799 "grew", 00800 last_shrank_fs, 00801 "shrank"); 00802 00803 /* And the records 00804 */ 00805 for ( i = 0; i < site_count; ++i ) { 00806 as = as_vec[i]; 00807 00808 fprintf(TFile,"%*d %*d %*d %*d %*d %*d %*d %s %d\n", 00809 max_t_fs, 00810 MEM_STAT_max_t(as), 00811 current_fs, 00812 MEM_STAT_current(as), 00813 total_fs, 00814 MEM_STAT_total(as), 00815 max_s_fs, 00816 MEM_STAT_max_s(as), 00817 count_fs, 00818 MEM_STAT_count(as), 00819 last_grew_fs, 00820 MEM_STAT_last_grew(as), 00821 last_shrank_fs, 00822 MEM_STAT_last_shrank(as), 00823 MEM_STAT_file(as), 00824 MEM_STAT_line(as)); 00825 total_current += MEM_STAT_current(as); 00826 total_allocated += MEM_STAT_total(as); 00827 max_allocated += MEM_STAT_max_t(as); 00828 } 00829 00830 MEM_POOL_Pop(&mem_overhead_pool); 00831 00832 fprintf(TFile,"++++ Allocated for %s pool: total=%d, max=%d, current=%d (%d%%used)\n", 00833 MEM_POOL_name(pool), 00834 total_allocated, 00835 max_allocated, 00836 total_current, 00837 (INT) (100.0 * ( ((double) total_current) 00838 / ((double) used_total)))); 00839 return total_allocated; 00840 } 00841 00842 /* ==================================================================== 00843 * 00844 * MEM_Trace 00845 * 00846 * Show detailed info about where the memory is being used. 00847 * 00848 * ==================================================================== 00849 */ 00850 00851 void 00852 MEM_Trace(void) 00853 { 00854 #ifdef Is_True_On 00855 /* need linux malloc or -lmalloc on irix to use mallinfo */ 00856 #if defined(linux) || defined(MEM_STATS) 00857 MEM_POOL *pool; 00858 struct mallinfo mi = mallinfo(); 00859 INT32 used_total = mi.usmblks + mi.uordblks; 00860 INT32 total_allocated = 0; 00861 00862 fprintf(TFile,"arena %10d\n",mi.arena); 00863 fprintf(TFile,"ordblks %10d\n",mi.ordblks); 00864 fprintf(TFile,"smblks %10d\n",mi.smblks); 00865 fprintf(TFile,"hblkhd %10d\n",mi.hblkhd); 00866 fprintf(TFile,"hblks %10d\n",mi.hblks); 00867 fprintf(TFile,"usmblks %10d\n",mi.usmblks); 00868 fprintf(TFile,"fsmblks %10d\n",mi.fsmblks); 00869 fprintf(TFile,"uordblks %10d\n",mi.uordblks); 00870 fprintf(TFile,"fordblks %10d\n",mi.fordblks); 00871 fprintf(TFile,"keepcost %10d\n",mi.keepcost); 00872 00873 for ( pool = initialized_pools; 00874 pool != NULL; 00875 pool = MEM_POOL_rest(pool) 00876 ) { 00877 total_allocated += MEM_POOL_Report(pool,used_total); 00878 } 00879 fprintf(TFile,"++++ Total Allocated = %d\n",total_allocated); 00880 #else 00881 fprintf(TFile, 00882 "MEM_Trace: Not available; compiler not compiled with MEM_STATS\n"); 00883 #endif 00884 #else 00885 fprintf(TFile, 00886 "MEM_Trace: Not available; compiler not compiled with Is_True_On\n"); 00887 #endif 00888 } 00889 00890 00891 /* ==================================================================== 00892 * 00893 * Trace_Memory_Allocation 00894 * 00895 * Do a memory trace if request via command-line switch. 00896 * 00897 * ==================================================================== 00898 */ 00899 void 00900 Trace_Memory_Allocation ( 00901 const INT phase, /* Phase after which we're printing */ 00902 const char *const pname ) /* Print name for phase */ 00903 { 00904 if ( Get_Trace ( TKIND_ALLOC, phase ) ) { 00905 fprintf ( TFile, 00906 "\n%s%s\tMemory allocation information after %s\n%s%s\n", 00907 DBar, DBar, pname, DBar, DBar ); 00908 MEM_Trace (); 00909 } 00910 } 00911 00912 /* ==================================================================== 00913 * 00914 * MEM_Tracing_Enable 00915 * 00916 * Turn on statistics gathering. 00917 * 00918 * ==================================================================== 00919 */ 00920 00921 void 00922 MEM_Tracing_Enable(void) 00923 { 00924 #ifdef Is_True_On 00925 mem_tracing_enabled = TRUE; 00926 #endif 00927 } 00928 00929 00930 00931 #if Is_True_On 00932 const char *special_address = NULL; 00933 const char *special_address_owner = "NOBODY"; 00934 #endif 00935 00936 /* ==================================================================== 00937 * 00938 * Allocate_Block 00939 * 00940 * Allocate a new block to a pool. 00941 * 00942 * 'pool' Allocate a new block to this pool 00943 * 00944 * ==================================================================== 00945 */ 00946 00947 static MEM_PTR 00948 Allocate_Block (MEM_POOL *pool) 00949 { 00950 MEM_BLOCK *block = (MEM_BLOCK *) 00951 malloc (BLOCK_SIZE + PAD_TO_ALIGN(sizeof(MEM_BLOCK))); 00952 00953 if (block == NULL) 00954 ErrMsg (EC_No_Mem, "Allocate_Block"); 00955 00956 if ( MEM_POOL_bz(pool) ) 00957 memset (block, '\0', BLOCK_SIZE + PAD_TO_ALIGN(sizeof(MEM_BLOCK))); 00958 00959 #ifdef ZAP_ON_FREE 00960 else 00961 memset(((char *) block), 0xa5, 00962 BLOCK_SIZE + PAD_TO_ALIGN(sizeof(MEM_BLOCK))); 00963 #endif 00964 00965 MEM_BLOCK_avail(block) = BLOCK_SIZE; 00966 MEM_BLOCK_ptr(block) = MEM_BLOCK_first_ptr(block); 00967 MEM_BLOCK_rest(block) = MEM_POOL_block(pool); 00968 MEM_POOL_block(pool) = block; 00969 00970 #if Is_True_On 00971 if (special_address >= ((char *) MEM_BLOCK_ptr(block)) && 00972 special_address < (((char *) MEM_BLOCK_ptr(block)) + 00973 MEM_BLOCK_avail(block))) { 00974 fprintf(TFile, "Pool %s given %llu bytes from 0x%p to 0x%p\n", 00975 MEM_POOL_name(pool), (UINT64)MEM_BLOCK_avail(block), 00976 (char *) MEM_BLOCK_ptr(block), 00977 ((char *) MEM_BLOCK_ptr(block)) + MEM_BLOCK_avail(block)); 00978 special_address_owner = MEM_POOL_name(pool); 00979 } 00980 #endif 00981 00982 return block; 00983 } 00984 00985 /* ==================================================================== 00986 * 00987 * Allocate_Large_Block 00988 * 00989 * Allocate a new large block to a pool. 00990 * 00991 * 'pool' Allocate a new block to this pool 00992 * 'size' size of the new block 00993 * 00994 * ==================================================================== 00995 */ 00996 00997 static MEM_PTR 00998 Allocate_Large_Block (MEM_POOL *pool, INT32 size) 00999 { 01000 MEM_LARGE_BLOCK *block; 01001 size += MEM_LARGE_BLOCK_OVERHEAD; 01002 block = (MEM_LARGE_BLOCK *) malloc (size); 01003 01004 if (block == NULL) 01005 ErrMsg (EC_No_Mem, "Allocate_Large_Block"); 01006 01007 if ( MEM_POOL_bz(pool) ) { 01008 memset (block, '\0', size); 01009 } 01010 01011 #ifdef ZAP_ON_FREE 01012 else 01013 memset(((char *) block), 0xa5, size); 01014 #endif 01015 01016 MEM_LARGE_BLOCK_ptr(block) = (MEM_PTR) 01017 (((char *)block) + MEM_LARGE_BLOCK_OVERHEAD); 01018 MEM_LARGE_BLOCK_base(block) = MEM_POOL_blocks(pool); 01019 MEM_LARGE_BLOCK_next(block) = MEM_POOL_large_block(pool); 01020 MEM_LARGE_BLOCK_prev(block) = NULL; 01021 if (MEM_LARGE_BLOCK_next(block) != NULL) 01022 MEM_LARGE_BLOCK_prev(MEM_LARGE_BLOCK_next(block)) = block; 01023 MEM_POOL_large_block(pool) = block; 01024 01025 return MEM_LARGE_BLOCK_ptr(block); 01026 } 01027 01028 /* ==================================================================== 01029 * 01030 * Raw_Allocate 01031 * 01032 * Allocate memory from a pool having determined which block size to 01033 * use. 01034 * 01035 * pool - the pool to allocate from 01036 * size - How much to allocate. Already rouneded up to double 01037 * word alignment 01038 * 01039 * ==================================================================== 01040 */ 01041 01042 static MEM_PTR 01043 Raw_Allocate( 01044 MEM_POOL *pool, 01045 INT32 size 01046 ) 01047 { 01048 MEM_PTR *result; 01049 01050 if (size <= MIN_LARGE_BLOCK_SIZE) { 01051 MEM_BLOCK *b; 01052 b = MEM_POOL_block(pool); 01053 01054 if (b == NULL || MEM_BLOCK_avail(b) < size) { 01055 b = Allocate_Block (pool); 01056 } 01057 01058 result = MEM_BLOCK_ptr(b); 01059 MEM_BLOCK_ptr(b) = (MEM_PTR) (((char*) MEM_BLOCK_ptr(b)) + size); 01060 MEM_BLOCK_avail(b) -= size; 01061 01062 return result; 01063 } else 01064 01065 return Allocate_Large_Block (pool, size); 01066 } 01067 01068 /* ==================================================================== 01069 * 01070 * MEM_POOL_Allocate 01071 * 01072 * Allocate memory out of a pool. 01073 * 01074 * 'pool' - The pool to allocate from. 01075 * 'size' - How much to allocate. 01076 * 01077 * ==================================================================== 01078 */ 01079 01080 MEM_PTR 01081 MEM_POOL_Alloc_P 01082 ( 01083 MEM_POOL *pool, 01084 size_t size 01085 MEM_STAT_ARGS(line,file) 01086 ) 01087 { 01088 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01089 if (pool == Malloc_Mem_Pool) { 01090 MEM_PTR p = malloc(size); 01091 if (p == NULL) 01092 ErrMsg (EC_No_Mem, "MEM_POOL_Alloc"); 01093 return p; 01094 } 01095 01096 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01097 ("Alloc from un-initialized MEM_POOL %s\n", MEM_POOL_name(pool))); 01098 01099 #ifdef JUST_USE_MALLOC 01100 return calloc(1,size); 01101 #endif 01102 01103 if (purify_pools) { 01104 MEM_PTR ret_val; 01105 /* Check to see that this pool was pushed before this allocation. 01106 */ 01107 if (!MEM_POOL_blocks(pool)) { 01108 DevWarn("Allocation from %s before MEM_POOL_Push(%s)", 01109 MEM_POOL_name(pool), MEM_POOL_name(pool)); 01110 MEM_POOL_blocks(pool) = (MEM_POOL_BLOCKS *) TRUE; 01111 } 01112 01113 ret_val = calloc(1,size+8); 01114 Is_True (ret_val, ("MEM_POOL_Alloc: calloc returned NULL")); 01115 Is_True (MEM_POOL_pure_stack(pool), ("MEM_POOL_Alloc %s: missing stack", 01116 MEM_POOL_name(pool))); 01117 *(MEM_PTR*)ret_val = MEM_POOL_last_alloc(pool); 01118 MEM_POOL_last_alloc(pool) = ret_val; 01119 if (purify_pools_trace) 01120 printf ("pool %s, alloc 0x%p, size %llu, (0x%p - 0x%p)\n", 01121 MEM_POOL_name(pool), (char *)ret_val+8, (UINT64)size, 01122 (char *)ret_val+8, (char *)ret_val+size); 01123 return ((MEM_PTR) ((size_t)ret_val+8)); 01124 } 01125 01126 Is_True(MEM_POOL_blocks(pool) != NULL, 01127 ("Alloc with uninitialized MEM_POOL")); 01128 #ifdef Is_True_On 01129 if ( mem_tracing_enabled ) 01130 Site_Account_Alloc(pool,0,size,line,file); 01131 #endif 01132 01133 /* Round size to double word so any double will be correctly aligned 01134 */ 01135 size = PAD_TO_ALIGN(size); 01136 01137 return Raw_Allocate(pool,size); 01138 01139 } 01140 01141 01142 /* ==================================================================== 01143 * 01144 * MEM_POOL_Realloc 01145 * 01146 * See interface description 01147 * 01148 * ==================================================================== 01149 */ 01150 01151 MEM_PTR 01152 MEM_POOL_Realloc_P 01153 ( 01154 MEM_POOL *pool, 01155 MEM_PTR old_block, 01156 size_t old_size, 01157 size_t new_size 01158 MEM_STAT_ARGS(line,file) 01159 ) 01160 { 01161 MEM_PTR result; 01162 01163 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01164 if (pool == Malloc_Mem_Pool) { 01165 MEM_PTR p = realloc(old_block,new_size); 01166 if (p == NULL) 01167 ErrMsg (EC_No_Mem, "MEM_POOL_Realloc"); 01168 return p; 01169 } 01170 01171 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01172 ("Realloc from un-initialized MEM_POOL %s\n", MEM_POOL_name(pool))); 01173 01174 #ifdef JUST_USE_MALLOC 01175 result = realloc(old_block,new_size); 01176 if ( old_size < new_size ) 01177 memset((char*)result + old_size, '\0', new_size - old_size); 01178 return result; 01179 #endif 01180 01181 if (purify_pools) { 01182 MEM_PTR ret_val = NULL; 01183 BOOL foundit = FALSE; 01184 01185 if (!MEM_POOL_blocks(pool)) { 01186 DevWarn("Realloc from %s before MEM_POOL_Push(%s)", 01187 MEM_POOL_name(pool), MEM_POOL_name(pool)); 01188 MEM_POOL_blocks(pool) = (MEM_POOL_BLOCKS *) TRUE; 01189 } 01190 01191 /* Find the thing that points to this location, but if orig non-null */ 01192 if (old_block) { 01193 /* find the previous entry and remove it */ 01194 MEM_PURE_STACK* tmp_stack = MEM_POOL_pure_stack(pool); 01195 MEM_PTR cur = (MEM_PTR) ((size_t) old_block - 8); 01196 Is_True (tmp_stack, ("MEM_POOL_Realloc %s: missing stack", 01197 MEM_POOL_name(pool))); 01198 while (tmp_stack) { 01199 MEM_PTR tmp = MEM_PURE_STACK_last_alloc(tmp_stack); 01200 MEM_PTR prev = NULL; 01201 01202 while (tmp && (tmp != cur)) { 01203 prev = tmp; 01204 tmp = *((MEM_PTR*) tmp); 01205 } 01206 if (tmp) { 01207 foundit = TRUE; 01208 /* splice it out */ 01209 if (prev) *(MEM_PTR*) prev = *(MEM_PTR*) tmp; 01210 else MEM_PURE_STACK_last_alloc(tmp_stack) = *(MEM_PTR*) tmp; 01211 break; 01212 } 01213 tmp_stack = MEM_PURE_STACK_prev_stack(tmp_stack); 01214 } 01215 } 01216 if (old_block && !foundit) { 01217 DevWarn ("Realloc without a previous alloc, pool %s, 0x%p", 01218 MEM_POOL_name(pool), old_block); 01219 /* Do a malloc and copy */ 01220 ret_val = (MEM_PTR) malloc (new_size+8); 01221 memmove((MEM_PTR) (((size_t) ret_val)+8), old_block, old_size); 01222 } 01223 else { 01224 /* either found it or old_block was null, so do a real realloc */ 01225 ret_val = (MEM_PTR) 01226 realloc((MEM_PTR) (old_block ? (size_t) old_block-8 : 0), 01227 new_size+8); 01228 } 01229 if (new_size > 0) { 01230 FmtAssert (ret_val, ("oops - realloc returned NULL, pool %s\n", 01231 MEM_POOL_name(pool))); 01232 *(MEM_PTR*) ret_val = MEM_POOL_last_alloc(pool); 01233 MEM_POOL_last_alloc(pool) = ret_val; 01234 ret_val = (MEM_PTR) ((size_t) ret_val + 8); 01235 if ( old_size < new_size ) 01236 memset((char*)ret_val + old_size, '\0', new_size - old_size); 01237 } 01238 if (purify_pools_trace) 01239 printf ("pool %s, realloc 0x%p, new size %llu, (0x%p - 0x%p)\n", 01240 MEM_POOL_name(pool), ret_val, (UINT64)new_size, 01241 ret_val, (char *)ret_val + new_size - 8); 01242 return ret_val; 01243 } 01244 01245 Is_True(MEM_POOL_blocks(pool) != NULL, 01246 ("Alloc with uninitialized MEM_POOL")); 01247 #ifdef Is_True_On 01248 if ( mem_tracing_enabled ) 01249 Site_Account_Alloc(pool,old_size,new_size,line,file); 01250 #endif 01251 01252 /* Round size to double word so any double will be correctly aligned 01253 */ 01254 old_size = PAD_TO_ALIGN(old_size); 01255 new_size = PAD_TO_ALIGN(new_size); 01256 01257 /* It might already be just the right size. 01258 */ 01259 if ( new_size == old_size ) 01260 return old_block; 01261 01262 #if 0 01263 #ifdef Is_True_On 01264 if (new_size < old_size) 01265 DevWarn ("MEMORY: shrinking an object in (%s) from %d to %d bytes", 01266 MEM_POOL_name(pool), old_size, new_size); 01267 else if (new_size < old_size * 1.5 && old_size > 256) 01268 DevWarn ("MEMORY: small grow from %d to %d bytes (mempool: %s)", 01269 old_size, new_size, MEM_POOL_name(pool)); 01270 #endif 01271 #endif 01272 01273 if (old_size <= MIN_LARGE_BLOCK_SIZE) { 01274 if (new_size < old_size) 01275 return old_block; 01276 else { 01277 result = Raw_Allocate (pool, new_size); 01278 memmove (result, old_block, old_size); 01279 return result; 01280 } 01281 } else { 01282 MEM_LARGE_BLOCK *large_block = (MEM_LARGE_BLOCK *) 01283 (((char *) old_block) - MEM_LARGE_BLOCK_OVERHEAD); 01284 if (MEM_LARGE_BLOCK_ptr(large_block) == (MEM_PTR) old_block && 01285 MEM_LARGE_BLOCK_base(large_block) == MEM_POOL_blocks(pool)) { 01286 /* this is a valid large block that we can reallocate */ 01287 if (new_size <= MIN_LARGE_BLOCK_SIZE) { 01288 result = Raw_Allocate (pool, new_size); 01289 memmove (result, old_block, new_size); 01290 MEM_POOL_FREE (pool, old_block); 01291 return result; 01292 } else { 01293 MEM_LARGE_BLOCK *p = 01294 (MEM_LARGE_BLOCK *)(((char *)old_block) - MEM_LARGE_BLOCK_OVERHEAD); 01295 01296 large_block = 01297 MEM_LARGE_BLOCK_realloc(p, new_size + MEM_LARGE_BLOCK_OVERHEAD); 01298 01299 if (large_block == NULL) 01300 ErrMsg (EC_No_Mem, "MEM_POOL_Realloc"); 01301 MEM_LARGE_BLOCK_ptr(large_block) = (MEM_PTR) 01302 (((char *)large_block) + MEM_LARGE_BLOCK_OVERHEAD); 01303 if (MEM_POOL_bz(pool)) { 01304 memset (((char *) MEM_LARGE_BLOCK_ptr(large_block)) + old_size, 01305 '\0', new_size - old_size); 01306 } 01307 p = MEM_LARGE_BLOCK_prev(large_block); 01308 if (p == NULL) 01309 MEM_POOL_large_block(pool) = large_block; 01310 else 01311 MEM_LARGE_BLOCK_next(p) = large_block; 01312 p = MEM_LARGE_BLOCK_next(large_block); 01313 if (p) 01314 MEM_LARGE_BLOCK_prev(p) = large_block; 01315 return MEM_LARGE_BLOCK_ptr(large_block); 01316 } 01317 } else { 01318 result = Raw_Allocate (pool, new_size); 01319 if (new_size > old_size) 01320 memmove (result, old_block, old_size); 01321 else 01322 memmove (result, old_block, new_size); 01323 return result; 01324 } 01325 } 01326 } 01327 01328 /* ==================================================================== 01329 * 01330 * MEM_POOL_Push 01331 * 01332 * Push a MEM_POOL to a new allocation level. Memory can be 01333 * No memory can be allocated in a pool until it's pushed the first 01334 * time. 01335 * 01336 * 'pool' - memory pool to push 01337 * 01338 * ==================================================================== 01339 */ 01340 01341 void 01342 MEM_POOL_Push_P 01343 ( 01344 MEM_POOL *pool 01345 MEM_STAT_ARGS(line,file) 01346 ) 01347 { 01348 MEM_POOL_BLOCKS *pb; 01349 01350 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01351 ("Push before Initialize in MEM_POOL %s\n", MEM_POOL_name(pool))); 01352 01353 FmtAssert(MEM_POOL_frozen(pool) == FALSE, ("Pushing a frozen pool - %s.", 01354 MEM_POOL_name(pool))); 01355 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01356 if (pool == Malloc_Mem_Pool) return; 01357 #ifdef JUST_USE_MALLOC 01358 return; 01359 #endif 01360 01361 if (purify_pools) { 01362 MEM_PURE_STACK* tmp = (MEM_PURE_STACK*) malloc(sizeof(MEM_PURE_STACK)); 01363 Is_True (tmp, ("MEM_POOL_Push %s: malloc stack returned NULL", 01364 MEM_POOL_name(pool))); 01365 MEM_PURE_STACK_last_alloc(tmp) = NULL; 01366 MEM_PURE_STACK_prev_stack(tmp) = MEM_POOL_pure_stack(pool); 01367 MEM_POOL_pure_stack(pool) = tmp; 01368 if (purify_pools_trace_x) { 01369 if (MEM_POOL_blocks(pool) == (MEM_POOL_BLOCKS *) MEM_POOL_INIT_IN_PROGRESS) { 01370 (void) printf("MEM_POOL_Push %s 0x%p<-- free push (called by M_P_Initialize)\n", 01371 MEM_POOL_name(pool), pool); 01372 } 01373 else { 01374 (void) printf ("MEM_POOL_Push %s 0x%p\n", MEM_POOL_name(pool), pool); 01375 } 01376 } 01377 01378 /* Co-opt the blocks field to note whether we have kosher 01379 * push-before-alloc behavior. 01380 */ 01381 MEM_POOL_blocks(pool) = (MEM_POOL_BLOCKS *) TRUE; 01382 return; 01383 } 01384 01385 #ifdef Is_True_On 01386 if ( mem_tracing_enabled ) 01387 Site_Account_Push(pool,line,file); 01388 #endif 01389 01390 if ( free_mem_pool_blocks_list != NULL ) { 01391 /* Can take from free list. 01392 */ 01393 pb = free_mem_pool_blocks_list; 01394 free_mem_pool_blocks_list = MEM_POOL_BLOCKS_rest(pb); 01395 } else { 01396 /* Need to allocate a new one. 01397 */ 01398 pb = TYPE_MEM_POOL_ALLOC(MEM_POOL_BLOCKS,&mem_overhead_pool); 01399 } 01400 01401 MEM_POOL_BLOCKS_rest(pb) = MEM_POOL_blocks(pool); 01402 MEM_POOL_BLOCKS_large_block(pb) = NULL; 01403 if (MEM_POOL_BLOCKS_rest(pb) == NULL) { 01404 MEM_POOL_BLOCKS_block(pb) = NULL; 01405 MEM_POOL_BLOCKS_base_block(pb) = NULL; 01406 MEM_POOL_BLOCKS_base_ptr(pb) = NULL; 01407 MEM_POOL_BLOCKS_base_avail(pb) = 0; 01408 } else { 01409 MEM_POOL_BLOCKS *p = MEM_POOL_BLOCKS_rest(pb); 01410 MEM_POOL_BLOCKS_block(pb) = MEM_POOL_BLOCKS_block(p); 01411 MEM_POOL_BLOCKS_base_block(pb) = MEM_POOL_BLOCKS_block(p); 01412 if (MEM_POOL_BLOCKS_block(p)) { 01413 MEM_POOL_BLOCKS_base_ptr(pb) = MEM_BLOCK_ptr(MEM_POOL_BLOCKS_block(p)); 01414 MEM_POOL_BLOCKS_base_avail(pb) = 01415 MEM_BLOCK_avail(MEM_POOL_BLOCKS_block(p)); 01416 } else { 01417 MEM_POOL_BLOCKS_base_ptr(pb) = NULL; 01418 MEM_POOL_BLOCKS_base_avail(pb) = 0; 01419 } 01420 } 01421 MEM_POOL_blocks(pool) = pb; 01422 } 01423 01424 /* ==================================================================== 01425 * 01426 * MEM_POOL_Push_Freeze 01427 * 01428 * Check that the pool is not already frozen. If not, push a pool 01429 * to a new allocation level and then freeze it from subsequent push/pop 01430 * operations until the pool is explicitly unfrozen. 01431 * 01432 * 'pool' - is the pool to push-and-freeze 01433 * 01434 * ==================================================================== 01435 */ 01436 01437 void 01438 MEM_POOL_Push_Freeze_P 01439 ( 01440 MEM_POOL *pool 01441 MEM_STAT_ARGS(line,file) 01442 ) 01443 { 01444 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01445 ("Push_Freeze before Initialize in MEM_POOL %s\n", MEM_POOL_name(pool))); 01446 FmtAssert (MEM_POOL_frozen(pool) == FALSE, 01447 ("Cannot Push_Freeze a frozen pool - %s.", MEM_POOL_name(pool))); 01448 if (purify_pools_trace_x) 01449 printf ("MEM_POOL_Push_Freeze %s -- \n", MEM_POOL_name(pool)); 01450 MEM_POOL_Push_P (pool, line, file); 01451 MEM_POOL_frozen(pool) = TRUE; 01452 } 01453 01454 01455 /* ==================================================================== 01456 * 01457 * MEM_POOL_Pop 01458 * 01459 * Pop the state of the given MEM_POOL, freeing any memory allocated 01460 * since the matching call to MEM_POOL_Push. 01461 * 01462 * 'pool' - is the pool to pop. 01463 * 01464 * ==================================================================== 01465 */ 01466 01467 void 01468 MEM_POOL_Pop_P 01469 ( 01470 MEM_POOL *pool 01471 MEM_STAT_ARGS(line,file) 01472 ) 01473 { 01474 MEM_BLOCK *bp, *next_bp; 01475 MEM_LARGE_BLOCK *lbp, *next_lbp; 01476 MEM_POOL_BLOCKS *bsp; 01477 01478 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01479 ("Pop before Initialize in MEM_POOL %s\n", MEM_POOL_name(pool))); 01480 01481 FmtAssert(MEM_POOL_frozen(pool) == FALSE, ("Popping a frozen pool - %s.", 01482 MEM_POOL_name(pool))); 01483 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01484 if (pool == Malloc_Mem_Pool) return; 01485 01486 #ifdef JUST_USE_MALLOC 01487 return; 01488 #endif 01489 if (purify_pools) { 01490 MEM_PURE_STACK *tmp_stack; 01491 MEM_PTR tmp = NULL; 01492 MEM_PTR next = NULL; 01493 Is_True (MEM_POOL_pure_stack(pool), 01494 ("Pop, but no push stack on %s", MEM_POOL_name(pool))); 01495 if (purify_pools_trace_x) 01496 printf ("MEM_POOL_Pop %s 0x%p\n", MEM_POOL_name(pool), pool); 01497 tmp = MEM_POOL_last_alloc(pool); 01498 while (tmp) { 01499 next = (*(MEM_PTR*) tmp); 01500 if (purify_pools_trace) printf ("pool %s, pop-free 0x%p\n", 01501 MEM_POOL_name(pool), (char *)tmp+8); 01502 free (tmp); 01503 tmp = next; 01504 } 01505 tmp_stack = MEM_POOL_prev_stack(pool); 01506 free (MEM_POOL_pure_stack(pool)); 01507 MEM_POOL_pure_stack(pool) = tmp_stack; 01508 return; 01509 } 01510 01511 bsp = MEM_POOL_blocks(pool); 01512 01513 FmtAssert(MEM_POOL_blocks(pool),("Freeing an uninitialized pool.")); 01514 01515 #ifdef Is_True_On 01516 if ( mem_tracing_enabled ) 01517 Site_Account_Pop(pool,line,file); 01518 #endif 01519 01520 for (bp = MEM_POOL_BLOCKS_block(bsp); bp; bp = next_bp) { 01521 next_bp = MEM_BLOCK_rest(bp); 01522 01523 #if Is_True_On 01524 if (special_address >= (char *) MEM_BLOCK_first_ptr(bp) && 01525 special_address < ((char *) MEM_BLOCK_ptr(bp) + 01526 MEM_BLOCK_avail(bp))) { 01527 fprintf(TFile, "Pool %s freed %llu bytes from 0x%p to 0x%p\n", 01528 MEM_POOL_name(pool), 01529 (UINT64)(MEM_BLOCK_avail(bp) + 01530 (char *) MEM_BLOCK_ptr(bp) - 01531 (char *) MEM_BLOCK_first_ptr(bp)), 01532 (char *) MEM_BLOCK_first_ptr(bp), 01533 (char *) MEM_BLOCK_ptr(bp) + MEM_BLOCK_avail(bp)); 01534 special_address_owner = "NOBODY"; 01535 } 01536 #endif 01537 01538 if (bp == MEM_POOL_BLOCKS_base_block(bsp)) { 01539 MEM_BLOCK_ptr(bp) = MEM_POOL_BLOCKS_base_ptr(bsp); 01540 MEM_BLOCK_avail(bp) = MEM_POOL_BLOCKS_base_avail(bsp); 01541 if (MEM_POOL_bz(pool)) 01542 memset (MEM_BLOCK_ptr(bp), '\0', MEM_BLOCK_avail(bp)); 01543 break; 01544 } 01545 free (bp); 01546 } 01547 01548 for (lbp = MEM_POOL_BLOCKS_large_block(bsp); lbp; lbp = next_lbp) { 01549 next_lbp = MEM_LARGE_BLOCK_next(lbp); 01550 MEM_LARGE_BLOCK_free(lbp); 01551 } 01552 01553 /* Avoid poping the final blocks from a pool. This allow a usage 01554 * like: 01555 * MEM_POOL_Alloc 01556 * ... 01557 * MEM_POOL_Pop 01558 * without the initial push. 01559 */ 01560 if ( MEM_POOL_BLOCKS_rest(bsp) != NULL ) { 01561 MEM_POOL_blocks(pool) = MEM_POOL_BLOCKS_rest(bsp); 01562 MEM_POOL_BLOCKS_rest(bsp) = free_mem_pool_blocks_list; 01563 free_mem_pool_blocks_list = bsp; 01564 } else { 01565 memset (bsp, '\0', sizeof(MEM_POOL_BLOCKS)); 01566 } 01567 } 01568 01569 01570 /* ==================================================================== 01571 * 01572 * MEM_POOL_Pop_Unfreeze 01573 * 01574 * Check that the pool is frozen. 01575 * Then unfreeze the memory pool, and pop. 01576 * 01577 * 'pool' - is the pool to pop. 01578 * 01579 * ==================================================================== 01580 */ 01581 01582 void 01583 MEM_POOL_Pop_Unfreeze_P 01584 ( 01585 MEM_POOL *pool 01586 MEM_STAT_ARGS(line,file) 01587 ) 01588 { 01589 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01590 ("Pop_Unfreeze before Initialize in MEM_POOL %s\n", MEM_POOL_name(pool))); 01591 FmtAssert (MEM_POOL_frozen(pool) == TRUE, 01592 ("Cannot Pop_Unfreeze a non-frozen pool - %s.", 01593 MEM_POOL_name(pool))); 01594 MEM_POOL_frozen(pool) = FALSE; 01595 if (purify_pools_trace_x) 01596 printf ("MEM_POOL_Pop_Unfreeze %s -- \n", MEM_POOL_name(pool)); 01597 MEM_POOL_Pop_P (pool, line, file); 01598 } 01599 01600 void MEM_POOL_Set_Default(MEM_POOL *pool) 01601 { 01602 The_Default_Mem_Pool = pool; 01603 } 01604 01605 void MEM_POOL_FREE(MEM_POOL *pool, void *data) 01606 { 01607 MEM_LARGE_BLOCK *large_block; 01608 01609 if (data == NULL) 01610 return; 01611 01612 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01613 if (pool == Malloc_Mem_Pool) { 01614 free(data); 01615 return; 01616 } 01617 01618 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01619 ("Free into un-initialized MEM_POOL %s\n", MEM_POOL_name(pool))); 01620 01621 #ifdef JUST_USE_MALLOC 01622 return; 01623 #endif 01624 if (data && purify_pools) { 01625 BOOL foundit = FALSE; 01626 /* find the entry and remove it */ 01627 MEM_PURE_STACK* tmp_stack = MEM_POOL_pure_stack(pool); 01628 MEM_PTR cur = (MEM_PTR) ((size_t) data - 8); 01629 Is_True (tmp_stack, ("MEM_POOL_Realloc %s: missing stack", 01630 MEM_POOL_name(pool))); 01631 while (tmp_stack) { 01632 MEM_PTR tmp = MEM_PURE_STACK_last_alloc(tmp_stack); 01633 MEM_PTR prev = NULL; 01634 01635 while (tmp && (tmp != cur)) { 01636 prev = tmp; 01637 tmp = *((MEM_PTR*) tmp); 01638 } 01639 if (tmp) { 01640 foundit = TRUE; 01641 /* splice it out */ 01642 if (prev) *(MEM_PTR*) prev = *(MEM_PTR*) tmp; 01643 else MEM_PURE_STACK_last_alloc(tmp_stack) = *(MEM_PTR*) tmp; 01644 break; 01645 } 01646 tmp_stack = MEM_PURE_STACK_prev_stack(tmp_stack); 01647 } 01648 if (purify_pools_trace) 01649 printf ("pool %s, free 0x%p\n", MEM_POOL_name(pool), data); 01650 if (!foundit) { 01651 /* free anyway, so that it shows up as a purify error */ 01652 free (cur); 01653 FmtAssert(FALSE,("MEM_POOL_FREE: pool %s, could not find pointer 0x%p\n", 01654 MEM_POOL_name(pool), data)); 01655 } 01656 free (cur); 01657 return; 01658 } 01659 01660 large_block = (MEM_LARGE_BLOCK *) 01661 (((char *) data) - MEM_LARGE_BLOCK_OVERHEAD); 01662 if (MEM_LARGE_BLOCK_ptr(large_block) == (MEM_PTR) data) { 01663 MEM_LARGE_BLOCK *prev; 01664 MEM_LARGE_BLOCK *next; 01665 if (MEM_LARGE_BLOCK_base(large_block) != MEM_POOL_blocks(pool)) 01666 return; 01667 01668 prev = MEM_LARGE_BLOCK_prev(large_block); 01669 next = MEM_LARGE_BLOCK_next(large_block); 01670 if (prev == NULL) 01671 MEM_POOL_large_block(pool) = next; 01672 else 01673 MEM_LARGE_BLOCK_next(prev) = next; 01674 01675 if (next) 01676 MEM_LARGE_BLOCK_prev(next) = prev; 01677 01678 MEM_LARGE_BLOCK_free(large_block); 01679 } 01680 01681 } 01682 01683 #ifdef Is_True_On 01684 static void 01685 trace_initialized_pool (char *msg, char *pname) 01686 { 01687 MEM_POOL **listp = &initialized_pools; 01688 printf("<%s %s> initialized_pools: ", msg, pname); 01689 while (*listp != NULL) { 01690 printf(", %s", MEM_POOL_name(*listp)); 01691 listp = &MEM_POOL_rest(*listp); 01692 } 01693 printf("\n"); 01694 } 01695 #endif 01696 01697 void MEM_POOL_Delete(MEM_POOL *pool) 01698 { 01699 MEM_POOL_BLOCKS *bsp; 01700 01701 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01702 if (pool == Malloc_Mem_Pool) return; 01703 01704 #ifdef Is_True_On 01705 /* 01706 * Remove from initialized_pools list so we don't get bogus stats. 01707 * To enable stats for deleted pools, need to keep a stats data 01708 * structure separate from the pools themselves. I think we want to 01709 * accumulate stats for pools of the same name that are created 01710 * within a given run. 01711 */ 01712 if ( mem_tracing_enabled ) { 01713 MEM_POOL **listp = &initialized_pools; 01714 /* trace_initialized_pool ("delete", MEM_POOL_name(pool)); */ 01715 if (*listp == pool) { 01716 initialized_pools = MEM_POOL_rest(pool); 01717 } 01718 else { 01719 while (*listp && MEM_POOL_rest(*listp)) { 01720 if (MEM_POOL_rest(*listp) == pool) break; 01721 listp = &MEM_POOL_rest(*listp); 01722 } 01723 if (*listp && MEM_POOL_rest(*listp)) { 01724 /* found it */ 01725 MEM_POOL_rest(*listp) = MEM_POOL_rest(pool); 01726 } 01727 else { 01728 DevWarn("didn't find pool %s in initialized_pools", MEM_POOL_name(pool)); 01729 } 01730 } 01731 Is_True(!MEM_STAT_In_List( initialized_pools, pool ), 01732 ("Pool still in initialized list")); 01733 } 01734 #endif 01735 01736 Is_True (MEM_POOL_magic_num(pool) == MAGIC_NUM, 01737 ("Deleting a pool that has not been initialized: %s\n", 01738 MEM_POOL_name(pool))); 01739 01740 if (purify_pools) { 01741 /* let's be nice and deallocate all storage */ 01742 #ifndef TODO_REMOVE_FREE_PUSH 01743 if (!MEM_POOL_pure_stack(pool)) { 01744 DevWarn("During MEM_POOL_Delete: Too many pops on %s.", 01745 MEM_POOL_name(pool)); 01746 } 01747 else { 01748 MEM_POOL_Pop(pool); 01749 #endif 01750 if (MEM_POOL_pure_stack(pool)) { 01751 DevWarn("During MEM_POOL_Delete: Too few pops on %s.", 01752 MEM_POOL_name(pool)); 01753 while (MEM_POOL_pure_stack(pool)) 01754 MEM_POOL_Pop(pool); 01755 } 01756 #ifndef TODO_REMOVE_FREE_PUSH 01757 } 01758 #endif 01759 if (purify_pools_trace_x) 01760 printf ("MEM_POOL_Delete %s 0x%p\n", MEM_POOL_name(pool), pool); 01761 MEM_POOL_magic_num(pool) = 0; 01762 return; 01763 } 01764 01765 /* Pop everything to make old blocks available for re-use. 01766 * Must treat last block specially since MEM_POOL_Pop doesn't 01767 * make last block available for reuse by other pools. 01768 */ 01769 while (MEM_POOL_BLOCKS_rest(MEM_POOL_blocks(pool)) != NULL) 01770 MEM_POOL_Pop(pool); 01771 MEM_POOL_Pop(pool); 01772 bsp = MEM_POOL_blocks(pool); 01773 MEM_POOL_BLOCKS_rest(bsp) = free_mem_pool_blocks_list; 01774 free_mem_pool_blocks_list = bsp; 01775 01776 memset (pool, '\0', sizeof(MEM_POOL)); 01777 MEM_POOL_magic_num(pool) = 0; 01778 } 01779 01780 01781 /* ==================================================================== 01782 * 01783 * MEM_POOL_Initialize 01784 * 01785 * Initialize a new MEM_POOL. Must be done before it can be pushed. 01786 * 01787 * 'pool' - is the pool to initialize 01788 * 'name' - a name to associate with the pool for debugging purposes 01789 * (NOT copied.) 01790 * 'memzero' - if true, memory allocate from the pool will always be 01791 * zeroed, otherwise no guarantee. 01792 * 01793 * ==================================================================== 01794 */ 01795 01796 void 01797 MEM_POOL_Initialize_P 01798 ( 01799 MEM_POOL *pool, 01800 const char *name, 01801 BOOL memzero 01802 MEM_STAT_ARGS(line,file) 01803 ) 01804 { 01805 if (pool == Default_Mem_Pool) pool = The_Default_Mem_Pool; 01806 if (pool == Malloc_Mem_Pool) return; 01807 01808 MEM_POOL_name(pool) = name; 01809 MEM_POOL_bz(pool) = memzero; 01810 MEM_POOL_blocks(pool) = NULL; 01811 MEM_POOL_frozen(pool) = FALSE; 01812 MEM_POOL_pure_stack(pool) = NULL; 01813 01814 /* Don't allow duplicate initializations */ 01815 Is_True (MEM_POOL_magic_num(pool) != MAGIC_NUM, 01816 ("Initialization of an already initialized pool: %s\n", 01817 MEM_POOL_name(pool))); 01818 MEM_POOL_magic_num(pool) = MAGIC_NUM; 01819 01820 if (purify_pools_trace_x) 01821 printf ("MEM_POOL_Initialize %s 0x%p\n", MEM_POOL_name(pool), pool); 01822 01823 #ifdef Is_True_On 01824 MEM_POOL_alloc_site_list(pool) = NULL; 01825 if ( mem_tracing_enabled ) { 01826 if ( ! MEM_STAT_In_List( initialized_pools, pool ) ) { 01827 /* trace_initialized_pool ("initialize", MEM_POOL_name(pool)); */ 01828 MEM_POOL_rest(pool) = initialized_pools; 01829 initialized_pools = pool; 01830 } 01831 } 01832 #endif 01833 01834 if (purify_pools) { 01835 MEM_POOL_blocks(pool) = (MEM_POOL_BLOCKS *) MEM_POOL_INIT_IN_PROGRESS; 01836 } 01837 01838 #ifndef TODO_REMOVE_FREE_PUSH 01839 MEM_POOL_Push(pool); 01840 #endif 01841 01842 if (purify_pools) { 01843 /* Mark the pool as unpushed, even though we still do a push for 01844 * the moment. 01845 */ 01846 MEM_POOL_blocks(pool) = NULL; 01847 } 01848 } 01849 01850 /* ==================================================================== 01851 * 01852 * MEM_Initialize 01853 * 01854 * Initialize the memory package. Actually, just initialize the 01855 * backward compatible pools. 01856 * 01857 * ==================================================================== 01858 */ 01859 01860 void 01861 MEM_Initialize(void) 01862 { 01863 const char* ppools = getenv ("PURIFY_MEMPOOLS"); 01864 if (ppools) { 01865 if (((ppools[0] == 'O') || (ppools[0] == 'o')) && 01866 ((ppools[1] == 'N') || (ppools[1] == 'n'))) { 01867 purify_pools = TRUE; 01868 if ((ppools[2] == '-') && 01869 ((ppools[3] == 'T') || (ppools[3] == 't')) && 01870 ((ppools[4] == 'R') || (ppools[4] == 'r')) && 01871 ((ppools[5] == 'A') || (ppools[5] == 'a')) && 01872 ((ppools[6] == 'C') || (ppools[6] == 'c')) && 01873 ((ppools[7] == 'E') || (ppools[7] == 'e'))) { 01874 purify_pools_trace = TRUE; 01875 if ((ppools[8] == '-') && 01876 ((ppools[9] == 'X') || (ppools[9] == 'x'))) { 01877 purify_pools_trace_x = TRUE; 01878 if ((ppools[10] == '-') && 01879 ((ppools[11] == 'O') || (ppools[11] == 'o')) && 01880 ((ppools[12] == 'N') || (ppools[12] == 'n')) && 01881 ((ppools[13] == 'L') || (ppools[13] == 'l')) && 01882 ((ppools[14] == 'Y') || (ppools[14] == 'y'))) { 01883 purify_pools_trace = FALSE; 01884 DevWarn("Using purify memory pools, limited extended tracing ###"); 01885 } else 01886 DevWarn ("Using purify memory pools, with extended tracing ###"); 01887 } 01888 else 01889 DevWarn ("Using purify memory pools, with tracing ###"); 01890 } 01891 else DevWarn ("Using purify memory pools ###"); 01892 } 01893 else if (((ppools[0] == 'O') || (ppools[0] == 'o')) && 01894 ((ppools[1] == 'F') || (ppools[1] == 'f')) && 01895 ((ppools[2] == 'F') || (ppools[2] == 'f'))) { 01896 purify_pools = FALSE; 01897 } 01898 else DevWarn ("PURIFY_MEMPOOLS set to garbage, using regular pools"); 01899 } 01900 01901 MEM_POOL_Initialize(&MEM_local_pool,"Local",TRUE); 01902 MEM_POOL_Initialize(&MEM_src_pool,"Source",TRUE); 01903 MEM_POOL_Initialize(&MEM_pu_pool,"Program unit",TRUE); 01904 MEM_POOL_Initialize(&MEM_phase_pool,"Phase",TRUE); 01905 01906 MEM_POOL_Push(&MEM_local_pool); 01907 MEM_POOL_Push(&MEM_src_pool); 01908 MEM_POOL_Push(&MEM_pu_pool); 01909 MEM_POOL_Push(&MEM_phase_pool); 01910 01911 MEM_POOL_Initialize(&MEM_local_nz_pool,"Local (nz)",FALSE); 01912 MEM_POOL_Initialize(&MEM_src_nz_pool,"Source (nz)",FALSE); 01913 MEM_POOL_Initialize(&MEM_pu_nz_pool,"Program unit (nz)",FALSE); 01914 MEM_POOL_Initialize(&MEM_phase_nz_pool,"Phase (nz)",FALSE); 01915 01916 MEM_POOL_Push(&MEM_local_nz_pool); 01917 MEM_POOL_Push(&MEM_src_nz_pool); 01918 MEM_POOL_Push(&MEM_pu_nz_pool); 01919 MEM_POOL_Push(&MEM_phase_nz_pool); 01920 01921 } 01922 01923 /* Two non pool related things kept here for historical reasons. 01924 */ 01925 01926 /* ==================================================================== 01927 * 01928 * MEM_PTR Realloc_Clear ( ptr, new_size, old_size ) 01929 * 01930 * This routine is used to grow space that was initially allocated via 01931 * a call to the Unix routine 'malloc()'. 01932 * 01933 * This routine takes as input a pointer that was previously allocated 01934 * by, for example, 'malloc()', the new size (in bytes) to be allocated, 01935 * and old size (in bytes) that were allocated by the previous call to 01936 * 'malloc()'. It calls 'realloc()' to grow the space pointed to by 01937 * the input 'ptr', then clears the new space. Note that we need to 01938 * know the old size so we can determine which portion of the returned 01939 * space must be cleared (the contents of the original space must be 01940 * unchanged). 01941 * 01942 * Note that we fatal-error-out here if we cannot allocate enough 01943 * space. That is *probably* what is desired, but I can imagine a 01944 * situation where our caller can do a graceful recovery if there is not 01945 * enough memory. If that ever becomes needed, we should just return 01946 * NULL here to allow our caller that flexibility. On the other hand, 01947 * by fatal-erroring-out here, we relieve our caller of the burden of 01948 * checking if memory was successfully allocated -- thus making our 01949 * caller less cluttered / easier to understand. 01950 * 01951 * ==================================================================== 01952 */ 01953 01954 MEM_PTR 01955 Realloc_Clear ( MEM_PTR ptr, INT32 new_size, INT32 old_size ) 01956 { 01957 MEM_PTR result = (MEM_PTR) realloc ( ptr, new_size ); 01958 01959 if ( result == NULL ) 01960 ErrMsg ( EC_No_Mem, "Realloc_Clear" ); 01961 01962 /* must clear the new portion of the allocated space */ 01963 if ( new_size > old_size ) { 01964 MEM_PTR start_of_new = (MEM_PTR) ( ((char *) result) + old_size ); 01965 INT32 num_added_bytes = new_size - old_size; 01966 memset ( start_of_new, '\0', num_added_bytes ); 01967 } 01968 01969 return result; 01970 } 01971 01972 /* ==================================================================== 01973 * 01974 * MEM_PTR Re_Calloc ( ptr, new_nelem, elsize, old_nelem ) 01975 * 01976 * This routine is used to grow space that was initially allocated via 01977 * a call to the Unix routine 'calloc()'. 'calloc()' is passed a number 01978 * of elements and an element size, and returns a pointer to *cleared* 01979 * memory for that many elements of that size: 01980 * 01981 * MEM_PTR calloc ( UINT nelem, UINT elsize ) 01982 * 01983 * This routine takes as input a pointer that was previously allocated 01984 * by 'calloc()', the same element size, and both the new and old number 01985 * of elements. It calls 'realloc()' indirectly, via 'clear_realloc()', 01986 * to grow the space pointed to by the input 'ptr', clearing all the new 01987 * space. Note that we need to know the old number of elements so we 01988 * can determine which portion of the returned space must be cleared 01989 * (the contents of the original space must be unchanged). 01990 * 01991 * The major functionality of this routine is provided by the support 01992 * routine 'clear_realloc()' -- we could easily only provide that 01993 * interface, but this gives a calloc()-style interface to the user who 01994 * likes to use 'calloc()'. 01995 * 01996 * ==================================================================== 01997 */ 01998 01999 MEM_PTR 02000 Re_Calloc ( MEM_PTR ptr, INT32 new_nelem, INT32 elsize, INT32 old_nelem ) 02001 { 02002 return Realloc_Clear ( ptr, new_nelem * elsize, old_nelem * elsize ); 02003 }