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