home *** CD-ROM | disk | FTP | other *** search
/ BBS in a Box 15 / BBS in a box XV-2.iso / Files II / Prog / M / MacPerl 4.13 source.sit / Perl Source ƒ / Perl / icemalloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-04  |  34.6 KB  |  1,429 lines  |  [TEXT/MPS ]

  1.  
  2. /*
  3. **
  4. ** Notice.
  5. **
  6. ** This source code was written by Tim Endres. time@ice.com
  7. ** Copyright 1988-1991 © By Tim Endres. All rights reserved.
  8. ** 8840 Main Street, Whitmore Lake, MI  48189
  9. **
  10. ** You may use this source code for any purpose you can dream
  11. ** of as long as this notice is never modified nor removed.
  12. **
  13. ** Please email me any improvements that you might make. Any
  14. ** reasonable form of diff (compare) on the files changes will
  15. ** do nicely. You can mail "time@ice.com". Thank you.
  16. **
  17. ** BTW: In case it is not obvious, do not #define DOCUMENTATION ;)
  18. **
  19. * $Log: icemalloc.c,v $
  20.  * Revision 1.3  1994/05/04  02:10:46  neeri
  21.  * Rewrote memory management.
  22.  *
  23.  * Revision 1.2  1994/04/01  17:51:22  neeri
  24.  * Bucket allocator works.
  25.  *
  26. */
  27.  
  28.  
  29. #include <types.h>
  30. #include <memory.h>
  31.  
  32. #include "icemalloc.h"
  33.  
  34. #define mNEWPTR(size)            ( NewPtr ( (size) ) )
  35. #define mDISPOSPTR(ptr)            ( DisposPtr ( (ptr) ) )
  36.  
  37. #define DEBUG
  38.  
  39. #ifdef DOCUMENTATION
  40.  
  41.     malloc() will allocate "size" bytes from the default malloc pool.
  42.     
  43. #endif
  44.  
  45. char    *
  46. malloc ( size )
  47. u_long    size;
  48. {
  49. _mem_pool_ptr    pool;
  50.  
  51.     pool = _default_mem_pool;
  52.     if (pool == (_mem_pool_ptr)0)
  53.         return (char *)0;
  54.     
  55.     return _pool_malloc(pool, size);
  56.     }
  57.  
  58.  
  59. #ifdef DOCUMENTATION
  60.  
  61.     free() will free the memory occupied by the "ptr" allocated by malloc().
  62.     
  63. #endif
  64.  
  65. void free ( void * ptr )
  66. {
  67.     _pool_free((char *) ptr);
  68.     }
  69.  
  70. #ifdef DOCUMENTATION
  71.  
  72.     MN 15May93 realloc() tries to change the size of the memory pointed 
  73.     to by "ptr". No optimizations are attempted.
  74.     
  75. #endif
  76.  
  77. void *
  78. realloc ( old, size )
  79. void *     old;
  80. u_long    size;
  81. {
  82.     void *            nu;
  83.     
  84.     nu = malloc(size);
  85.     
  86.     if (!old || !nu)
  87.         return nu;
  88.     
  89.     memcpy(nu, old, size);
  90.     
  91.     free(old);
  92.     
  93.     return nu;
  94. }
  95.  
  96. void
  97. fastzero(ptr, size)
  98. register char *ptr;
  99. register u_long size;
  100. {
  101.     int     portiuncula;
  102.     int     longs;
  103.     int     max;
  104.     long    *lptr;
  105.  
  106.     longs = size >> 2;
  107.     lptr  = (long *) ptr;
  108.     max   = 8;
  109.     
  110.     switch (longs) {
  111.     default:
  112.         *lptr++ = 0;
  113.     case 7:
  114.         *lptr++ = 0;
  115.     case 6:
  116.         *lptr++ = 0;
  117.     case 5:
  118.         *lptr++ = 0;
  119.     case 4:
  120.         *lptr++ = 0;
  121.     case 3:
  122.         *lptr++ = 0;
  123.     case 2:
  124.         *lptr++ = 0;
  125.     case 1:
  126.         *lptr++ = 0;
  127.     case 0:
  128.         break;
  129.     }
  130.     
  131.     for (longs -= 8; longs > 0; longs -= portiuncula) {
  132.         portiuncula = longs > max ? max : longs;
  133.         BlockMove((Ptr)(lptr - portiuncula), (Ptr) lptr, portiuncula*4);
  134.         max += portiuncula;
  135.         lptr += portiuncula;
  136.     }
  137. }
  138.  
  139. #ifdef DOCUMENTATION
  140.  
  141.     set_default_pool() - given a pool id, this routine will make it the default
  142.     pool from which malloc() allocates memory.
  143.     
  144. #endif
  145.  
  146.  
  147. int set_default_pool ( id )
  148. int        id;
  149. {
  150. _mem_pool_ptr    pool, last;
  151.  
  152.     if (_default_mem_pool->id == id)
  153.         return 0;
  154.     
  155.     last = _default_mem_pool;
  156.     pool = _default_mem_pool->next;
  157.     for ( ; pool != (_mem_pool_ptr)0 ; pool = pool->next) {
  158.         if (pool->id == id) {
  159.             last->next = pool->next;
  160.             pool->next = _default_mem_pool;
  161.             _default_mem_pool = pool;
  162.             return 0;
  163.             }
  164.         }
  165.     
  166.     return -1;
  167.     }
  168.  
  169.  
  170. #ifdef DOCUMENTATION
  171.  
  172.     new_malloc_pool() creates a new pool from which memory can be malloc()-ed.
  173.     
  174. #endif
  175.  
  176. _mem_pool_ptr
  177. new_malloc_pool ( id, pref_blk_size )
  178. int        id;
  179. u_long    pref_blk_size;
  180. {
  181. _mem_pool_ptr    new_pool;
  182.  
  183.     new_pool = find_pool(id);
  184.     if (new_pool != NULL)            /* ? Is this the best choice? Its not ID-able */
  185.         return new_pool;
  186.  
  187.     new_pool = (_mem_pool_ptr) mNEWPTR( sizeof(_mem_pool) );
  188.     if (new_pool == (_mem_pool_ptr)0)
  189.         return new_pool;
  190.     
  191.     new_pool->id = id;                            /* The pool's ID. */
  192.     new_pool->pref_blk_size = pref_blk_size;    /* The preferred size of new blks. */
  193.     new_pool->blk_list = NULL;                    /* The list of blocks in the pool. */
  194.     new_pool->blk_16 = nil;
  195.     new_pool->blk_32 = nil;
  196.     new_pool->blk_64 = nil;
  197.     new_pool->free_16 = nil;
  198.     new_pool->free_32 = nil;
  199.     new_pool->free_64 = nil;
  200.     
  201.     /* The next two lines insert right after the default, so we don't change it. */
  202.     new_pool->next = _mem_pool_forest->next;
  203.     _mem_pool_forest->next = new_pool;
  204.  
  205. #ifdef _PM_STATS
  206.     new_pool->total_memory = 0;            /* The total allocated memory by this pool */
  207.     new_pool->total_storage = 0;        /* The total malloc-able storage in this pool */
  208.     new_pool->total_malloc = 0;            /* The total malloc-ed storage not freed. */
  209.     new_pool->max_blk_size = 0;            /* The maximum block size allocated. */
  210.     new_pool->ave_req_size = 0.0;        /* The ave allocated request size */
  211.     new_pool->ave_req_total = 0;        /* The total requests in the average. */
  212.     new_pool->ave_blk_size = 0.0;        /* The ave sallocated blk size */
  213.     new_pool->ave_blk_total = 0;        /* The total blks in the average. */
  214. #endif
  215.  
  216.     return new_pool;
  217.     }
  218.  
  219.  
  220. #ifdef DOCUMENTATION
  221.  
  222.     find_pool() will find the pool with the given "id" and return its pointer.
  223.     
  224. #endif
  225.  
  226. _mem_pool_ptr
  227. find_pool ( id )
  228. int        id;
  229. {
  230. _mem_pool_ptr    pool;
  231.  
  232.     for (pool = _mem_pool_forest ; pool != (_mem_pool_ptr)0 ; pool = pool->next) {
  233.         if (pool->id == id)
  234.             break;
  235.         }
  236.         
  237.     return pool;
  238.     }
  239.  
  240.  
  241. #ifdef DOCUMENTATION
  242.  
  243.     free_pool_memory() this will free and *release* all memory occupied by the
  244.     pool but not free the pool, letting you allocate some more.
  245.     
  246. #endif
  247.  
  248. free_pool_memory ( id )
  249. int        id;
  250. {
  251. _mem_pool_ptr        pool;
  252. _mem_blk_ptr        blk, nextblk;
  253. _mem_bucket_ptr    bucket;
  254.  
  255.     pool = find_pool(id);
  256.     if (pool == NULL)
  257.         return -1;
  258.     
  259.     /* The buckets themselves are always allocated from the pool and therefore
  260.        don't need to be disposed explicitely.
  261.     */
  262.     
  263.     for ( bucket = pool->blk_16; bucket; bucket = bucket->next)
  264.         mDISPOSPTR((Ptr) bucket->memory);
  265.     for ( bucket = pool->blk_32; bucket; bucket = bucket->next)
  266.         mDISPOSPTR((Ptr) bucket->memory);
  267.     for ( bucket = pool->blk_64; bucket; bucket = bucket->next)
  268.         mDISPOSPTR((Ptr) bucket->memory);
  269.     
  270.     pool->blk_16 = nil;
  271.     pool->blk_32 = nil;
  272.     pool->blk_64 = nil;
  273.     pool->free_16 = nil;
  274.     pool->free_32 = nil;
  275.     pool->free_64 = nil;
  276.     
  277.     for ( blk = pool->blk_list ; blk != (_mem_blk_ptr)0 ; ) {
  278.         nextblk = blk->next;
  279.         DPRINTF(3, ("pool_find_free_blk() Freeing Block x%lx from pool #%d!\n",
  280.                         blk, blk->pool->id));
  281. #ifdef _PM_STATS
  282.         pool->total_memory -= sizeof(_mem_blk) + blk->size;
  283.         pool->total_storage -= blk->size;
  284. #endif
  285.         mDISPOSPTR((Ptr)blk->memory);
  286.         mDISPOSPTR((Ptr)blk);
  287.  
  288.         blk = nextblk;
  289.         }
  290.  
  291.     pool->blk_list = NULL;
  292.     
  293.     return 0;
  294.     }
  295.  
  296.  
  297. #ifdef DOCUMENTATION
  298.  
  299.     free_pool() will free the pool's memory *and* free the pool (removing
  300.     it from the pool list) releasing all memory back to the heap.
  301.     
  302. #endif
  303.  
  304. free_pool ( id )
  305. int        id;
  306. {
  307. _mem_pool_ptr    pool;
  308.  
  309.     if (free_pool_memory(id) == -1)
  310.         return -1;
  311.     
  312.     pool = find_pool(id);
  313.     if (pool == NULL)
  314.         return -1;
  315.     
  316.     mDISPOSPTR((Ptr)pool);
  317.     
  318.     return 0;
  319.     }
  320.  
  321.  
  322. #ifdef DOCUMENTATION
  323.  
  324.     _pool_malloc() does the low level malloc() work in a specified pool.
  325.     
  326. #endif
  327.  
  328. char * _bucket_malloc();
  329. char * _blk_malloc();
  330.  
  331. char    *
  332. _pool_malloc(pool, size)
  333. _mem_pool_ptr    pool;
  334. u_long            size;
  335. {
  336.     if (size < 33)
  337.         if (size < 17)
  338.             return _bucket_malloc(pool, 16, &pool->free_16, &pool->blk_16, 4);
  339.         else
  340.             return _bucket_malloc(pool, 32, &pool->free_32, &pool->blk_32, 5);
  341.     else 
  342.         if (size < 65)
  343.             return _bucket_malloc(pool, 64, &pool->free_64, &pool->blk_64, 6);
  344.         else
  345.             return _blk_malloc(pool, size);
  346. }
  347.  
  348. char     *
  349. _bucket_malloc(pool, size, free, buckets, shift)
  350. _mem_pool_ptr        pool;
  351. u_long                 size;
  352. _mem_bucket_ptr *    free;
  353. _mem_bucket_ptr *    buckets;
  354. short                    shift;
  355. {
  356.     _mem_bucket_ptr    bucket;
  357.     char *                 mem;
  358.     
  359.     if (!(bucket = *free)) {
  360.         for (bucket = *buckets; bucket && !bucket->free_count; bucket = bucket->next);
  361.     
  362.         if (!bucket) {
  363.             int count;
  364.             int max                = pool->pref_blk_size >> shift;
  365.             char * next;
  366.             
  367.             bucket                = (_mem_bucket_ptr) _blk_malloc(pool, sizeof(_mem_bucket));
  368.             bucket->prev        = (_mem_bucket_ptr) buckets;
  369.             bucket->next         = *buckets;
  370.             *buckets             = bucket;
  371.             bucket->pool         = pool;
  372.             bucket->memory     = mem = mNEWPTR(pool->pref_blk_size);
  373.             bucket->max_count    = max;
  374.             bucket->free_count= max;
  375.             
  376.             *(char **) mem = nil;
  377.             for (count = 1; count++ < max; mem = next) {
  378.                 next = mem + size;
  379.                 *(char **) next = mem;
  380.             }
  381.             bucket->free        = next;
  382.         }
  383.         *free = bucket;
  384.     }
  385.     mem                 = bucket->free;
  386.     bucket->free     = *(char **) mem;
  387.     if (!--bucket->free_count)
  388.         *free = nil;
  389.  
  390.     fastzero(mem, size);
  391.     
  392.     return mem;
  393. }
  394.  
  395. char    *
  396. _blk_malloc(pool, size)
  397. _mem_pool_ptr    pool;
  398. u_long            size;
  399. {
  400. _mem_blk_ptr        blk;
  401. _mem_ptr_hdr_ptr    hdr = (_mem_ptr_hdr_ptr)0, freehdr;
  402. u_long                freesize, size_req;
  403. char                *ptr = (char *)0;
  404.  
  405.     DPRINTF(5, ("_pool_malloc() request of %ld bytes in pool #%d [x%lx]\n",
  406.                 size, pool->id, pool));
  407.         
  408.     size_req = (size < _PM_MIN_ALLOC_SIZE) ? _PM_MIN_ALLOC_SIZE : size;
  409.     size_req = INT_ALIGN(size_req, ALIGNMENT);
  410.  
  411. #ifdef _PM_STATS
  412.     pool->ave_req_size = ( ( (pool->ave_req_size * (float)pool->ave_req_total) + (float)size_req )
  413.                             / (float)(pool->ave_req_total + 1) );
  414.     pool->ave_req_total++;
  415. #endif
  416.  
  417.     blk = pool->blk_list;
  418.     if (blk == NULL) {
  419.         /* No blocks in pool, allocate one... */
  420.         blk = _pool_new_blk(pool, size_req);
  421.         }
  422.     else {
  423.         blk = _pool_find_free_blk(pool, size_req, &hdr);
  424.  
  425.         if (blk == (_mem_blk_ptr)0 || hdr == (_mem_ptr_hdr_ptr)0) {
  426.             /* No blocks that can support this size... */
  427.             blk = _pool_new_blk(pool, size_req);
  428.             }
  429.         else
  430.             DPRINTF(5, ("_pool_malloc() found free: blk x%lx hdr x%lx\n",
  431.                         blk, hdr));
  432.         }
  433.     
  434.     if (blk != (_mem_blk_ptr)0) {
  435.         /* Determine the pointer's location, establish, return. */
  436.         if (hdr == (_mem_ptr_hdr_ptr)0) {
  437.             hdr = (_mem_ptr_hdr_ptr) blk->memory;
  438.             DPRINTF(5, ("_pool_malloc() header of new blk blk->memory x%lx\n", blk->memory));
  439.             }
  440.         
  441.         DPRINTF(5, ("_pool_malloc() free hdr x%lx size %ld\n", hdr, GET_PTR_SIZE(hdr)));
  442.         if (hdr != (_mem_ptr_hdr_ptr)0) {
  443.             ptr = (char *)hdr + sizeof(_mem_ptr_hdr);
  444.             
  445.             if (size_req < GET_PTR_SIZE(hdr)) {
  446.                 /* Split this free block... */
  447.                 DPRINTF(5, ("_pool_malloc() split hdr x%lx into %ld used and %ld free\n",
  448.                             hdr, size_req, GET_PTR_SIZE(hdr) - (size_req + sizeof(_mem_ptr_hdr))));
  449.  
  450.                 freehdr = (_mem_ptr_hdr_ptr)
  451.                             ( (char *)hdr + sizeof(_mem_ptr_hdr) + size_req );
  452.                 freesize = GET_PTR_SIZE(hdr) - (sizeof(_mem_ptr_hdr) + size_req);
  453.                 fastzero(freehdr, sizeof(_mem_ptr_hdr));
  454.                 SET_PTR_FREE(freehdr);
  455.                 SET_PTR_SIZE(freehdr, freesize);
  456.                 blk->max_free -= sizeof(_mem_ptr_hdr);
  457.                 }
  458.  
  459. #ifdef _PM_STATS    
  460.             pool->total_malloc += size_req;
  461. #endif
  462.  
  463.             blk->max_free -= size_req;
  464.             SET_PTR_USED(hdr);
  465.             SET_PTR_SIZE(hdr, size_req);
  466.             fastzero(ptr, size_req);        /* Programmer's expect malloc() to zero. */
  467.             }
  468.         else {
  469.             /* ERROR: This should not happen!!! */
  470.             DPRINTF(1, ("ERROR: pool_malloc() could not get block's free hdr ptr\n"));
  471.             DACTION(2, { list_pool_forest(NULL); });
  472.             }
  473.         }
  474.     else {
  475.         /* ERROR, no block, no memory. */
  476.         DPRINTF(1, ("ERROR: pool_malloc() could not get a block\n"));
  477.         DACTION(2, { list_pool_forest(NULL); });
  478.         }
  479.     
  480.     DPRINTF(5, ("_pool_malloc() returning ptr x%lx\n", ptr));
  481.     return ptr;
  482.     }
  483.  
  484. #ifdef DOCUMENTATION
  485.  
  486.     _pool_free() does the low level work of a free().
  487.     
  488. #endif
  489.  
  490. _mem_bucket_ptr _pool_find_ptr_bucket();
  491.  
  492. _pool_free ( ptr )
  493. char    *ptr;
  494. {
  495. _mem_pool_ptr        pool;
  496. _mem_blk_ptr        blk;
  497. _mem_ptr_hdr_ptr    hdr, adjhdr, limit;
  498. int                    result = 0;
  499. u_long                ptr_size, new_size;
  500. _mem_bucket_ptr    bucket;
  501.  
  502.     if (ptr == (char *)0) {
  503.         /* WHOAH! NULL Pointers... */
  504.         DPRINTF(1, ("_pool_free() ptr NULL!"));
  505.         return -1;
  506.         }
  507.     
  508.     if ( ( (u_long)ptr & 1 ) != 0 ) {
  509.         /* WHOAH! ODD Pointers... */
  510.         DPRINTF(1, ("_pool_free() ptr ODD!"));
  511.         return -1;
  512.         }
  513.     
  514.     DPRINTF(5, ("_pool_free() free ptr x%lx\n", ptr));
  515.  
  516.     if (bucket = _pool_find_ptr_bucket(ptr)) {
  517.         if (
  518.             ++bucket->free_count == bucket->max_count
  519.         ) {    /* Kick the bucket */
  520.             bucket->prev->next = bucket->next;
  521.             
  522.             if (bucket->next)
  523.                 bucket->next->prev = bucket->prev;
  524.             
  525.             mDISPOSPTR(bucket->memory);
  526.             _pool_free(bucket);
  527.         } else {
  528.             *(char **) ptr = bucket->free;
  529.             bucket->free = ptr;
  530.         }
  531.         return -1;
  532.     }
  533.         
  534.     blk = _pool_find_ptr_blk(ptr);
  535.     
  536.     if (blk == (_mem_blk_ptr)0) {
  537.         /* We could not find this thing's blk! BUG!!! */
  538.         DPRINTF(1, ("ERROR: free(x%lx) could not find ptr's blk\n", ptr));
  539.         DACTION(2, { list_pool_forest(NULL); });
  540.         result = -1;
  541.         }
  542.     else {
  543.         /*
  544.         ** Now, if it is adjacent to free memory, combine.
  545.         ** NOTE: We only do this because it is SO DAMN CHEAP!!!!!
  546.         */
  547.  
  548.         /* Delay these assigns til we know ptr is good. (now) */
  549.         hdr = (_mem_ptr_hdr_ptr) ( (u_long)ptr - sizeof(_mem_ptr_hdr) );
  550.         ptr_size = GET_PTR_SIZE(hdr);
  551.  
  552.         DPRINTF(5, ("_pool_free() free hdr x%lx size %ld flags x%02x in blk x%lx\n",
  553.                     hdr, ptr_size, GET_PTR_FLAGS(hdr), blk));
  554.     
  555.         pool = blk->pool;
  556.         SET_PTR_FREE(hdr);
  557.         blk->max_free += ptr_size;
  558.         
  559.         adjhdr = (_mem_ptr_hdr_ptr)
  560.                     ( (char *)hdr + GET_PTR_SIZE(hdr) +
  561.                       sizeof(_mem_ptr_hdr) );
  562.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  563.         
  564.         if (adjhdr < limit && IS_PTR_FREE(adjhdr)) {
  565.             DPRINTF(5, ("_pool_free() merging hdr x%lx with freehdr x%lx\n", hdr, adjhdr));
  566.             
  567.             new_size =    GET_PTR_SIZE(hdr) +
  568.                         GET_PTR_SIZE(adjhdr) +
  569.                         sizeof(_mem_ptr_hdr);
  570.  
  571.             DPRINTF(5, ("_pool_free() merged hdr new_size %ld\n", new_size));
  572.             SET_PTR_SIZE(hdr, new_size);
  573.             blk->max_free += sizeof(_mem_ptr_hdr);
  574.             }    /* is adjacent free ? */
  575.         
  576. #ifdef _PM_STATS    
  577.         pool->total_malloc -= ptr_size;
  578. #endif
  579.  
  580. #ifdef _PM_DYNAMIC_FREE
  581.         if (block_is_freed(blk)) {
  582.             /* This blk is free-ed ... */
  583.             _mem_blk_ptr    tmpblk;
  584.  
  585.             if (blk == blk->pool->blk_list) {
  586.                 blk->pool->blk_list = blk->next;
  587.                 }
  588.             else {
  589.                 tmpblk = blk->pool->blk_list;
  590.                 while (tmpblk != (_mem_blk_ptr)0) {
  591.                     if (tmpblk->next == blk) {
  592.                         tmpblk->next = blk->next;
  593.                         break;
  594.                         }
  595.                     else
  596.                         tmpblk = tmpblk->next;
  597.                     }
  598.                 if (tmpblk == (_mem_blk_ptr)0)
  599.                     DPRINTF(1, ("ERROR: could not free blk x%lx from list!\n", blk));
  600.                 }
  601.             
  602.             DPRINTF(3, ("_pool_free() Freeing Block x%lx from pool #%d!\n",
  603.                         blk, blk->pool->id));
  604. #ifdef _PM_STATS
  605.             pool->total_memory -= sizeof(_mem_blk) + blk->size;
  606.             pool->total_storage -= blk->size;
  607. #endif
  608.             mDISPOSPTR((Ptr)blk->memory);
  609.             mDISPOSPTR((Ptr)blk);
  610.             }    /* if (block_is_freed(blk)) */
  611. #endif _PM_DYNAMIC_FREE
  612.  
  613.         result = 0;
  614.         }    /* else we found the block containing the ptr. */
  615.     
  616.     return result;
  617.     }
  618.  
  619. #ifdef DOCUMENTATION
  620.  
  621.     block_is_freed() determines if all memory in a given block is free.
  622.     
  623. #endif
  624.  
  625. block_is_freed(blk)
  626. _mem_blk_ptr    blk;
  627. {
  628. int            freed = 1;
  629. _mem_ptr_hdr_ptr    loophdr, limit;
  630.  
  631. /*
  632. ** This loop is not as expensive as you might think, since most of the
  633. ** time we've "merged" into few "ptrs", and in allocated cases we will
  634. ** break out of the loop almost immediately.
  635. */
  636.  
  637.     if (blk != NULL) {
  638.         loophdr = (_mem_ptr_hdr_ptr) blk->memory;
  639.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  640.         while (loophdr < limit) {
  641.             if (! IS_PTR_FREE(loophdr)) {
  642.                 freed = 0;
  643.                 break;
  644.                 }
  645.             
  646.             loophdr = (_mem_ptr_hdr_ptr)
  647.                         ((char *)loophdr + GET_PTR_SIZE(loophdr) + sizeof(_mem_ptr_hdr));
  648.             }
  649.         }
  650.     else
  651.         freed = 0;    /* ? Or is it really free? */
  652.     
  653.     return freed;
  654.     }
  655.  
  656.  
  657. #ifdef DOCUMENTATION
  658.  
  659.     _pool_new_blk() allocate a new memory block to a pool. This is called
  660.     by the low level malloc() code when new memory is needed.
  661.     
  662. #endif
  663.  
  664. _mem_blk_ptr
  665. _pool_new_blk(pool, size_req)
  666. _mem_pool_ptr    pool;
  667. u_long            size_req;    /* size required */
  668. {
  669. u_long                blk_size;
  670. _mem_blk_ptr        new_blk;
  671. _mem_ptr_hdr_ptr    hdr;
  672.  
  673.     DPRINTF(5, ("_pool_new_blk() req_size %ld pool #%d [x%lx]\n", size_req, pool->id, pool));
  674.  
  675.     /* MN 29Mar94 To avoid agonizing death from internal fragmentation, we make an 
  676.        allocation "private" if it would occupy more than about 45% of a block.
  677.     */
  678.     if ((size_req + sizeof(_mem_ptr_hdr)) > (pool->pref_blk_size*7 >> 4)) {
  679.         blk_size = size_req + sizeof(_mem_ptr_hdr);
  680. #ifdef _PM_STATS
  681.         if (blk_size > pool->max_blk_size)
  682.             pool->max_blk_size = blk_size;
  683. #endif
  684.         }
  685.     else
  686.         blk_size = pool->pref_blk_size;
  687.     
  688.     blk_size = INT_ALIGN(blk_size, ALIGNMENT);
  689.     
  690. #ifdef _PM_STATS
  691.     pool->ave_blk_size = ( ( (pool->ave_blk_size * (float)pool->ave_blk_total) + (float)blk_size )
  692.                             / (float)(pool->ave_blk_total + 1) );
  693.     pool->ave_blk_total++;
  694. #endif
  695.  
  696.     new_blk = (_mem_blk_ptr) mNEWPTR(sizeof(_mem_blk));
  697.     if (new_blk == (_mem_blk_ptr)0)
  698.         return new_blk;
  699.     
  700.     /*
  701.     ** NOTE: We assume here that mNEWPTR() gives us proper alignment.
  702.     */
  703.     new_blk->memory = (char *) mNEWPTR(blk_size);
  704. #ifdef NEVER_DEFINED
  705.     if (new_blk->memory == (char *)0) {
  706.         /* Attempt to handle the request only. */
  707.         blk_size = size_req + sizeof(_mem_ptr_hdr);
  708.         blk_size = INT_ALIGN(blk_size, ALIGNMENT);
  709.         new_blk->memory = (char *) mNEWPTR(blk_size);
  710.         }
  711. #endif
  712.     
  713.     if (new_blk->memory == (char *)0) {
  714.         mDISPOSPTR((Ptr)new_blk);
  715.         DPRINTF(10, ("_pool_new_blk(pool:x%lx, size:%ld) Out of memory.\n", pool, size_req));
  716.         return (_mem_blk_ptr)0;
  717.         }
  718.     
  719. #ifdef _PM_STATS
  720.     pool->total_memory += sizeof(_mem_blk) + blk_size;
  721.     pool->total_storage += blk_size;
  722. #endif
  723.  
  724.     new_blk->pool = pool;
  725.     new_blk->size = blk_size;
  726.     new_blk->max_free = blk_size - sizeof(_mem_ptr_hdr);
  727.     
  728.     /* Add to the block list. */
  729.     new_blk->next = pool->blk_list;
  730.     pool->blk_list = new_blk;
  731.     
  732.     hdr = (_mem_ptr_hdr_ptr) new_blk->memory;
  733.     fastzero(hdr, sizeof(_mem_ptr_hdr));
  734.     
  735.     SET_PTR_FREE(hdr);
  736.     SET_PTR_SIZE(hdr, ( blk_size - sizeof(_mem_ptr_hdr) ) );
  737.     
  738.     DPRINTF(5, ("_pool_new_blk() new blk x%lx size %ld memory x%lx pool #%d [x%lx]\n",
  739.             new_blk, new_blk->size, new_blk->memory, pool->id, pool));
  740.     return new_blk;
  741.     }
  742.     
  743.  
  744. #ifdef DOCUMENTATION
  745.  
  746.     _pool_find_free_blk() looks for a block in the pool with enough free memory
  747.     to allocate the "size_req" bytes.
  748.     
  749. #endif
  750.  
  751. _mem_blk_ptr
  752. _pool_find_free_blk(pool, size_req, hdr_ptr)
  753. _mem_pool_ptr        pool;
  754. u_long                size_req;    /* size required */
  755. _mem_ptr_hdr_ptr    *hdr_ptr;
  756. {
  757. _mem_blk_ptr        blk, use_this_blk;
  758. _mem_ptr_hdr_ptr    loophdr, limit;
  759. long                hdrsize, max_size;
  760.  
  761. #ifdef _PM_DYNAMIC_MERGING
  762. _mem_ptr_hdr_ptr    lasthdr, nexthdr, blkhdr;
  763. long                lastsize, nextsize;
  764. #endif _PM_DYNAMIC_MERGING
  765.  
  766.     blk = pool->blk_list;
  767.     max_size = 0x3FFFFFFF;
  768.     for (use_this_blk=NULL; blk != (_mem_blk_ptr)0 ; blk=blk->next) {
  769.         if (blk->max_free >= size_req) {
  770.             if (use_this_blk == NULL) {
  771.                 use_this_blk = blk;
  772.                 max_size = blk->size;
  773.                 }
  774.             else if (blk->size < max_size) {
  775.                 use_this_blk = blk;
  776.                 max_size = blk->size;
  777.                 }
  778.             }
  779.         }
  780.     
  781.     blk = use_this_blk;
  782.     if (blk != NULL) {
  783.         loophdr = (_mem_ptr_hdr_ptr) blk->memory;
  784.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  785. #ifdef _PM_DYNAMIC_MERGING
  786.         lasthdr = (_mem_ptr_hdr_ptr)0;
  787. #endif _PM_DYNAMIC_MERGING
  788.         while (loophdr < limit) {
  789.             if (IS_PTR_FREE(loophdr)) {
  790.                 hdrsize = GET_PTR_SIZE(loophdr);
  791.                 if (hdrsize >= size_req) {
  792.                     DPRINTF(5, ("pool_find_free_blk() Found blk x%lx hdr x%lx pool #%d [x%lx]\n",
  793.                                 blk, loophdr, pool->id, pool));
  794.                     
  795.                     *hdr_ptr = loophdr;
  796.                     return blk;
  797.                     }
  798.  
  799. #ifdef _PM_DYNAMIC_MERGING
  800.                 else {
  801.                     nexthdr = (_mem_ptr_hdr_ptr)
  802.                                 ( (char *)loophdr + hdrsize + sizeof(_mem_ptr_hdr) );
  803.                     if (nexthdr < limit) {
  804.                         if (IS_PTR_FREE(nexthdr)) {
  805.                             nextsize = GET_PTR_SIZE(nexthdr);
  806.                             blk->max_free += sizeof(_mem_ptr_hdr);    /* We're gonna merge... */
  807.                             if ((nextsize + hdrsize + sizeof(_mem_ptr_hdr)) >= size_req) {
  808.                                 DPRINTF(3, ("pool_find_free_blk() F-Merge blk x%lx hdr1 x%lx hdr2 x%lx \n",
  809.                                             blk, loophdr, nexthdr));
  810.                                 
  811.                                 hdrsize = nextsize + hdrsize + sizeof(_mem_ptr_hdr);
  812.                                 SET_PTR_SIZE(loophdr, hdrsize);
  813.                                 *hdr_ptr = loophdr;
  814.                                 return blk;
  815.                                 }
  816.                             else {
  817.                                 /* OK, so merge anyways... */
  818.                                 hdrsize = nextsize + hdrsize + sizeof(_mem_ptr_hdr);
  819.                                 SET_PTR_SIZE(loophdr, hdrsize);
  820.                                 }
  821.                             }
  822.                         }
  823.                     if (lasthdr != (_mem_ptr_hdr_ptr)0) {
  824.                         if (IS_PTR_FREE(lasthdr)) {
  825.                             lastsize = GET_PTR_SIZE(lasthdr);
  826.                             blk->max_free += sizeof(_mem_ptr_hdr);    /* We're gonna merge... */
  827.                             if ((lastsize + hdrsize + sizeof(_mem_ptr_hdr)) >= size_req) {
  828.                                 DPRINTF(3, ("pool_find_free_blk() R-Merge blk x%lx hdr1 x%lx hdr2 x%lx \n",
  829.                                             blk, lasthdr, loophdr));
  830.                                 
  831.                                 hdrsize = lastsize + hdrsize + sizeof(_mem_ptr_hdr);
  832.                                 SET_PTR_SIZE(lasthdr, hdrsize);
  833.                                 *hdr_ptr = lasthdr;
  834.                                 return blk;
  835.                                 }
  836.                             else {
  837.                                 /* OK, so merge anyways... */
  838.                                 hdrsize = lastsize + hdrsize + sizeof(_mem_ptr_hdr);
  839.                                 SET_PTR_SIZE(lasthdr, hdrsize);
  840.                                 }
  841.                             loophdr = lasthdr;
  842.                             lasthdr = (_mem_ptr_hdr_ptr)0;
  843.                             }
  844.                         }
  845. #ifdef _PM_DYNAMIC_FREE
  846.                     blkhdr = (_mem_ptr_hdr_ptr)blk->memory;
  847.                     if (IS_PTR_FREE(blkhdr)) {
  848.                         if ((GET_PTR_SIZE(blkhdr) + sizeof(_mem_ptr_hdr)) == blk->size) {
  849.                             /* This blk is free-ed ... */
  850.                             
  851.                             _mem_blk_ptr    tmpblk, next;
  852.             
  853.                             if (blk == blk->pool->blk_list) {
  854.                                 blk->pool->blk_list = next = blk->next;
  855.                                 }
  856.                             else {
  857.                                 tmpblk = blk->pool->blk_list;
  858.                                 while (tmpblk != (_mem_blk_ptr)0) {
  859.                                     if (tmpblk->next == blk) {
  860.                                         tmpblk->next = next = blk->next;
  861.                                         break;
  862.                                         }
  863.                                     else
  864.                                         tmpblk = tmpblk->next;
  865.                                     }
  866.                                 if (tmpblk == (_mem_blk_ptr)0)
  867.                                     DPRINTF(1, ("pool_find_free_blk() ERROR: could not free blk x%lx from list!\n", blk));
  868.                                 }
  869.                             
  870.                             DPRINTF(3, ("pool_find_free_blk() Freeing Block x%lx from pool #%d!\n",
  871.                                         blk, blk->pool->id));
  872. #ifdef _PM_STATS
  873.                             pool->total_memory -= sizeof(_mem_blk) + blk->size;
  874.                             pool->total_storage -= blk->size;
  875. #endif
  876.                             mDISPOSPTR((Ptr)blk->memory);
  877.                             mDISPOSPTR((Ptr)blk);
  878.                             blk = next;
  879.                             break;    /* The while (hdr) loop, into while (blk) loop */
  880.                             }
  881.                         }    /* if (IS_PTR_FREE(blkhdr)) */
  882. #endif _PM_DYNAMIC_FREE
  883.  
  884.                     }
  885. #endif _PM_DYNAMIC_MERGING
  886.  
  887.                 }
  888. #ifdef _PM_DYNAMIC_MERGING
  889.             lasthdr = loophdr;
  890. #endif _PM_DYNAMIC_MERGING
  891.             loophdr = (_mem_ptr_hdr_ptr)
  892.                         ((char *)loophdr + GET_PTR_SIZE(loophdr) + sizeof(_mem_ptr_hdr));
  893.             }
  894.         }
  895.     
  896.     *hdr_ptr = (_mem_ptr_hdr_ptr)0;
  897.     return blk;
  898.     }
  899.     
  900.  
  901. #ifdef DOCUMENTATION
  902.  
  903.     _pool_find_ptr_blk() finds the block containing this pointer in "ptr".
  904.     
  905. #endif
  906.  
  907. _mem_bucket_ptr 
  908. _pool_find_ptr_bucket(ptr)
  909. char *                    ptr;
  910. {
  911. _mem_pool_ptr        pool;
  912. _mem_bucket_ptr    bucket;
  913.  
  914.     /*
  915.     ** Since the default list is stored at the front of the forest list,
  916.     ** we inherently search the default forest first. Nice.
  917.     */
  918.     pool = _mem_pool_forest;
  919.     
  920.     while (pool != (_mem_pool_ptr)0) {
  921.         if (bucket = pool->free_16)
  922.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size) {
  923.                 if (bucket->free_count+1 == bucket->max_count)
  924.                     pool->free_16 = nil;
  925.                 return bucket;
  926.             }
  927.         if (bucket = pool->free_32)
  928.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)    {
  929.                 if (bucket->free_count+1 == bucket->max_count)
  930.                     pool->free_32 = nil;
  931.                 return bucket;
  932.             }
  933.         if (bucket = pool->free_64)
  934.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size) {
  935.                 if (bucket->free_count+1 == bucket->max_count)
  936.                     pool->free_64 = nil;
  937.                 return bucket;
  938.             }
  939.         
  940.         for (bucket = pool->blk_16; bucket; bucket = bucket->next)
  941.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)
  942.                 return bucket;
  943.         for (bucket = pool->blk_32; bucket; bucket = bucket->next)
  944.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)
  945.                 return bucket;
  946.         for (bucket = pool->blk_64; bucket; bucket = bucket->next)
  947.             if (ptr > bucket->memory && ptr < bucket->memory + pool->pref_blk_size)
  948.                 return bucket;
  949.         
  950.         pool = pool->next;
  951.     }
  952.     
  953.     return (_mem_bucket_ptr)0;
  954. }
  955.  
  956. _mem_blk_ptr
  957. _pool_find_ptr_blk(ptr)
  958. char    *ptr;
  959. {
  960. _mem_pool_ptr    pool;
  961. _mem_blk_ptr    blk;
  962.  
  963.     /*
  964.     ** Since the default list is stored at the front of the forest list,
  965.     ** we inherently search the default forest first. Nice.
  966.     */
  967.     pool = _mem_pool_forest;
  968.     
  969.     while (pool != (_mem_pool_ptr)0) {
  970.         blk = pool->blk_list;
  971.         
  972.         while (blk != (_mem_blk_ptr)0) {
  973.             if ( ( ptr >= blk->memory ) &&
  974.                  ( ptr <= ((char *)blk->memory + blk->size) ) )
  975.                 return blk;
  976.             else
  977.                 blk = blk->next;
  978.             }
  979.         
  980.         pool = pool->next;
  981.         }
  982.     
  983.     return (_mem_blk_ptr)0;
  984.     }
  985.  
  986.  
  987. #ifdef DOCUMENTATION
  988.  
  989.     merge_free_list() runs the routine to merge and "release" any free-ed
  990.     blocks back into the heap.
  991.     
  992. #endif
  993.  
  994. merge_free_list()
  995. {
  996.     return _pool_free_list_merge(_default_mem_pool);
  997.     }
  998.  
  999.  
  1000. #ifdef DOCUMENTATION
  1001.  
  1002.     _pool_free_list_merge() will merge and "release" any free-ed blocks
  1003.     back into the heap.
  1004.     
  1005. #endif
  1006.  
  1007. _pool_free_list_merge(pool)
  1008. _mem_pool_ptr        pool;
  1009. {
  1010. _mem_blk_ptr        blk, nextblk;
  1011. _mem_ptr_hdr_ptr    loophdr, limit, nexthdr, blkhdr;
  1012. int                    result = 0;
  1013. long                hdrsize, nextsize;
  1014.  
  1015.     blk = pool->blk_list;
  1016.     while (blk != (_mem_blk_ptr)0) {
  1017.         loophdr = blkhdr = (_mem_ptr_hdr_ptr)blk->memory;
  1018.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1019.         while (loophdr < limit) {
  1020.             if (IS_PTR_FREE(loophdr)) {
  1021.                 hdrsize = GET_PTR_SIZE(loophdr);
  1022.                 nexthdr = (_mem_ptr_hdr_ptr)
  1023.                             ( (char *)loophdr + hdrsize + sizeof(_mem_ptr_hdr) );
  1024.                 /* Now loop and merge free ptr's til used one is hit... */
  1025.                 while (nexthdr < limit) {
  1026.                     if (IS_PTR_FREE(nexthdr)) {
  1027.                         nextsize = GET_PTR_SIZE(nexthdr);
  1028.                         blk->max_free += sizeof(_mem_ptr_hdr);    /* We're gonna merge... */
  1029.                         hdrsize = nextsize + hdrsize + sizeof(_mem_ptr_hdr);
  1030.                         SET_PTR_SIZE(loophdr, hdrsize);
  1031.                         nexthdr = (_mem_ptr_hdr_ptr)
  1032.                                     ( (char *)loophdr + hdrsize + sizeof(_mem_ptr_hdr) );
  1033.                         }
  1034.                     else
  1035.                         break;
  1036.                     }
  1037.                 }
  1038.             
  1039.             loophdr = (_mem_ptr_hdr_ptr)
  1040.                         ((char *)loophdr + GET_PTR_SIZE(loophdr) + sizeof(_mem_ptr_hdr));
  1041.             }
  1042.  
  1043.         /* Get next block now, so _PM_DYNAMIC_FREE can modify blk as desired */
  1044.         nextblk = blk->next;
  1045.  
  1046. #ifdef _PM_DYNAMIC_FREE
  1047.         if (IS_PTR_FREE(blkhdr)) {
  1048.             if ((GET_PTR_SIZE(blkhdr) + sizeof(_mem_ptr_hdr)) == blk->size) {
  1049.                 /* This blk is free-ed ... */
  1050.                 _mem_blk_ptr    tmpblk;
  1051.  
  1052.                 if (blk == blk->pool->blk_list) {
  1053.                     blk->pool->blk_list = blk->next;
  1054.                     }
  1055.                 else {
  1056.                     tmpblk = blk->pool->blk_list;
  1057.                     while (tmpblk != (_mem_blk_ptr)0) {
  1058.                         if (tmpblk->next == blk) {
  1059.                             tmpblk->next = blk->next;
  1060.                             break;
  1061.                             }
  1062.                         else
  1063.                             tmpblk = tmpblk->next;
  1064.                         }
  1065.                     if (tmpblk == (_mem_blk_ptr)0)
  1066.                         DPRINTF(1, ("pool_find_free_blk() ERROR: could not free blk x%lx from list!\n", blk));
  1067.                     }
  1068.                 
  1069.                 DPRINTF(3, ("pool_find_free_blk() Freeing Block x%lx from pool #%d!\n",
  1070.                             blk, blk->pool->id));
  1071. #ifdef _PM_STATS
  1072.                 pool->total_memory -= sizeof(_mem_blk) + blk->size;
  1073.                 pool->total_storage -= blk->size;
  1074. #endif
  1075.                 result += blk->size + sizeof(_mem_blk);
  1076.                 mDISPOSPTR((Ptr)blk->memory);
  1077.                 mDISPOSPTR((Ptr)blk);
  1078.                 }
  1079.             
  1080.             }    /* if (IS_PTR_FREE(blkhdr)) */
  1081. #endif _PM_DYNAMIC_FREE
  1082.         
  1083.         blk = nextblk;
  1084.         }
  1085.     
  1086.     return result;
  1087.     }
  1088.     
  1089.  
  1090. #ifdef DOCUMENTATION
  1091.  
  1092.     get_malloc_stats() return several statistics about the default heap.
  1093.     
  1094. #endif
  1095.  
  1096. get_malloc_stats(total_memory, total_free, total_malloc)
  1097. long        *total_memory;
  1098. long        *total_free;
  1099. long        *total_malloc;
  1100. {
  1101. _mem_pool_ptr        pool;
  1102. _mem_blk_ptr        blk;
  1103. _mem_ptr_hdr_ptr    hdr, limit;
  1104. u_long                total_size, used_space, free_space;
  1105. u_long                ptr_size;
  1106.  
  1107.     pool = _default_mem_pool;
  1108.     blk = pool->blk_list;
  1109.     total_size = used_space = free_space = 0;
  1110.     for ( ; blk != (_mem_blk_ptr)0; ) {
  1111.         hdr = (_mem_ptr_hdr_ptr) blk->memory;
  1112.         limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1113.         total_size += blk->size;
  1114.         for ( ; hdr && hdr < limit; ) {
  1115.             ptr_size = GET_PTR_SIZE(hdr);
  1116.             if (IS_PTR_FREE(hdr))
  1117.                 free_space += ptr_size;
  1118.             else
  1119.                 used_space += ptr_size;
  1120.             
  1121.             hdr = (_mem_ptr_hdr_ptr)
  1122.                     ( (char *)hdr + GET_PTR_SIZE(hdr) + sizeof(_mem_ptr_hdr) );
  1123.             }
  1124.         
  1125.         blk = blk->next;
  1126.         }
  1127.     
  1128.     *total_memory = total_size;
  1129.     *total_free = free_space;
  1130.     *total_malloc = used_space;
  1131.     }
  1132.  
  1133. #ifdef DEBUG
  1134.  
  1135. #include <stdio.h>
  1136.  
  1137. char    temp_str[512];
  1138.  
  1139. list_all_pool_stats(file)
  1140. FILE    *file;
  1141. {
  1142. _mem_pool_ptr        pool;
  1143.  
  1144.     pool = _mem_pool_forest;
  1145.     
  1146.     while (pool != (_mem_pool_ptr)0) {
  1147.         
  1148.         list_pool_stats(file, pool);
  1149.  
  1150.         pool = pool->next;
  1151.         }
  1152.     
  1153.     }
  1154.  
  1155.  
  1156. list_pool_stats(file, pool)
  1157. FILE    *file;
  1158. _mem_pool_ptr        pool;
  1159. {
  1160. _mem_blk_ptr        blk;
  1161. _mem_ptr_hdr_ptr    hdr, limit;
  1162. int                    i, j;
  1163. int                    num_used_hdrs, num_free_hdrs;
  1164. u_long                used_hdr_space, free_hdr_space;
  1165. u_long                ptr_size, max_free_size, max_used_size;
  1166. float                ave_used_size, ave_free_size, frag_ratio;
  1167.  
  1168.     if (file == (FILE *)0) {
  1169.         file = stdout;
  1170.         }
  1171.     
  1172.     fprintf(file, "POOL STATISTICS FOR ID#%d @ x%lx blk_list x%lx pref_blk_size %ld\n",
  1173.             pool->id, pool, pool->blk_list, pool->pref_blk_size);
  1174.  
  1175. #ifdef _PM_STATS
  1176.     fprintf(file, "\tMEMORY: Total memory %ld Total ptr space %ld Currently malloc-ed %ld\n",
  1177.             pool->total_memory, pool->total_storage, pool->total_malloc);
  1178.     fprintf(file, "\tREQUESTS: Ave req size %f Total reqs %ld Total size reqs %f\n",
  1179.             pool->ave_req_size, pool->ave_req_total, 
  1180.             (float) (pool->ave_req_size * (float)pool->ave_req_total));
  1181.     fprintf(file, "\tBLOCKS: Max block size %ld Ave block size %f\n",
  1182.             pool->max_blk_size, pool->ave_blk_size);
  1183.     fprintf(file, "\tBLOCKS: Total ave blocks %ld Total ave size %f\n",
  1184.             pool->ave_blk_total,(float) (pool->ave_blk_size * (float)pool->ave_blk_total));
  1185. #endif
  1186.  
  1187.         fprintf(file, "POOL BLOCK STATISTICS:\n");
  1188.         
  1189.         blk = pool->blk_list;
  1190.         for (i=0; blk != (_mem_blk_ptr)0; i++) {
  1191.             hdr = (_mem_ptr_hdr_ptr) blk->memory;
  1192.             limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1193.             num_used_hdrs = num_free_hdrs = 0;
  1194.             used_hdr_space = free_hdr_space = 0;
  1195.             max_free_size = max_used_size = 0;
  1196.             for (j=0; hdr && hdr < limit; j++) {
  1197.                 ptr_size = GET_PTR_SIZE(hdr);
  1198.                 if (IS_PTR_FREE(hdr)) {
  1199.                     num_free_hdrs++;
  1200.                     free_hdr_space += ptr_size;
  1201.                     if (ptr_size > max_free_size)
  1202.                         max_free_size = ptr_size;
  1203.                     }
  1204.                 else {
  1205.                     num_used_hdrs++;
  1206.                     used_hdr_space += ptr_size;
  1207.                     if (ptr_size > max_used_size)
  1208.                         max_used_size = ptr_size;
  1209.                     }
  1210.                 
  1211.                 hdr = (_mem_ptr_hdr_ptr)
  1212.                         ( (char *)hdr + GET_PTR_SIZE(hdr) + sizeof(_mem_ptr_hdr) );
  1213.                 }
  1214.             
  1215.             if (num_free_hdrs == 0)
  1216.                 ave_free_size = (float)0.0;
  1217.             else
  1218.                 ave_free_size = (float)free_hdr_space / (float)num_free_hdrs;
  1219.             
  1220.             if (num_used_hdrs == 0)
  1221.                 ave_used_size = (float)0.0;
  1222.             else
  1223.                 ave_used_size = (float)used_hdr_space / (float)num_used_hdrs;
  1224.             
  1225.             if (num_used_hdrs == 0) {
  1226.                 frag_ratio = (float)num_free_hdrs / 2.0;
  1227.                 }
  1228.             else {
  1229.                 frag_ratio = (float)num_free_hdrs / (float)num_used_hdrs;
  1230.                 }
  1231.             
  1232.             fprintf(file, "\tBLOCK #%-4d Fragmentation Ratio %5.2f\n", i, frag_ratio);
  1233.             fprintf(file, "\t      #%-4d    Block Size %ld Ptr x%lx MaxFree %ld\n",
  1234.                     i, blk->size, blk->memory, blk->max_free);
  1235.             fprintf(file, "\t      #%-4d    Number free ptrs %d Number used ptrs %d\n",
  1236.                     i, num_free_hdrs, num_used_hdrs);
  1237.             fprintf(file, "\t      #%-4d    Free space %ld Used space %ld\n",
  1238.                     i, free_hdr_space, used_hdr_space);
  1239.             fprintf(file, "\t      #%-4d    Max free ptr %ld Max used ptr %ld\n",
  1240.                     i, max_free_size, max_used_size);
  1241.             fprintf(file, "\t      #%-4d    Ave free ptr size %5.1f Ave used ptr size %5.1f\n",
  1242.                     i, ave_free_size, ave_used_size);
  1243.  
  1244.             blk = blk->next;
  1245.             }
  1246.     }
  1247.  
  1248.  
  1249. list_pool_forest(file, with_data)
  1250. FILE    *file;
  1251. int        with_data;
  1252. {
  1253. _mem_pool_ptr        pool;
  1254. _mem_blk_ptr        blk;
  1255. _mem_ptr_hdr_ptr    hdr, limit;
  1256. int                    i, j;
  1257. extern char            temp_str[];
  1258.  
  1259.     if (file == (FILE *)0) {
  1260.         file = stdout;
  1261.         }
  1262.     
  1263.     pool = _mem_pool_forest;
  1264.     while (pool != (_mem_pool_ptr)0) {
  1265.         
  1266.         list_pool_stats(file, pool);
  1267.         
  1268.         blk = pool->blk_list;
  1269.         for (i=0; blk != (_mem_blk_ptr)0; i++) {
  1270.             fprintf(file, "   BLK #%05d ; @ x%lx ; blk_size %ld ; memory x%lx ; max_free %ld\n",
  1271.                     i, blk, blk->size, blk->memory, blk->max_free);
  1272.             fprintf(file, "   BLK          pool x%lx ; next blk x%lx\n", blk->pool, blk->next);
  1273.             
  1274.             hdr = (_mem_ptr_hdr_ptr) blk->memory;
  1275.             limit = (_mem_ptr_hdr_ptr) ((char *)blk->memory + blk->size);
  1276.             for (j=0; hdr && hdr < limit; j++) {
  1277.                 sprintf(temp_str, "      PTR #%d ; hdr x%lx ; nxt x%08lx ; size %ld ; flgs x%02x",
  1278.                         j, hdr, hdr->size, GET_PTR_SIZE(hdr), GET_PTR_FLAGS(hdr));
  1279.                 if (with_data)
  1280.                     hex_dump(file, temp_str,
  1281.                             (char *)((char *)hdr + sizeof(_mem_ptr_hdr)),
  1282.                             GET_PTR_SIZE(hdr));
  1283.                 else
  1284.                     fprintf(file, "%s\n", temp_str);
  1285.                 
  1286.                 hdr = (_mem_ptr_hdr_ptr)
  1287.                         ( (char *)hdr + GET_PTR_SIZE(hdr) + sizeof(_mem_ptr_hdr) );
  1288.                 }
  1289.             
  1290.             blk = blk->next;
  1291.             }
  1292.         
  1293.         pool = pool->next;
  1294.         }
  1295.     }
  1296.  
  1297. #define ROW_BYTES        16
  1298.  
  1299. hex_dump(output, title, ptr, bytes)
  1300. FILE    *output;
  1301. char    *title;
  1302. char    *ptr;
  1303. long    bytes;
  1304. {
  1305. int                rows, residue, i, j;
  1306. unsigned char    save_buf[ROW_BYTES+2];
  1307. unsigned char    hex_buf[4];
  1308. char            hex_chars[20];
  1309.     strcpy(hex_chars, "0123456789ABCDEF");
  1310.     
  1311.     fprintf(output, "\n%s - x%lX (%ld) bytes.\n", title, bytes, bytes);
  1312.     rows = bytes >> 4;
  1313.     residue = bytes & 0x0000000F;
  1314.     for (i=0; i<rows; i++) {
  1315.         fprintf(output, "%04.4X:", i * ROW_BYTES);
  1316.         for (j=0; j<ROW_BYTES; j++) {
  1317.             save_buf[j] = *ptr++;
  1318.             hex_buf[0] = hex_chars[(save_buf[j] >> 4) & 0x0F];
  1319.             hex_buf[1] = hex_chars[save_buf[j] & 0x0F];
  1320.             hex_buf[2] = '\0';
  1321.             fprintf(output, " %2.2s", hex_buf);
  1322.             if (save_buf[j] < 0x20 || save_buf[j] > 0xD9) save_buf[j] = '.';
  1323.             }
  1324.         save_buf[ROW_BYTES+1] = '\0';
  1325.         fprintf(output, "\t/* %16.16s */\n", save_buf);
  1326.         }
  1327.     if (residue) {
  1328.         fprintf(output, "%04.4X:", i * ROW_BYTES);
  1329.         for (j=0; j<residue; j++) {
  1330.             save_buf[j] = *ptr++;
  1331.             hex_buf[0] = hex_chars[(save_buf[j] >> 4) & 0x0F];
  1332.             hex_buf[1] = hex_chars[save_buf[j] & 0x0F];
  1333.             hex_buf[2] = '\0';
  1334.             fprintf(output, " %2.2s", hex_buf);
  1335.             if (save_buf[j] < 0x20 || save_buf[j] > 0xD9) save_buf[j] = '.';
  1336.             }
  1337.         for (/*j INHERITED*/; j<ROW_BYTES; j++) {
  1338.             save_buf[j] = ' ';
  1339.             fprintf(output, "   ");
  1340.             }
  1341.         save_buf[ROW_BYTES+1] = '\0';
  1342.         fprintf(output, "\t/* %16.16s */\n", save_buf);
  1343.         }
  1344.     }
  1345.  
  1346. #ifdef TESTING
  1347.  
  1348. main(argc, argv)
  1349. char    *argc;
  1350. char    *argv[];
  1351. {
  1352. int        i;
  1353. _mem_pool_ptr pool;
  1354. char    *ptr, *aptr[20];
  1355. char    input[128];
  1356. #pragma unused (argc, argv)
  1357.  
  1358.     printf("Debug level?\n");
  1359.     gets(input);
  1360.     if (input[0] == '\0' || input[0] == 'q')
  1361.         return 0;
  1362.     
  1363.     pool_malloc_debug_level = atoi(input);
  1364.     printf("Debug level set to %d\n", pool_malloc_debug_level);
  1365.     
  1366.     fprintf(stderr, "******************** START ********************\n");
  1367.     list_pool_forest(stderr, 0);
  1368.     
  1369.     printf("Allocating in default (system) pool...\n");
  1370.     for (i = 10 ; i < (10 * 1024) ; i += 128)
  1371.         if (malloc(i) == NULL)
  1372.             break;
  1373.     
  1374.     fprintf(stderr, "******************** ## 1 ## ********************\n");
  1375.     list_pool_forest(stderr, 0);
  1376.     
  1377.     printf("Allocating and Free-ing in default (system) pool...\n");
  1378.     for (i = 10 ; i < (10 * 1024) ; i += 128)
  1379.         if ((ptr = malloc(i)) != NULL)
  1380.             free(ptr);
  1381.         else
  1382.             break;
  1383.         
  1384.     fprintf(stderr, "******************** ## 2 ## ********************\n");
  1385.     list_pool_forest(stderr, 0);
  1386.     
  1387.     printf("Allocating and Free-ing again in default (system) pool...\n");
  1388.     for (i = 0 ; i < 20 ; i++)
  1389.         aptr[i] = NULL;
  1390.     for (i = 0 ; i < 20 ; i++) {
  1391.         aptr[i] = malloc(i * 128);
  1392.         if (aptr[i] == NULL)
  1393.             break;
  1394.         }
  1395.     for (i = 19 ; i >= 0 ; i--)
  1396.         if (aptr[i] != NULL) {
  1397.             free(aptr[i]);
  1398.             }
  1399.         
  1400.     fprintf(stderr, "******************** ## 3 ## ********************\n");
  1401.     list_pool_forest(stderr, 0);
  1402.     
  1403.     pool = new_malloc_pool ( 2001, (16 * 1024) );
  1404.     printf("new_malloc_pool ( 2001, %d ) returns x%lx\n", (16 * 1024), pool);
  1405.     if (pool) {
  1406.         set_default_pool ( 2001 );
  1407.         
  1408.         printf("Allocating in pool #2001...\n");
  1409.         for (i = 10 ; i < (10 * 1024) ; i += 128)
  1410.             if (malloc(i) == NULL)
  1411.                 break;
  1412.         }
  1413.  
  1414.     fprintf(stderr, "******************** ## 4 ## ********************\n");
  1415.     list_pool_forest(stderr, 0);
  1416.     
  1417.     printf("Free-ing memory in pool #2001...\n");
  1418.     free_pool_memory ( 2001 );
  1419.  
  1420.     fprintf(stderr, "******************** ## 5 ## ********************\n");
  1421.     list_pool_forest(stderr, 0);
  1422.     
  1423.     printf("Done.\n");
  1424.     }
  1425.  
  1426. #endif TESTING
  1427.  
  1428. #endif _PM_STATS
  1429.