home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR3 / KA9Q212.ZIP / ALLOC.C < prev    next >
C/C++ Source or Header  |  1993-07-16  |  10KB  |  430 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.  
  11. /****************************************************************************
  12. *    $Id: alloc.c 1.3 93/07/16 11:41:34 ROOT_DOS Exp $
  13. *    13 Jul 93    1.2        GT    Fix warnings.                                    *
  14. ****************************************************************************/
  15.  
  16. #include <stdio.h>
  17. #include <dos.h>
  18. #include <alloc.h>
  19. #include "global.h"
  20. #include "mbuf.h"
  21. #include "proc.h"
  22. #include "cmdparse.h"
  23. #include "config.h"
  24.  
  25. static unsigned long Memfail;    /* Count of allocation failures */
  26. static unsigned long Allocs;    /* Total allocations */
  27. static unsigned long Frees;    /* Total frees */
  28. static unsigned long Invalid;    /* Total calls to free with garbage arg */
  29. static unsigned long Intalloc;    /* Calls to malloc with ints disabled */
  30. static unsigned long Intfree;    /* Calls to free with ints disabled */
  31. static int Memwait;        /* Number of tasks waiting for memory */
  32. static unsigned long Yellows;    /* Yellow alert garbage collections */
  33. static unsigned long Reds;    /* Red alert garbage collections */
  34. unsigned long Availmem;        /* Heap memory, ABLKSIZE units */
  35. static unsigned long Morecores;
  36. #ifdef MULTITASK
  37. unsigned Minheap = 16 * 1024;    /* Min free heap when shelling out */
  38. #endif
  39.  
  40. static unsigned long Sizes[16];
  41.  
  42. static int dostat __ARGS((int argc,char *argv[],void *p));
  43. static int dofreelist __ARGS((int argc,char *argv[],void *p));
  44. static int doibufsize __ARGS((int argc,char *argv[],void *p));
  45. static int donibufs __ARGS((int argc,char *argv[],void *p));
  46. static int dothresh __ARGS((int argc,char *argv[],void *p));
  47. static int dosizes __ARGS((int argc,char *argv[],void *p));
  48. static int dominheap __ARGS((int argc,char *argv[],void *p));
  49.  
  50. struct cmds Memcmds[] = {
  51.     { "freelist",    dofreelist,    0, 0, NULLCHAR },
  52.     { "ibufsize",    doibufsize,    0, 0, NULLCHAR },
  53. #ifdef MULTITASK
  54.  {    "minheap",  dominheap,  0, 0, NULLCHAR },
  55. #endif
  56.     { "nibufs",    donibufs,    0, 0, NULLCHAR },
  57.     { "sizes",    dosizes,    0, 0, NULLCHAR },
  58.     { "status",    dostat,        0, 0, NULLCHAR },
  59.     { "thresh",    dothresh,    0, 0, NULLCHAR },
  60.     { NULLCHAR },
  61. };
  62.  
  63. #ifdef    LARGEDATA
  64. #define    HUGE    huge
  65. #else
  66. #define    HUGE
  67. #endif
  68.  
  69. union header {
  70.     struct {
  71.         union header HUGE *ptr;
  72.         unsigned long size;
  73.     } s;
  74.     long l[2];
  75. };
  76.  
  77. typedef union header HEADER;
  78. #define    NULLHDR    (HEADER HUGE *)NULL
  79.  
  80. #define    ABLKSIZE    (sizeof (HEADER))
  81.  
  82. static HEADER HUGE *morecore __ARGS((unsigned nu));
  83.  
  84. static HEADER Base;
  85. static HEADER HUGE *Allocp = NULLHDR;
  86. static unsigned long Heapsize;
  87.  
  88. /* Allocate block of 'nb' bytes */
  89. void *
  90. malloc(nb)
  91. unsigned nb;
  92. {
  93.     register HEADER HUGE *p, HUGE *q;
  94.     register unsigned nu;
  95.     int i;
  96.  
  97.     if(!istate())
  98.         Intalloc++;
  99.     if(nb == 0)
  100.         return NULL;
  101.  
  102.     /* Record the size of this request */
  103.     if((i = log2(nb)) >= 0)
  104.         Sizes[i]++;
  105.     
  106.     /* Round up to full block, then add one for header */
  107.     nu = ((nb + ABLKSIZE - 1) / ABLKSIZE) + 1;
  108.     if((q = Allocp) == NULLHDR){
  109.         Base.s.ptr = Allocp = q = &Base;
  110.         Base.s.size = 1;
  111.     }
  112.     for(p = q->s.ptr; ; q = p, p = p->s.ptr){
  113.         if(p->s.size >= nu){
  114.             /* This chunk is at least as large as we need */
  115.             if(p->s.size <= nu + 1){
  116.                 /* This is either a perfect fit (size == nu)
  117.                  * or the free chunk is just one unit larger.
  118.                  * In either case, alloc the whole thing,
  119.                  * because there's no point in keeping a free
  120.                  * block only large enough to hold the header.
  121.                  */
  122.                 q->s.ptr = p->s.ptr;
  123.             } else {
  124.                 /* Carve out piece from end of entry */
  125.                 p->s.size -= nu;
  126.                 p += p->s.size;
  127.                 p->s.size = nu;
  128.             }
  129. #ifdef    circular
  130.             Allocp = q;
  131. #endif
  132.             p->s.ptr = p;    /* for auditing */
  133.             Allocs++;
  134.             Availmem -= p->s.size;
  135.             p++;
  136.             break;
  137.         }
  138.         if(p == Allocp && ((p = morecore(nu)) == NULLHDR)){
  139.             Memfail++;
  140.             break;
  141.         }
  142.     }
  143. #ifdef    LARGEDATA
  144.     /* On the brain-damaged Intel CPUs in "large data" model,
  145.      * make sure the pointer's offset field isn't null
  146.      * (unless the entire pointer is null).
  147.      * The Turbo C compiler and certain
  148.      * library functions like strrchr() assume this.
  149.      */
  150.     if(FP_OFF(p) == 0 && FP_SEG(p) != 0){
  151.         /* Return denormalized but equivalent pointer */
  152.         return (void *)MK_FP(FP_SEG(p)-1,16);
  153.     }
  154. #endif
  155.     return (void *)p;
  156. }
  157. /* Get more memory from the system and put it on the heap */
  158. static HEADER HUGE *
  159. morecore(nu)
  160. unsigned nu;
  161. {
  162.     register char HUGE *cp;
  163.     register HEADER HUGE *up;
  164.  
  165.     Morecores++;
  166.     if ((int)(cp = (char HUGE *)sbrk(nu * ABLKSIZE)) == -1)
  167.         return NULLHDR;
  168.     up = (HEADER *)cp;
  169.     up->s.size = nu;
  170.     up->s.ptr = up;    /* satisfy audit */
  171.     free((void *)(up + 1));
  172.     Heapsize += nu*ABLKSIZE;
  173.     Frees--;    /* Nullify increment inside free() */
  174.     return Allocp;
  175. }
  176.  
  177. /* Put memory block back on heap */
  178. void
  179. free(blk)
  180. void *blk;
  181. {
  182.     register HEADER HUGE *p, HUGE *q;
  183.     unsigned short HUGE *ptr;
  184.  
  185.     if(!istate())
  186.         Intfree++;
  187.     if(blk == NULL)
  188.         return;        /* Required by ANSI */
  189.     p = (HEADER HUGE *)blk - 1;
  190.     /* Audit check */
  191.     if(p->s.ptr != p){
  192.         ptr = (unsigned short *)&blk;
  193.         printf("free: WARNING! invalid pointer (0x%lx) pc = 0x%x %x proc %s\n",ptol(blk),
  194.          ptr[-1],ptr[-2],Curproc->name);
  195.         Invalid++;
  196.         log(-1,"free: WARNING! invalid pointer (0x%lx) pc = 0x%x %x proc %s\n",ptol(blk),
  197.          ptr[-1],ptr[-2],Curproc->name);
  198.         return;
  199.     }
  200.     Availmem += p->s.size;
  201.     /* Search the free list looking for the right place to insert */
  202.     for(q = Allocp; !(p > q && p < q->s.ptr); q = q->s.ptr){
  203.         /* Highest address on circular list? */
  204.         if(q >= q->s.ptr && (p > q || p < q->s.ptr))
  205.             break;
  206.     }
  207.     if(p + p->s.size == q->s.ptr){
  208.         /* Combine with front of this entry */
  209.         p->s.size += q->s.ptr->s.size;
  210.         p->s.ptr = q->s.ptr->s.ptr;
  211.     } else {
  212.         /* Link to front of this entry */
  213.         p->s.ptr = q->s.ptr;
  214.     }
  215.     if(q + q->s.size == p){
  216.         /* Combine with end of this entry */
  217.         q->s.size += p->s.size;
  218.         q->s.ptr = p->s.ptr;
  219.     } else {
  220.         /* Link to end of this entry */
  221.         q->s.ptr = p;
  222.     }
  223. #ifdef    circular
  224.     Allocp = q;
  225. #endif
  226.     Frees++;
  227.     if(Memwait != 0)
  228.         psignal(&Memwait,0);
  229. }
  230.  
  231. #ifdef    notdef    /* Not presently used */
  232. /* Move existing block to new area */
  233. void *
  234. realloc(area,size)
  235. void *area;
  236. unsigned size;
  237. {
  238.     unsigned osize;
  239.     HEADER HUGE *hp;
  240.     char HUGE *cp;
  241.  
  242.     hp = ((HEADER *)area) - 1;
  243.     osize = (hp->s.size -1) * ABLKSIZE;
  244.  
  245.     free(area);
  246.     if((cp = malloc(size)) != NULL && cp != area)
  247.         memcpy((char *)cp,(char *)area,size>osize? osize : size);
  248.     return cp;
  249. }
  250. #endif
  251. /* Allocate block of cleared memory */
  252. void *
  253. calloc(nelem,size)
  254. unsigned nelem;    /* Number of elements */
  255. unsigned size;    /* Size of each element */
  256. {
  257.     register unsigned i;
  258.     register char *cp;
  259.  
  260.     i = nelem * size;
  261.     if((cp = malloc(i)) != NULL)
  262.         memset(cp,0,i);
  263.     return cp;
  264. }
  265. /* Version of malloc() that waits if necessary for memory to become available */
  266. void *
  267. mallocw(nb)
  268. unsigned nb;
  269. {
  270.     register void *p;
  271.  
  272.     while((p = malloc(nb)) == NULL){
  273.         Memwait++;
  274.         pwait(&Memwait);
  275.         Memwait--;
  276.     }
  277.     return p;
  278. }
  279. /* Version of calloc that waits if necessary for memory to become available */
  280. void *
  281. callocw(nelem,size)
  282. unsigned nelem;    /* Number of elements */
  283. unsigned size;    /* Size of each element */
  284. {
  285.     register unsigned i;
  286.     register char *cp;
  287.  
  288.     i = nelem * size;
  289.     cp = mallocw(i);
  290.     memset(cp,0,i);
  291.     return cp;
  292. }
  293. /* Return available memory on our heap plus available system memory */
  294. unsigned long
  295. availmem()
  296. {
  297.     return Availmem * ABLKSIZE + coreleft();
  298. }
  299.  
  300. /* Print heap stats */
  301. static int
  302. dostat(argc,argv,envp)
  303. int argc;
  304. char *argv[];
  305. void *envp;
  306. {
  307.     tprintf("heap size %lu avail %lu (%lu%%) morecores %lu coreleft %lu\n",
  308.      Heapsize,Availmem * ABLKSIZE,100L*Availmem*ABLKSIZE/Heapsize,
  309.      Morecores,coreleft());
  310.     tprintf("allocs %lu frees %lu (diff %lu) alloc fails %lu invalid frees %lu\n",
  311.         Allocs,Frees,Allocs-Frees,Memfail,Invalid);
  312.     tprintf("interrupts-off calls to malloc %lu free %lu\n",Intalloc,Intfree);
  313.     tprintf("garbage collections yellow %lu red %lu\n",Yellows,Reds);
  314.     iqstat();
  315.     return 0;
  316. }
  317.  
  318. /* Print heap free list */
  319. static int
  320. dofreelist(argc,argv,envp)
  321. int argc;
  322. char *argv[];
  323. void *envp;
  324. {
  325.     HEADER HUGE *p;
  326.     int i = 0;
  327.  
  328.     for(p = Base.s.ptr;p != (HEADER HUGE *) &Base;p = p->s.ptr){
  329.         tprintf("%5lx %6lu",ptol((void *)p),p->s.size * ABLKSIZE);
  330.         if(++i == 4){
  331.             i = 0;
  332.             if(tprintf("\n") == EOF)
  333.                 return 0;
  334.         } else
  335.             tprintf(" | ");
  336.     }
  337.     if(i != 0)
  338.         tprintf("\n");
  339.     return 0;
  340. }
  341. static int
  342. dosizes(argc,argv,p)
  343. int argc;
  344. char *argv[];
  345. void *p;
  346. {
  347.     int i;
  348.  
  349.     for(i=0;i<16;i += 4){
  350.         tprintf("N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld| N>=%5u:%7ld\n",
  351.          1<<i,Sizes[i],    2<<i,Sizes[i+1],
  352.          4<<i,Sizes[i+2],8<<i,Sizes[i+3]);
  353.     }
  354.     return 0;
  355. }
  356. int
  357. domem(argc,argv,p)
  358. int argc;
  359. char *argv[];
  360. void *p;
  361. {
  362.     return subcmd(Memcmds,argc,argv,p);
  363. }
  364.  
  365. static int
  366. donibufs(argc,argv,p)
  367. int argc;
  368. char *argv[];
  369. void *p;
  370. {
  371.     return setint(&Nibufs,"Interrupt pool buffers",argc,argv);
  372. }
  373. static int
  374. doibufsize(argc,argv,p)
  375. int argc;
  376. char *argv[];
  377. void *p;
  378. {
  379.     return setuns(&Ibufsize,"Interrupt buffer size",argc,argv);
  380. }
  381.  
  382. static int
  383. dothresh(argc,argv,p)
  384. int argc;
  385. char *argv[];
  386. void *p;
  387. {
  388.     return setlong(&Memthresh,"Free memory threshold (bytes)",argc,argv);
  389. }
  390.  
  391. /* Background memory compactor, used when memory runs low */
  392. void
  393. gcollect(i,v1,v2)
  394. int i;    /* Args not used */
  395. void *v1;
  396. void *v2;
  397. {
  398.     void (**fp)(int colour);
  399.     int red;
  400.  
  401.     for(;;){
  402.         pause(1000L);    /* Run every second */
  403.         /* If memory is low, collect some garbage. If memory is VERY
  404.          * low, invoke the garbage collection routines in "red" mode.
  405.          */
  406.         if(availmem() < Memthresh){
  407.             if(availmem() < Memthresh/2){
  408.                 red = 1;
  409.                 Reds++;
  410.             } else {
  411.                 red = 0;
  412.                 Yellows++;
  413.             }
  414.             for(fp = Gcollect;*fp != NULL;fp++)
  415.                 (**fp)(red);
  416.         }
  417.     }
  418. }
  419.  
  420. #ifdef MULTITASK
  421. static int
  422. dominheap(argc,argv,p)
  423. int argc;
  424. char *argv[];
  425. void *p;
  426. {
  427.     return setuns(&Minheap,"Minimum free heap when shelled out",argc,argv);
  428. }
  429. #endif
  430.