home *** CD-ROM | disk | FTP | other *** search
/ The Pier Shareware 6 / The_Pier_Shareware_Number_6_(The_Pier_Exchange)_(1995).iso / 024 / psi110g.zip / ALLOCNEW.C < prev    next >
C/C++ Source or Header  |  1994-04-17  |  18KB  |  659 lines

  1. /* memory allocation routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Adapted from alloc routine in K&R; memory statistics and interrupt
  5.  * protection added for use with net package. Must be used in place of
  6.  * standard Turbo-C library routines because the latter check for stack/heap
  7.  * collisions. This causes erroneous failures because process stacks are
  8.  * allocated off the heap.
  9.  *
  10.  * Mods by G1EMM , PA0GRI
  11.  */
  12.   
  13. #include <dos.h>
  14. #include <alloc.h>
  15. #include "global.h"
  16. #include "proc.h"
  17. #include "cmdparse.h"
  18. #include "mbuf.h"
  19. #include "socket.h"
  20. #include "daemon.h"
  21. #ifdef EMS
  22. #include "memlib.h"
  23. #endif
  24. #ifdef XMS
  25. #include "xms.h"
  26. #endif
  27.   
  28. extern unsigned long _brklvl;
  29.   
  30. static unsigned long ReallocSys;    /* Count of blocks reallocated to core mem */
  31. static unsigned long Memfail;   /* Count of allocation failures */
  32. static unsigned long Allocs;    /* Total allocations */
  33. static unsigned long Frees;     /* Total frees */
  34. static unsigned long Invalid;   /* Total calls to free with garbage arg */
  35. static unsigned long Yellows;   /* Yellow alert garbage collections */
  36. static unsigned long Reds;      /* Red alert garbage collections */
  37. static unsigned long Overuse;   /* Total calls to free with overused arg */
  38. static unsigned long Intalloc;  /* Calls to malloc with ints disabled */
  39. static unsigned long Intfree;   /* Calls to free with ints disabled */
  40. static int Memwait;             /* Number of tasks waiting for memory */
  41. unsigned long Availmem;         /* Heap memory, ABLKSIZE units */
  42. static unsigned long Morecores;
  43. #ifdef notdef
  44. static int Efficient = 1;       /* 0 = normal/fast, 1 = effecient/slow */
  45. #endif
  46. static int Memdebug = 0;        /* 0 = normal, 1 = call logstat() */
  47. #ifdef MULTITASK
  48. unsigned Minheap = 16 * 1024;   /* Min free heap when shelling out */
  49. #endif
  50. static char freewarn[] ="free: WARNING! %s (%Fp) pc = %04x:%04x proc %s%c";
  51. static char freewarn1[] = "invalid pointer";
  52. static char HeapSizeStr[] = "heap size %lu, avail %lu (%lu%%), morecores %lu, coreleft %lu";
  53. static char AllocStr[] = "allocs %lu, frees %lu (diff %lu), reallocs %lu, alloc fails %lu\ninvalid frees %lu, overused %lu";
  54. static char Threshold[] = "threshold %lu\n";
  55. static char GarbageStr[] = "garbage collections yellow %lu, red %lu";
  56. #ifdef notdef
  57. static char EfficientStr[] = "efficient %u, threshold %lu";
  58. #endif
  59. static char EfficientStr[] = "threshold %lu";
  60. static char InterruptStr[] = "interrupts-off calls to malloc %lu, free %lu\n";
  61. #ifdef Kelvdebug
  62. static char freewarn2[] = "overused buffer";
  63. #endif
  64.   
  65. static unsigned long Sizes[16];
  66. #ifdef EMS
  67. extern int EMS_Available;
  68. #endif
  69. static int logstat __ARGS((void));
  70.   
  71. int dostat __ARGS((int argc,char *argv[],void *p));
  72. static int dofreelist __ARGS((int argc,char *argv[],void *p));
  73. static int doibufsize __ARGS((int argc,char *argv[],void *p));
  74. static int donibufs __ARGS((int argc,char *argv[],void *p));
  75. static int dothresh __ARGS((int argc,char *argv[],void *p));
  76. static int dosizes __ARGS((int argc,char *argv[],void *p));
  77. static int doefficient __ARGS((int argc,char *argv[],void *p));
  78. static int domemdebug __ARGS((int argc,char *argv[],void *p));
  79. static int dominheap __ARGS((int argc,char *argv[],void *p));
  80.   
  81. struct cmds Memcmds[] = {
  82.     "debug",    domemdebug, 0, 0, NULLCHAR,
  83. #ifdef notdef
  84.     "efficient",doefficient,0, 0, NULLCHAR,
  85. #endif
  86.     "freelist", dofreelist, 0, 0, NULLCHAR,
  87.     "ibufsize", doibufsize, 0, 0, NULLCHAR,
  88. #ifdef MULTITASK
  89.     "minheap",  dominheap,  0, 0, NULLCHAR,
  90. #endif
  91.     "nibufs",   donibufs,   0, 0, NULLCHAR,
  92.     "sizes",    dosizes,    0, 0, NULLCHAR,
  93.     "status",   dostat,     0, 0, NULLCHAR,
  94.     "thresh",   dothresh,   0, 0, NULLCHAR,
  95.     NULLCHAR,
  96. };
  97.   
  98. #ifdef  LARGEDATA
  99. #define HUGE    huge
  100. #else
  101. #define HUGE
  102. #endif
  103.   
  104. union header {
  105.     struct {
  106.         union header HUGE *ptr;
  107.         unsigned long size;
  108.     } s;
  109. #ifdef Kelvdebug
  110.     long l[2];
  111. #endif
  112. };
  113.   
  114. typedef union header HEADER;
  115. #define NULLHDR (HEADER HUGE *)NULL
  116.   
  117. #define ABLKSIZE        (sizeof (HEADER))
  118.   
  119. static HEADER HUGE *morecore __ARGS((unsigned nu));
  120.   
  121. static HEADER Base;
  122. static HEADER HUGE *Allocp = NULLHDR;
  123. static unsigned long Heapsize;
  124.   
  125. static int freecore __ARGS((HEADER HUGE *p));
  126. static void freeheap __ARGS((HEADER HUGE *p));
  127.   
  128. #ifdef Kelvdebug
  129. #define MARKER          0x766c654bL /* Kelv in reverse */
  130. #endif
  131.   
  132. /* Allocate block of 'nb' bytes */
  133. void *
  134. malloc(nb)
  135. unsigned nb;
  136. {
  137.     register HEADER HUGE *p, HUGE *q;
  138.     register unsigned nu;
  139.     int i;
  140.   
  141.     if(!istate())
  142.         Intalloc++;
  143.     if(nb == 0)
  144.         return NULL;
  145.   
  146.     /* Record the size of this request */
  147.     if((i = log2(nb)) >= 0)
  148.         Sizes[i]++;
  149.   
  150. #ifndef Kelvdebug
  151.     /* Round up to full block, then add one for header */
  152.   
  153.     nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 2;      /* force allocated memory  */
  154.     nu &= 0xfffffffeL;                              /* to be on offset 0x0008 */
  155. #else
  156.     /* Round up to full block, then add one for header and one for debug */
  157.   
  158.     nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 4;      /* force allocated memory  */
  159.     nu &= 0xfffffffeL;                              /* to be on offset 0x0008 */
  160. #endif
  161.   
  162.     if ((q = Allocp) == NULLHDR){
  163.         Base.s.ptr = Allocp = q = &Base;
  164.         Base.s.size = 1;
  165.     }
  166.   
  167. #ifdef notdef
  168.     if(Efficient) {
  169.         Allocp = q = &Base;     /* Start at the very beginning again */
  170.     }
  171. #endif
  172.   
  173.     for (p = q->s.ptr; ; q = p, p = p->s.ptr){
  174.         if (p->s.size >= nu){
  175.             /* This chunk is at least as large as we need */
  176.             if (p->s.size <= nu + 1){
  177.                 /* This is either a perfect fit (size == nu)
  178.                  * or the free chunk is just one unit larger.
  179.                  * In either case, alloc the whole thing,
  180.                  * because there's no point in keeping a free
  181.                  * block only large enough to hold the header.
  182.                  */
  183.                 q->s.ptr = p->s.ptr;
  184.             } else {
  185.                 /* Carve out piece from end of entry */
  186.                 p->s.size -= nu;
  187.                 p += p->s.size;
  188.                 p->s.size = nu;
  189.             }
  190.             p->s.ptr = p;   /* for auditing */
  191. #ifdef Kelvdebug
  192.             p->l[(p->s.size * 2) - 2] = (long)p;    /* debug */
  193.             p->l[(p->s.size * 2) - 1] = MARKER;     /* debug */
  194. #endif
  195.             Allocs++;
  196.             Availmem -= p->s.size;
  197.             p++;
  198. #ifdef  LARGEDATA
  199.             /* On the brain-damaged Intel CPUs in
  200.              * "large data" model, make sure the offset field
  201.              * in the pointer we return isn't null.
  202.              * The Turbo C compiler and certain
  203.              * library functions like strrchr() assume this.
  204.              */
  205.             if(FP_OFF(p) == 0){
  206.                 /* Return denormalized but equivalent pointer */
  207.                 return (void *)MK_FP(FP_SEG(p)-1,16);
  208.             }
  209. #endif
  210.             return (void *)p;
  211.         }
  212.         if (p == Allocp && ((p = morecore(nu)) == NULLHDR)){
  213.             Memfail++;
  214.             return NULL;
  215.         }
  216.     }
  217. }
  218. /* Get more memory from the system and put it on the heap */
  219. static HEADER HUGE *
  220. morecore(nu)
  221. unsigned nu;
  222. {
  223.     char HUGE *cp;
  224.     HEADER HUGE *up;
  225.   
  226.     Morecores++;
  227.     if ((int)(cp = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1){
  228.         if(Memdebug) {
  229.             log(-1,"morecore: Failure requesting %lu (coreleft %lu)",
  230.             nu * ABLKSIZE,coreleft());
  231.             logstat();
  232.         }
  233.         return NULLHDR;
  234.     }
  235.   
  236.     up = (HEADER *)cp;
  237.     up->s.size = nu;
  238.     up->s.ptr = up; /* satisfy audit */
  239. #ifdef Kelvdebug
  240.     up->l[(up->s.size * 2) - 2] = (long)up;         /* satisfy debug */
  241.     up->l[(up->s.size * 2) - 1] = MARKER;           /* satisfy debug */
  242. #endif
  243.     /* free it to our internal heap for use */
  244.     freeheap(up);
  245.     Heapsize += nu*ABLKSIZE;
  246.     return Allocp;
  247. }
  248.   
  249. /* Put memory block back on heap or back onto system core */
  250. void
  251. free(blk)
  252. void *blk;
  253. {
  254.     HEADER HUGE *p;
  255.     unsigned short HUGE *ptr;
  256.   
  257.     if(!istate())
  258.         Intfree++;
  259.     if(blk == NULL)
  260.         return;         /* Required by ANSI */
  261.     p = (HEADER HUGE *)blk - 1;
  262.     /* Audit check */
  263.     if(p->s.ptr != p){
  264.         ptr = (unsigned short *)&blk;
  265.         printf(freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
  266.         fflush(stdout);
  267. #ifdef STKTRACE
  268.         stktrace();
  269. #endif
  270.         Invalid++;
  271.         log(-1,freewarn,freewarn1,blk,ptr[-1],ptr[-2],Curproc->name,' ');
  272.         logstat();
  273.         return;
  274.     }
  275. #ifdef Kelvdebug
  276.     if(p->l[(p->s.size * 2) - 2] != (long)p || p->l[(p->s.size * 2) - 1] != MARKER){
  277.         ptr = (unsigned short *)&blk;
  278.         printf(freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,'\n');
  279.         fflush(stdout);
  280.         Overuse++;
  281.         log(-1,freewarn,freewarn2,blk,ptr[-1],ptr[-2],Curproc->name,' ');
  282.         logstat();
  283.         return;
  284.     }
  285. #endif
  286.   
  287.     Frees++;
  288.   
  289.     /* if we can add this to the core, we're done
  290.      * else add to our internal heap
  291.      */
  292.     if(!freecore(p))
  293.         freeheap(p);
  294.   
  295.     if(Memwait != 0)
  296.         psignal(&Memwait,0);
  297. }
  298.   
  299. /* Put memory block back on interal heap */
  300. void freeheap(HEADER HUGE *p) {
  301.     HEADER HUGE *q;
  302.   
  303.     Availmem += p->s.size;
  304.     /* Search the free list looking for the right place to insert */
  305.     for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
  306.         /* Highest address on circular list? */
  307.         if(q >= q->s.ptr && (p > q || p < q->s.ptr))
  308.             break;
  309.     }
  310.     if(p + p->s.size == q->s.ptr){
  311.         /* Combine with front of this entry */
  312.         p->s.size += q->s.ptr->s.size;
  313.         p->s.ptr = q->s.ptr->s.ptr;
  314.     } else {
  315.         /* Link to front of this entry */
  316.         p->s.ptr = q->s.ptr;
  317.     }
  318.     if(q + q->s.size == p){
  319.         /* Combine with end of this entry */
  320.         q->s.size += p->s.size;
  321.         q->s.ptr = p->s.ptr;
  322.     } else {
  323.         /* Link to end of this entry */
  324.         q->s.ptr = p;
  325.     }
  326. }
  327.   
  328. /* Put memory block back on system core if it fits */
  329. int freecore(HEADER HUGE *p) {
  330.     unsigned long backto, backcnt;
  331.     int backed;
  332.   
  333.     if ((char HUGE *)_brklvl <= (char HUGE *)(p + p->s.size)) {
  334.         backcnt = backto = (p->s.size * ABLKSIZE);
  335.         do  {
  336.             backed = (backcnt < 32767) ? backcnt : 32767;
  337.             sbrk (-1 * backed);
  338.             backcnt -= backed;
  339.         } while (backcnt);
  340.         ReallocSys++;
  341.         return 1;
  342.     }
  343.     return 0;
  344. }
  345.   
  346. #ifdef  notdef  /* Not presently used */
  347. /* Move existing block to new area */
  348. void *
  349. realloc(area,size)
  350. void *area;
  351. unsigned size;
  352. {
  353.     unsigned osize;
  354.     HEADER HUGE *hp;
  355.     char HUGE *cp;
  356.   
  357.     hp = ((HEADER *)area) - 1;
  358.     osize = (hp->s.size -1) * ABLKSIZE;
  359.   
  360.     free(area);     /* Hopefully you have your interrupts off , Phil. */
  361.     if((cp = malloc(size)) != NULL && cp != area)
  362.         memcpy((char *)cp,(char *)area,size>osize? osize : size);
  363.     return cp;
  364. }
  365. #endif
  366.   
  367. /* Allocate block of cleared memory */
  368. void *
  369. calloc(nelem,size)
  370. unsigned nelem; /* Number of elements */
  371. unsigned size;  /* Size of each element */
  372. {
  373.     register unsigned i;
  374.     register char *cp;
  375.   
  376.     i = nelem * size;
  377.     if((cp = malloc(i)) != NULL)
  378.         memset(cp,0,i);
  379.     return cp;
  380. }
  381.   
  382. /* Version of malloc() that waits if necessary for memory to become available */
  383. void *
  384. mallocw(nb)
  385. unsigned nb;
  386. {
  387.     register void *p;
  388.   
  389.     while((p = malloc(nb)) == NULL){
  390.         Memwait++;
  391.         pwait(&Memwait);
  392.         Memwait--;
  393.     }
  394.     return p;
  395. }
  396.   
  397. /* Version of calloc that waits if necessary for memory to become available */
  398. void *
  399. callocw(nelem,size)
  400. unsigned nelem; /* Number of elements */
  401. unsigned size;  /* Size of each element */
  402. {
  403.     register unsigned i;
  404.     register char *cp;
  405.   
  406.     i = nelem * size;
  407.     cp = mallocw(i);
  408.     memset(cp,0,i);
  409.     return cp;
  410. }
  411.   
  412. /* Return available memory on our heap plus available system memory */
  413. unsigned long
  414. availmem()
  415. {
  416.     return Availmem * ABLKSIZE + coreleft();
  417. }
  418.   
  419. /* Log heap stats */
  420. static int
  421. logstat(void)
  422. {
  423.     if(Memdebug){
  424.         log(-1,"Memory status:");
  425.         log(-1,HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
  426.         100L*Availmem*ABLKSIZE/Heapsize,Morecores,coreleft());
  427.         log(-1,AllocStr,Allocs,Frees,Allocs-Frees,ReallocSys,Memfail,Invalid,Overuse);
  428.         log(-1,GarbageStr,Yellows,Reds);
  429. #ifdef notdef
  430.         log(-1,EfficientStr,Efficient,Memthresh);
  431. #endif
  432.         log(-1,EfficientStr,Memthresh);
  433.         log(-1,InterruptStr,Intalloc,Intfree);
  434.     }
  435.   
  436.     return 0;
  437. }
  438.   
  439. /* Print heap stats */
  440. int
  441. dostat(argc,argv,envp)
  442. int argc;
  443. char *argv[];
  444. void *envp;
  445. {
  446. #ifdef EMS
  447.     unsigned int emssize;
  448. #endif
  449. #ifdef XMS
  450.     long XMS_Ret;
  451. #endif
  452.   
  453.     tprintf(HeapSizeStr,Heapsize,Availmem*ABLKSIZE, \
  454.     100L*Availmem*ABLKSIZE/Heapsize,Morecores,coreleft());
  455.     tputc('\n');
  456.     tprintf(AllocStr,Allocs,Frees,Allocs-Frees,ReallocSys,Memfail,Invalid,Overuse);
  457.     tputc('\n');
  458.     tprintf(Threshold,Memthresh);
  459.     tprintf(GarbageStr,Yellows,Reds);
  460.     tputc('\n');
  461.     tprintf(InterruptStr,Intalloc,Intfree);
  462.     iqstat();
  463.   
  464. #ifdef EMS
  465.     if(EMS_Available) {
  466.         if(ememmax(&emssize) == 0)
  467.             tprintf("EMS: %u bytes contiguous available.\n",emssize);
  468.     }
  469. #endif
  470.   
  471. #ifdef XMS
  472.     if(XMS_Available) {
  473.         if((XMS_Ret = Total_XMS()) > 0L) {
  474.             tprintf("XMS: total %u KB, largest block: %u KB\n",
  475.             (unsigned) XMS_Ret, Query_XMS());
  476.         }
  477.     }
  478. #endif
  479.   
  480.     return 0;
  481. }
  482.   
  483. /* Print heap free list */
  484. static int
  485. dofreelist(argc,argv,envp)
  486. int argc;
  487. char *argv[];
  488. void *envp;
  489. {
  490.     HEADER HUGE *p;
  491.     int i = 0;
  492.   
  493.     for(p = Base.s.ptr;p !=(HEADER HUGE *) &Base;p = p->s.ptr){
  494.         tprintf("%4.4x %6lu",FP_SEG(p),p->s.size * ABLKSIZE);
  495.         if(++i == 5){
  496.             i = 0;
  497.             if(tputc('\n') == EOF)
  498.                 return 0;
  499.         } else
  500.             tputs(" | ");
  501.     }
  502.     if(i != 0)
  503.         tputc('\n');
  504.     return 0;
  505. }
  506.   
  507. static int
  508. dosizes(argc,argv,p)
  509. int argc;
  510. char *argv[];
  511. void *p;
  512. {
  513.     int i;
  514.   
  515.     for(i=0;i<16;i += 4){
  516.         tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
  517.         1<<i,Sizes[i], 2<<i,Sizes[i+1],
  518.         4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
  519.     }
  520.     return 0;
  521. }
  522.   
  523. int
  524. domem(argc,argv,p)
  525. int argc;
  526. char *argv[];
  527. void *p;
  528. {
  529.     if(argc == 1)
  530.         return dostat(0,NULL,NULL);
  531.   
  532.     return subcmd(Memcmds,argc,argv,p);
  533. }
  534.   
  535. static int
  536. dothresh(argc,argv,p)
  537. int argc;
  538. char *argv[];
  539. void *p;
  540. {
  541.     return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
  542. }
  543.   
  544. static int
  545. donibufs(argc,argv,p)
  546. int argc;
  547. char *argv[];
  548. void *p;
  549. {
  550.     if(setint(&Nibufs,"Interrupt pool buffers",argc,argv) == 0){
  551.         iqclear();
  552.         return 0;
  553.     }
  554.     return 1;
  555. }
  556.   
  557. static int
  558. doibufsize(argc,argv,p)
  559. int argc;
  560. char *argv[];
  561. void *p;
  562. {
  563.     return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
  564. }
  565.   
  566. void
  567. gcollect(i,v1,v2)
  568. int i;          /* Args not used */
  569. void *v1;
  570. void *v2;
  571. {
  572.     void (**fp)(int);
  573.     int red;
  574.   
  575.     for(;;){
  576.         pause(1000L);   /* Run every second */
  577. #ifdef CONVERS
  578.         {
  579.             extern void check_buffer_overload(void);
  580.             check_buffer_overload();
  581.         }
  582. #endif
  583.         /* If memory is low, collect some garbage. If memory is VERY
  584.          * low, invoke the garbage collection routines in "red" mode.
  585.          */
  586.         if(availmem() < Memthresh){
  587.             if(availmem() < Memthresh/2){
  588.                 red = 1;
  589.                 Reds++;
  590.             } else {
  591.                 red = 0;
  592.                 Yellows++;
  593.             }
  594.             for(fp = Gcollect;*fp != NULL;fp++)
  595.                 (**fp)(red);
  596.         }
  597.         {
  598.         /* See if the last block on our heap fits 'underneath' the system core.
  599.          * if so, free it to the core ...
  600.          */
  601.             HEADER HUGE *p, *last;
  602.             char HUGE *calc;
  603.             unsigned long backto, backcnt;
  604.             int backed;
  605.   
  606.             last = 0;
  607.             for (p = Base.s.ptr; p->s.ptr != &Base; p = p->s.ptr)
  608.                 last = p;
  609.             if (!last)
  610.                 continue;
  611.             calc = (char HUGE *)(p + p->s.size);
  612.             if ((char HUGE *)_brklvl <= calc)     {
  613.                 backcnt = backto = (p->s.size * ABLKSIZE);
  614.                 do  {
  615.                     backed = (backcnt < 32767) ? backcnt : 32767;
  616.                     sbrk (-1 * backed);
  617.                     backcnt -= backed;
  618.                 } while (backcnt);
  619.                 Heapsize -= backto;
  620.                 Availmem -= p->s.size;
  621.                 last->s.ptr = &Base;
  622.                 ReallocSys++;
  623.             }
  624.         }
  625.     }
  626. }
  627.   
  628. #ifdef notdef
  629.   
  630. static int
  631. doefficient(argc,argv,p)
  632. int argc;
  633. char *argv[];
  634. void *p;
  635. {
  636.     return setbool(&Efficient,"Efficient/slower mode",argc,argv);
  637. }
  638. #endif
  639.   
  640. static int
  641. domemdebug(argc,argv,p)
  642. int argc;
  643. char *argv[];
  644. void *p;
  645. {
  646.     return setbool(&Memdebug,"\"Mem stat\" to log after failures",argc,argv);
  647. }
  648.   
  649. #ifdef MULTITASK
  650. static int
  651. dominheap(argc,argv,p)
  652. int argc;
  653. char *argv[];
  654. void *p;
  655. {
  656.     return setuns(&Minheap,"Minimum free heap when shelled out",argc,argv);
  657. }
  658. #endif
  659.