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