home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gwm18a.zip / malloc.c < prev    next >
C/C++ Source or Header  |  1995-07-03  |  20KB  |  850 lines

  1. /* Copyright 1989-91 GROUPE BULL -- See license conditions in file COPYRIGHT */
  2. /*****************************************************************************\
  3. *                                                                             *
  4. * WOOL malloc:                                                                *
  5. * A fast malloc, with optional:                                               *
  6. * -DSTATS    stats                                                         *
  7. * -DMLEAK    memory lossage tracing via hash coding                        *
  8. * -DDEBUG    debugging information                                         *
  9. *     range checking (on_line and with a dbx call)                          *
  10. * -DMALLOCDEBUG more info                                                     *
  11. * -DUSE_STANDARD_MALLOC : use the system functions (do NOT work with -DDEBUG) *
  12. *                                                                             *
  13. \*****************************************************************************/
  14.  
  15. #ifdef MALLOCDEBUG0
  16. #ifndef MALLOCDEBUG
  17. #define MALLOCDEBUG
  18. #endif
  19. #endif
  20.  
  21.  
  22. #ifdef USE_STANDARD_MALLOC
  23. #ifdef DEBUG
  24. error=USE_STANDARD_MALLOC_and_DEBUG_are_incompatible_options;
  25. #endif
  26. #ifdef MALLOCDEBUG
  27. error=USE_STANDARD_MALLOC_and_MALLOCDEBUG_are_incompatible_options;
  28. #endif
  29. #ifdef MALLOCDEBUG0
  30. error=USE_STANDARD_MALLOC_and_MALLOCDEBUG0_are_incompatible_options;
  31. #endif
  32. #ifdef MLEAK
  33. error=USE_STANDARD_MALLOC_and_MLEAK_are_incompatible_options;
  34. #endif
  35. #ifdef DO_NOT_REDEFINE_MALLOC
  36. error=USE_STANDARD_MALLOC_and_DO_NOT_REDEFINE_MALLOC_are_incompatible_options;
  37. #endif
  38.     
  39. int malloc_init(){}
  40.  
  41. #else
  42.  
  43. #define WlO WOOL_OBJECT
  44. #define WlError wool_error
  45. #define WlAtom WOOL_Atom
  46. #define WlPuts wool_puts
  47. #define WlPrintf wool_printf
  48. #define WlMallocInit malloc_init
  49. #define WlMallocZoneBegin malloc_zone_begin
  50. #define WlMallocZoneEnd malloc_zone_end
  51. #define WlAtomFindNextPrefixedAtom find_next_prefixed_atom
  52. #define WlHashSlot HashSlot
  53. #define WlIntern wool_atom
  54. #define WlHashTableSize HashTableSize
  55.  
  56.  
  57. #include "EXTERN.h"
  58. #ifdef STATS
  59. #include <stdio.h>
  60. #else
  61. #define    NULL 0
  62. #endif
  63. #include <sys/types.h>
  64.  
  65. #if defined(i386) && !defined(sequent) && !defined(SCO) && !defined(linux)
  66. typedef unsigned char    u_char;
  67. typedef unsigned int    u_int;
  68. #endif /* i386 */
  69.  
  70. #include "wool.h"
  71.  
  72. #ifndef VOID_MALLOC
  73. #define MALLOC_TYPE char *
  74. #else
  75. #define MALLOC_TYPE void *
  76. #endif
  77.  
  78. #ifdef STANDARD_MALLOC
  79. # ifndef DO_NOT_REDEFINE_MALLOC
  80. # define DO_NOT_REDEFINE_MALLOC
  81. # endif
  82. # ifndef DO_NOT_USE_SBRK
  83. # define DO_NOT_USE_SBRK
  84. # endif
  85. #endif
  86.  
  87. #ifndef DO_NOT_REDEFINE_MALLOC
  88. #define REAL_malloc(nbytes)    malloc(nbytes)
  89. #define REAL_free(ptr)        free(ptr)
  90. #define REAL_realloc(ptr, nbytes) realloc(ptr, nbytes)
  91. #define REAL_calloc(n, s)    calloc(n, s)
  92. #else /* DO_NOT_REDEFINE_MALLOC */
  93. #define REAL_malloc(nbytes)    wool_malloc(nbytes)
  94. #define REAL_free(ptr)        wool_free(ptr)
  95. #define REAL_realloc(ptr, nbytes) wool_realloc(ptr, nbytes)
  96. #define REAL_calloc(n, s)    wool_calloc(n, s)
  97. #endif /* DO_NOT_REDEFINE_MALLOC */
  98.  
  99. #ifdef MLEAK
  100. #include "wl_atom.h"
  101. WlAtom      *WlHashSlot();
  102. int MLEAK_on = 0;
  103. int MLEAK_count = 0;
  104. int MLEAK_num = 0;
  105. MLEAK_break(){}        /* MLEAK_num reached! */
  106. extern WlAtom WlAtomFindNextPrefixedAtom();
  107. extern int WlHashTableSize;
  108. #endif /* MLEAK */
  109.  
  110.  
  111.  
  112. /*
  113.  * This storage allocator trades space for speed in separate arenas for each
  114.  * 2^n sizes (minus the header of 4 bytes (12 with debug on)
  115.  * 
  116.  * The overhead on a block is at least 4 bytes.  When free, this space
  117.  * contains a pointer to the next free block, and the bottom two bits must
  118.  * be zero.  When in use, the first byte is set to MAGIC, and the second
  119.  * byte is the size index.  The remaining bytes are for alignment.
  120.  * Whith DEBUG enabled, if the size of the block fits
  121.  * in two bytes, then the top two bytes hold the size of the requested block
  122.  * plus the range checking words, and the header word MINUS ONE.
  123.  */
  124.  
  125. union overhead {
  126.     union overhead *ov_next;    /* when free */
  127.     struct {
  128.     u_char          ovu_magic;    /* magic number */
  129.     u_char          ovu_index;    /* bucket # */
  130. #ifdef DEBUG
  131.     u_short         ovu_rmagic;    /* range magic number */
  132.     u_int           ovu_size;    /* actual block size */
  133. #endif
  134.     }               ovu;
  135. #ifdef DOUBLE_ALIGN
  136.     double          dummy;    /* Put union on double word boundary */
  137. #endif /* DOUBLE_ALIGN */
  138. };
  139.  
  140. #define    ov_magic    ovu.ovu_magic
  141. #define    ov_index    ovu.ovu_index
  142. #define    ov_rmagic    ovu.ovu_rmagic
  143. #define    ov_size        ovu.ovu_size
  144.  
  145. #define    MAGIC        0xef    /* = 239 magic # on accounting info */
  146. #define RMAGIC        0x5555    /* = 21845 magic # on range info */
  147. #define WlFREED_MAGIC 0x31416    /* block has been freed */
  148.  
  149. #ifdef DEBUG
  150. #define    RSLOP        sizeof (u_short)
  151. #else
  152. #define    RSLOP        0
  153. #endif
  154.  
  155. /*
  156.  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
  157.  * smallest allocatable block is 8 bytes.  The overhead information
  158.  * precedes the data area returned to the user.
  159.  */
  160.  
  161. #define    NBUCKETS 30
  162. static union overhead *nextf[NBUCKETS];
  163. extern char    *WlSbrk();
  164.  
  165. static int      pagesz;        /* page size */
  166. static int      pagebucket;    /* page size bucket */
  167. static void    morecore();
  168.  
  169. #ifdef STATS
  170. /*
  171.  * nmalloc[i] is the difference between the number of mallocs and frees
  172.  * for a given block size.
  173.  */
  174. static u_int    nmalloc[NBUCKETS];
  175.  
  176. #endif
  177.  
  178. char *WlMallocZoneBegin, *WlMallocZoneEnd;
  179.  
  180. /* WlMallocCheck is a routine that you can call regularily to verify validity 
  181.  * of the whole malloced blocks
  182.  * you MUST compile with -DMALLOCDEBUG, but not necessarily with -DDEBUG
  183.  * then malloc, free & realloc will call it each time
  184.  */
  185.  
  186. #ifdef MALLOCDEBUG
  187. #define MDbucketMax 10000
  188. char *MDbuckets[MDbucketMax];
  189. int MDbucketsSize[MDbucketMax];
  190. int MDbucket = 0;
  191. #ifdef MALLOCDEBUG0
  192. int MDnocheck = 1;
  193. #else
  194. int MDnocheck = 0;
  195. #endif
  196.  
  197. int
  198. WlMallocCheck()
  199. {
  200.     int i, j, sz, nblks, bucket;
  201.     union overhead *op, *pop;
  202.  
  203.     if (MDnocheck)
  204.     return 0;
  205.  
  206.     for (i = 0; i < MDbucket; i++) {
  207.     sz = MDbucketsSize[i];
  208.     bucket = 0;
  209.     while (sz > (1 << (bucket + 3)))
  210.         bucket++;
  211.     if (sz < pagesz) {
  212.         nblks = pagesz / sz;
  213.     } else {
  214.         nblks = 1;
  215.     }
  216.     for (j = 0; j < nblks; j++) {
  217.         op = (union overhead *) (MDbuckets[i] + j*sz);
  218.         if (((int)(op->ovu.ovu_magic)) == MAGIC) { /* in use */
  219.         ASSERT(op->ovu.ovu_index == bucket);
  220. #ifdef DEBUG
  221.         ASSERT(op -> ovu.ovu_rmagic == RMAGIC);
  222.         ASSERT(*(u_short *)((caddr_t)(op + 1)+op->ovu.ovu_size)==RMAGIC);
  223. #endif /*DEBUG*/
  224.         } else {            /* free, follow chain */
  225.         pop = op;
  226.         while (op) {
  227.             op = op->ov_next;
  228.         }
  229.         }
  230.     }
  231.     }
  232.     return 0;
  233. }
  234.  
  235. #endif /*MALLOCDEBUG*/
  236.     
  237. #ifndef DO_NOT_USE_SBRK
  238. #define WlSbrk(n) sbrk(n)
  239. #else /*DO_NOT_USE_SBRK*/
  240.  
  241. /* for OSes with buggy malloc, we cannot use sbrk directly, so we just waste
  242.  * memory...
  243.  */
  244.  
  245. /* TODO: be smart, allocate a big arena, and do the splitting ourselves */
  246.  
  247. char *
  248. WlSbrk(amt)
  249.     int amt;
  250. {
  251.     return (char *) malloc(amt);
  252. }
  253.  
  254. #endif /*DO_NOT_USE_SBRK*/
  255.  
  256.  
  257. /*
  258.  * Init malloc lists: to be called AT THE TOP of your program!!!
  259.  * setup page size and align break pointer so all data will be page aligned.
  260.  */
  261.  
  262. WlMallocInit()
  263. {
  264.     union overhead *op;
  265.     int    bucket;
  266.     unsigned amt, n;
  267.  
  268.     ASSERT(!pagesz);
  269.     pagesz = n = getpagesize();
  270.     op = (union overhead *) WlSbrk(0);
  271.     WlMallocZoneBegin = (char *) op;
  272.     n = n - sizeof(*op) - ((int) op & (n - 1));
  273.     if ((int) n < 0)
  274.     n += pagesz;
  275.     if (n) {
  276.     if ((char *) WlSbrk(n) == (char *) -1)
  277.         WlError("no more memory%s", "");
  278.     }
  279.     bucket = 0;
  280.     amt = 8;
  281.     while (pagesz > amt) {
  282.     amt <<= 1;
  283.     bucket++;
  284.     }
  285.     pagebucket = bucket;
  286. }
  287.  
  288. /*
  289.  * Convert amount of memory requested into closest block size stored in
  290.  * hash buckets which satisfies request. Account for space used per block
  291.  * for accounting.
  292.  */
  293.  
  294. MALLOC_TYPE
  295. REAL_malloc(nbytes)
  296. unsigned        nbytes;
  297. {
  298.     union overhead *op;
  299.     int    bucket;
  300.     unsigned amt, n;
  301. #ifdef DEBUG
  302.     char *result;
  303. #endif
  304.  
  305. #ifdef MALLOCDEBUG
  306.     WlMallocCheck();
  307. #endif
  308. #ifdef DEBUG
  309.     if ((nbytes > 100000) 
  310. #  ifdef DEBUG2
  311.     || (nbytes == 0)
  312. #  endif
  313.     ) {
  314.     fprintf(stderr, "MALLOC: trying to allocate %d bytes\n", nbytes);
  315.     stop_if_in_dbx();
  316.     }
  317. #endif /* DEBUG */
  318.  
  319.     if (nbytes <= (n = pagesz - sizeof(*op) - RSLOP)) {
  320. #ifndef DEBUG
  321.     amt = 8;        /* size of first bucket */
  322.     bucket = 0;
  323. #else
  324.     amt = 16;        /* size of first bucket */
  325.     bucket = 1;
  326. #endif
  327.     n = -(sizeof(*op) + RSLOP);
  328.     } else {
  329.     amt = pagesz;
  330.     bucket = pagebucket;
  331.     }
  332.     while (nbytes > amt + n) {  /* find bucket */
  333.     amt <<= 1;
  334.     bucket++;
  335.     }
  336.  
  337.     /* if no hash bucket, allocates more memory */
  338.     if ((op = nextf[bucket]) == NULL) {
  339.     morecore(bucket);
  340.     if ((op = nextf[bucket]) == NULL)    /* TO_DO: compact space? */
  341.         WlError("no more memory%s", "");
  342.     }
  343.     /* remove from linked list */
  344.     nextf[bucket] = op -> ov_next;
  345.     op -> ovu.ovu_index = bucket;
  346. #ifdef STATS
  347.     nmalloc[bucket]++;
  348. #endif
  349.  
  350. #ifdef DEBUG
  351.     /* Record allocated size of block and bound space with magic numbers. */
  352.     op -> ovu.ovu_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
  353.     op -> ovu.ovu_magic = MAGIC;
  354.     op -> ovu.ovu_rmagic = RMAGIC;
  355.     *(u_short *) ((caddr_t) (op + 1) + op -> ovu.ovu_size) = RMAGIC;
  356.     ASSERT(((char *) (op + 1)));
  357. #else
  358. # ifdef MALLOCDEBUG
  359.     op -> ovu.ovu_magic = MAGIC;
  360. # endif
  361. #endif /*DEBUG*/
  362. #ifndef MLEAK
  363. #ifdef DEBUG
  364.     result = ((char *) (op + 1));
  365.     Trace('m', ("malloc: 0x%x\n", result));
  366.     return result;
  367. #else
  368.     return ((char *) (op + 1));
  369. #endif /*DEBUG*/
  370. #else
  371.     if (MLEAK_on) {
  372.     char            name[20];
  373.     WlAtom            atom;
  374.     char           *ptr = (char *) (op + 1);
  375.  
  376.     sprintf(name + 1, "0x%x", ptr);
  377.     name[0] = '\r';
  378.     MLEAK_on = 0;
  379.     atom = WlIntern(name);
  380.     MLEAK_on = 1;
  381.     atom -> c_val = (WlO) ++MLEAK_count;
  382.     if (MLEAK_num == MLEAK_count)
  383.         MLEAK_break();
  384.     return ptr;
  385.     } else {
  386. #ifdef DEBUG
  387.     result = ((char *) (op + 1));
  388.     Trace('m', ("malloc: 0x%x\n", result));
  389.     return result;
  390. #else
  391.     return ((char *) (op + 1));
  392. #endif /*DEBUG*/
  393.     }
  394. #endif /* MLEAK */
  395. }
  396.  
  397. /*
  398.  * Allocate more memory to the indicated bucket.
  399.  */
  400. static void
  401. morecore(bucket)
  402. int             bucket;
  403. {
  404.     union overhead *op;
  405.     int    sz;        /* size of desired block */
  406.     int    amt;    /* amount to allocate */
  407.     int    nblks;    /* how many blocks we get */
  408.  
  409.     sz = 1 << (bucket + 3);
  410.     if (sz < pagesz) {
  411.     amt = pagesz;
  412.     nblks = amt / sz;
  413.     } else {
  414.     amt = sz + pagesz;
  415.     nblks = 1;
  416.     }
  417.     op = (union overhead *) WlSbrk(amt);
  418.     WlMallocZoneEnd = ((char *) op) + amt;
  419. #ifdef MALLOCDEBUG
  420.     ASSERT(MDbucket < MDbucketMax);
  421.     MDbuckets[MDbucket] = (char *) op;
  422.     MDbucketsSize[MDbucket] = sz;
  423.     MDbucket++;
  424. #endif
  425.     /* no more room! */
  426.     if ((int) op == -1)
  427.     return;
  428.  
  429.     /* Add new memory allocated to that on free list for this hash bucket. */
  430.     nextf[bucket] = op;
  431.     while (--nblks > 0) {
  432.     op -> ov_next = (union overhead *) ((caddr_t) op + sz);
  433.     op = (union overhead *) ((caddr_t) op + sz);
  434.     }
  435.     op -> ov_next = NULL;
  436. }
  437.  
  438. #ifdef VOID_MALLOC
  439. void
  440. #endif
  441. REAL_free(cp)
  442. MALLOC_TYPE cp;
  443. {
  444.     int    size;
  445.     union overhead *op;
  446. #ifdef DEBUG
  447.     MALLOC_TYPE last_ptr;
  448. #endif /* DEBUG */
  449.  
  450. #ifdef MALLOCDEBUG
  451.     WlMallocCheck();
  452. #endif
  453.  
  454. #ifdef MLEAK
  455.     if (WlHashTableSize) {
  456.     char            name[20];
  457.     WlAtom      *patom;
  458.  
  459.     sprintf(name + 1, "0x%x", cp);
  460.     name[0] = '\r';
  461.     patom = WlHashSlot(name);
  462.     if (*patom)
  463.         (*patom) -> c_val = 0;
  464.     }
  465. #endif /* MLEAK */
  466.  
  467.     ASSERT(cp != NULL);
  468.     if(!cp) return;
  469.     op = (union overhead *) ((caddr_t) cp - sizeof(union overhead));
  470.     ASSERT(op -> ovu.ovu_magic == MAGIC);    /* make sure it was in use */
  471.     ASSERT(op -> ovu.ovu_rmagic == RMAGIC);
  472.     ASSERT(*(u_short *) ((caddr_t) (op + 1) + op -> ovu.ovu_size) == RMAGIC);
  473.     size = op -> ovu.ovu_index;
  474.     ASSERT(size < NBUCKETS);
  475. #ifdef DEBUG
  476.     last_ptr = cp + op -> ovu.ovu_size;
  477. #endif /* DEBUG */
  478.     op -> ov_next = nextf[size];
  479.     nextf[size] = op;
  480. #ifdef DEBUG
  481.     /* we erase all the data zone, to detect earlier re-using a freed block */
  482. #ifdef SIMPLE_LHS
  483.     WlIntFill(cp, last_ptr, WlFREED_MAGIC);
  484. #else /* SIMPLE_LHS */
  485.     while (cp <  last_ptr)
  486.     *(((int *) cp)++) = WlFREED_MAGIC;
  487. #endif /* SIMPLE_LHS */
  488. #endif /* DEBUG */
  489. #ifdef STATS
  490.     nmalloc[size]--;
  491. #endif
  492.     Trace('m', ("free: 0x%x\n", cp));
  493. }
  494.  
  495. #ifdef SIMPLE_LHS
  496. WlIntFill(p, last, value)
  497. int *p, *last, value;
  498. {
  499.     while (p < last)
  500.     *p++ = value;
  501. }
  502. #endif /* SIMPLE_LHS */
  503.  
  504. /*
  505.  * Simple realloc without storage compaction
  506.  * can be handled NULL pointer, but not 0 size...
  507.  */
  508.  
  509. MALLOC_TYPE
  510. REAL_realloc(cp, nbytes)
  511. MALLOC_TYPE cp;
  512. unsigned        nbytes;
  513. {
  514.     u_int  onb, i;
  515.     union overhead *op;
  516.     char           *res;
  517.  
  518. #ifdef MALLOCDEBUG
  519.     WlMallocCheck();
  520.     ASSERT(nbytes);
  521. #endif
  522.     if (!cp)
  523.     return REAL_malloc(nbytes);
  524.     op = (union overhead *) ((caddr_t) cp - sizeof(union overhead));
  525.     i = op -> ovu.ovu_index;
  526.     onb = 1 << (i + 3);
  527.     if (onb < pagesz)
  528.     onb -= sizeof(*op) + RSLOP;
  529.     else
  530.     onb += pagesz - sizeof(*op) - RSLOP;
  531.     /* avoid the copy if same size block */
  532.     if (i) {
  533.     i = 1 << (i + 2);
  534.     if (i < pagesz)
  535.         i -= sizeof(*op) + RSLOP;
  536.     else
  537.         i += pagesz - sizeof(*op) - RSLOP;
  538.     }
  539.     if (nbytes <= onb && nbytes > i) {
  540. #ifdef DEBUG
  541.     op -> ovu.ovu_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
  542.     *(u_short *) ((caddr_t) (op + 1) + op -> ovu.ovu_size) = RMAGIC;
  543. #endif
  544.     return (cp);
  545.     } else {
  546.     if ((res = REAL_malloc(nbytes)) == NULL)
  547.         return (NULL);
  548.     ASSERT(cp != res);
  549.     bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
  550.     REAL_free(cp);
  551.     return (res);
  552.     }
  553. }
  554.  
  555. MALLOC_TYPE
  556. REAL_calloc(nelem, elsize)
  557. unsigned nelem, elsize;
  558. {
  559.     char           *result = REAL_malloc(nelem * elsize);
  560.  
  561.     if (result)
  562.     bzero(result, nelem * elsize);
  563.     return result;
  564. }
  565.  
  566. /*****************************************************************************\
  567. *                 misc utilities                                *
  568. \*****************************************************************************/
  569. /* returns room in current chunk
  570.  * we set up things in debug mode so that all the chunk can be allocated
  571.  * without trashing end markers
  572.  */
  573.  
  574. int
  575. WlMallocedSize(cp)
  576.     char           *cp;
  577. {
  578.     u_int  onb, i;
  579.     union overhead *op;
  580.  
  581.     if (!cp)
  582.     return 0;
  583.     op = (union overhead *) ((caddr_t) cp - sizeof(union overhead));
  584.     i = op -> ovu.ovu_index;
  585.     onb = 1 << (i + 3);
  586.     if (onb < pagesz)
  587.     onb -= sizeof(*op) + RSLOP;
  588.     else
  589.     onb += pagesz - sizeof(*op) - RSLOP;
  590. #ifdef DEBUG
  591.     /* set Recorded allocated size to max */
  592.     op -> ovu.ovu_size = (onb + RSLOP - 1) & ~(RSLOP - 1);
  593.     op -> ovu.ovu_magic = MAGIC;
  594.     op -> ovu.ovu_rmagic = RMAGIC;
  595.     *(u_short *) ((caddr_t) (op + 1) + op -> ovu.ovu_size) = RMAGIC;
  596. #endif
  597.     return onb;
  598. }
  599.  
  600.  
  601. #ifdef STATS
  602. /*
  603.  * WlMstats - print out statistics about malloc
  604.  * 
  605.  * Prints two lines of numbers, one showing the length of the free list
  606.  * for each size category, the second showing the number of mallocs -
  607.  * frees for each size category.
  608.  */
  609. WlO
  610. WlMstats()
  611. {
  612.     int    i, j;
  613.     union overhead *p;
  614.     int             totfree = 0, totused = 0;
  615.  
  616.     int             Nbuckets = (NBUCKETS > 14 ? 14 : NBUCKETS);
  617.  
  618.     WlPuts("Memory allocation statistics \n");
  619.     WlPuts("size");
  620.     for (i = 0; i < Nbuckets; i++) {
  621.     if (i < 7) {
  622.         WlPrintf("%5ld", (long) (1 << (i + 3)));
  623.     } else {
  624.         WlPrintf("%4ldk", (long) (1 << (i - 7)));
  625.     }
  626.     }
  627.     WlPuts("\nfree");
  628.     for (i = 0; i < Nbuckets; i++) {
  629.     for (j = 0, p = nextf[i]; p; p = p -> ov_next, j++);
  630.     WlPrintf("%5ld", (long) j);
  631.     totfree += j * (1 << (i + 3));
  632.     }
  633.     WlPuts("\nused");
  634.     for (i = 0; i < Nbuckets; i++) {
  635.     WlPrintf("%5ld", (long) nmalloc[i]);
  636.     totused += nmalloc[i] * (1 << (i + 3));
  637.     }
  638.     WlPrintf("\n\tTotal in use: %d,", (long) totused);
  639.     WlPrintf("total free: %d\n", (long) totfree);
  640.     return NIL;
  641. }
  642. #endif /* STATS */
  643.  
  644. /************\
  645. *          *
  646. * DBX tools  *
  647. *          *
  648. \************/
  649.  
  650. #ifdef DEBUG
  651.  
  652. /*
  653.  * verify if pointer is still valid
  654.  */
  655.  
  656. int
  657. WlVerifyMalloc(cp)
  658. char           *cp;
  659. {
  660.     int    size;
  661.     union overhead *op;
  662.  
  663.     if (cp == NULL)
  664.     return 0;
  665.     op = (union overhead *) ((caddr_t) cp - sizeof(union overhead));
  666.     ASSERT(op -> ovu.ovu_magic == MAGIC);    /* make sure it was in use */
  667.     if (op -> ovu.ovu_magic != MAGIC)
  668.     return 0;            /* sanity */
  669.     ASSERT(op -> ovu.ovu_rmagic == RMAGIC);
  670.     ASSERT(*(u_short *) ((caddr_t) (op + 1) + op -> ovu.ovu_size) == RMAGIC);
  671.     size = op -> ovu.ovu_index;
  672.     ASSERT(size < NBUCKETS);
  673.     return 1;
  674. }
  675.  
  676. #endif /* DEBUG */
  677.  
  678. #ifdef MLEAK
  679.  
  680. /************************************************************************\
  681. *                                      *
  682. * malloc-leak tracing: (colas: uses the hash table!)             *
  683. *                                      *
  684. * Under dbx:                                 *
  685. *                                      *
  686. * Turn tracing on by setting MLEAK_on to 1                 *
  687. * When malloced blocks are done, reset it to 0                 *
  688. * then MLEAK_print(file,n) prints the nth first (if any) traced blocks     *
  689. * remain allocated then. (file=0 means stdout)                 *
  690. *                                      *
  691. * then by re-executing the program and setting MLEAK_num to the desired     *
  692. * number and setting a beakpoint in MLEAK_break, bdx will halt when the     *
  693. * desired block will be allocated                     *
  694. *                                      *
  695. * Exemple of test file:                             *
  696. *                                      *
  697. *     (load ".gwmrc.gwm")                         *
  698. *     (? "set MLEAK_on = 1\n")                     *
  699. *     (break)                                 *
  700. *     (load ".gwmrc.gwm")                         *
  701. *     (? "set MLEAK_on = 0\n")                     *
  702. *     (break)                                 *
  703. *     (load ".gwmrc.gwm")                         *
  704. *     (load ".gwmrc.gwm")                         *
  705. *     (? "call MLEAK_print(\"FOO\", 10000)\n")             *
  706. *     (? "stop in MLEAK_break\n")                     *
  707. *     (? "continue\n")                         *
  708. *     (break)                                 *
  709. *                                      *
  710. \************************************************************************/
  711.  
  712. typedef struct _WlMleakCell {
  713.     int number;
  714.     char *object_addr;
  715. } *WlMleakCell;
  716.  
  717. #define WlMleakCellSize 100
  718.  
  719. static struct _WlMleakCell wlmltab[WlMleakCellSize];
  720.  
  721. static int
  722. WlMleakCellCompare(a, b)
  723.     WlMleakCell a, b;
  724. {
  725.     return (a->number - b->number);
  726. }
  727.  
  728. static int
  729. WlMleakCellMax(tab, size)
  730.     WlMleakCell tab;
  731.     int size;
  732. {
  733.     int i;
  734.     int max = 0;
  735.  
  736.     for (i = 0; i< size; i++) {
  737.     if (tab[i].number > max) {
  738.         max = tab[i].number;
  739.     }
  740.     }
  741.     return max;
  742. }
  743.  
  744. MLEAK_print()
  745. {
  746.     int i = 0, old_MLEAK_on = MLEAK_on;
  747.     WlAtom atom;
  748.     int curcell = 0;
  749.     int max_dirty = 1;
  750.     int max_index;
  751.  
  752.     MLEAK_on = 0;
  753.  
  754.     /* collect entries */
  755.     WlAtomFindNextPrefixedAtom('\0');
  756.     while (atom = WlAtomFindNextPrefixedAtom('\r')) {
  757.     int slot;
  758.     i++;
  759.     if (curcell >= WlMleakCellSize) {
  760.         if (max_dirty) {
  761.         max_index = WlMleakCellMax(wlmltab, WlMleakCellSize);
  762.         max_dirty = 0;
  763.         }
  764.         if (((int) atom->c_val) < wlmltab[max_index].number) {
  765.         max_dirty = 1;
  766.         slot = max_index;
  767.         } else {
  768.         curcell++;
  769.         continue;
  770.         }
  771.     } else {
  772.         slot = curcell;
  773.     }
  774.     wlmltab[slot].number = (int) atom->c_val;
  775.     wlmltab[slot].object_addr = atom->p_name + 1;
  776.     curcell++;
  777.     }
  778.  
  779.     /* sort entries */
  780.     qsort(wlmltab, Min(WlMleakCellSize, curcell), sizeof(struct _WlMleakCell),
  781.       WlMleakCellCompare);
  782.  
  783.     /* print entries */
  784.     printf("\n");
  785.     if (curcell > WlMleakCellSize) {
  786.     printf("Too many leaks (%d), printing only the first %d ones\n",
  787.         curcell, WlMleakCellSize);
  788.     curcell = WlMleakCellSize;
  789.     }
  790.     for (i = 0; i < curcell; i++) {
  791.     WlO obj;
  792.     union overhead *op;
  793.  
  794.     printf("%2d th malloc at %s remains",
  795.         wlmltab[i].number, wlmltab[i].object_addr);
  796.     sscanf(wlmltab[i].object_addr, "0x%x", &obj);
  797.     op = (union overhead *)
  798.         (((caddr_t) obj) - sizeof(union overhead));
  799.     printf(" bucket#%d", op->ovu.ovu_index);
  800. #ifdef DEBUG
  801.     printf(" size %3d bytes", op->ovu.ovu_size);
  802. #endif
  803.     if (wool_object_is_valid(obj)) {
  804.         printf(" of type: %s\n  = ", ((WOOL_Atom) obj->type[0])->p_name);
  805.         wool_print(obj);
  806.     }
  807.     printf("\n");
  808.     }
  809.     MLEAK_on = old_MLEAK_on;
  810. }
  811.  
  812. WlO
  813. MLEAK_printW()
  814. {
  815.     MLEAK_print();
  816.     return NIL;
  817. }
  818.  
  819. #ifdef __OBSOLETE
  820.  
  821. MLEAK_print(filename, n)
  822. char *filename;
  823. int    n;
  824. {
  825.     int             i = 0, old_MLEAK_on = MLEAK_on;
  826.     WlAtom       atom;
  827.     FILE           *ptr;
  828.  
  829.     MLEAK_on = 0;
  830.     if ((!filename) || filename[0] == '\0') {
  831.     filename = NULL;
  832.     ptr = NULL;
  833.     } else {
  834.     ptr = fopen(filename, "w+");
  835.     }
  836.     WlAtomFindNextPrefixedAtom('\0');
  837.     while ((atom = WlAtomFindNextPrefixedAtom('\r')) && i++ < n) {
  838.     fprintf((ptr ? ptr : stdout),
  839.         "%d th malloc at %s is still there\n",
  840.         atom -> c_val, atom -> p_name + 1);
  841.     }
  842.     if (filename)
  843.     fclose(ptr);
  844.     MLEAK_on = old_MLEAK_on;
  845. }
  846. #endif __OBSOLETE
  847.  
  848. #endif /* MLEAK */
  849. #endif                    /* USE_STANDARD_MALLOC */
  850.