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