Open64 (mfef90, whirl2f, and IR tools)  TAG: version-openad; SVN changeset: 916
memory.c
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines