home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v92.tgz / v92.tar / v92 / src / runtime / ralc.r < prev    next >
Text File  |  1996-03-22  |  19KB  |  841 lines

  1. /*
  2.  * File: ralc.r
  3.  *  Contents: allocation routines
  4.  */
  5.  
  6. /*
  7.  * Prototypes.
  8.  */
  9. hidden struct region *findgap    Params((struct region *curr, word nbytes));
  10. hidden struct region *newregion    Params((word nbytes, word stdsize));
  11.  
  12. extern word alcnum;
  13.  
  14. #ifndef MultiThread
  15. word coexp_ser = 2;    /* serial numbers for co-expressions; &main is 1 */
  16. word list_ser = 1;    /* serial numbers for lists */
  17. word set_ser = 1;    /* serial numbers for sets */
  18. word table_ser = 1;    /* serial numbers for tables */
  19. #endif                    /* MultiThread */
  20.  
  21. /*
  22.  * Note: function calls beginning with "MM" are just empty macros
  23.  * unless EventMon is defined.
  24.  */
  25.  
  26. /*
  27.  * AlcBlk - allocate a block.
  28.  */
  29. #begdef AlcBlk(var, struct_nm, t_code, nbytes)
  30. {
  31.    struct region *rp = NULL;
  32.  
  33. #ifdef MultiThread
  34.    MMAlc((word)nbytes,t_code);
  35. #endif                    /* MultiThread */
  36.  
  37.    /*
  38.     * Ensure that there is enough room in the block region.
  39.     */
  40.    if (DiffPtrs(blkend,blkfree) < nbytes && !reserve(Blocks, nbytes))
  41.       return NULL;
  42.  
  43.    /*
  44.     * If monitoring, show the allocation.
  45.     */
  46. #ifndef MultiThread
  47.    MMAlc((word)nbytes,t_code);
  48. #endif
  49.  
  50.    /*
  51.     * Decrement the free space in the block region by the number of bytes
  52.     *  allocated and return the address of the first byte of the allocated
  53.     *  block.
  54.     */
  55.    blktotal += nbytes;
  56.    var = (struct struct_nm *)blkfree;
  57.    blkfree += nbytes;
  58.    var->title = t_code;
  59. }
  60. #enddef
  61.  
  62. /*
  63.  * AlcFixBlk - allocate a fixed length block.
  64.  */
  65. #define AlcFixBlk(var, struct_nm, t_code)\
  66.    AlcBlk(var, struct_nm, t_code, sizeof(struct struct_nm))
  67.  
  68. /*
  69.  * AlcVarBlk - allocate a variable-length block.
  70.  */
  71. #begdef AlcVarBlk(var, struct_nm, t_code, n_desc)
  72.    {
  73.    register uword size;
  74.  
  75.    /*
  76.     * Variable size blocks are declared with one descriptor, thus
  77.     *  we need add in only n_desc - 1 descriptors.
  78.     */
  79.    size = sizeof(struct struct_nm) + (n_desc - 1) * sizeof(struct descrip);
  80.    AlcBlk(var, struct_nm, t_code, size)
  81.    var->blksize = size;
  82.    }
  83. #enddef
  84.  
  85. /*
  86.  * alcactiv - allocate a co-expression activation block.
  87.  */
  88.  
  89. struct astkblk *alcactiv()
  90.    {
  91.    struct astkblk *abp;
  92.  
  93.    abp = (struct astkblk *)malloc((msize)sizeof(struct astkblk));
  94.  
  95.    /*
  96.     * If malloc failed, attempt to free some co-expression blocks and retry.
  97.     */
  98.    if (abp == NULL) {
  99.       collect(Static);
  100.       abp = (struct astkblk *)malloc((msize)sizeof(struct astkblk));
  101.       }
  102.  
  103.    if (abp == NULL)
  104.       ReturnErrNum(305, NULL);
  105.    abp->nactivators = 0;
  106.    abp->astk_nxt = NULL;
  107.    return abp;
  108.    }
  109.  
  110. #ifdef LargeInts
  111. /*
  112.  * alcbignum - allocate an n-digit bignum in the block region
  113.  */
  114.  
  115. struct b_bignum *alcbignum(n)
  116. word n;
  117.    {
  118.    register struct b_bignum *blk;
  119.    register uword size;
  120.  
  121.    size = sizeof(struct b_bignum) + ((n - 1) * sizeof(DIGIT));
  122.    /* ensure whole number of words allocated */
  123.    size = (size + WordSize - 1) & -WordSize;
  124.    AlcBlk(blk, b_bignum, T_Lrgint, size);
  125.    blk->blksize = size;
  126.    blk->msd = blk->sign = 0;
  127.    blk->lsd = n - 1;
  128.    return blk;
  129.    }
  130. #endif                    /* LargeInts */
  131.  
  132. /*
  133.  * alccoexp - allocate a co-expression stack block.
  134.  */
  135.  
  136. #if COMPILER
  137. struct b_coexpr *alccoexp()
  138.    {
  139.    struct b_coexpr *ep;
  140.    static int serial = 2; /* main co-expression is allocated elsewhere */
  141.  
  142. #ifdef ATTM32
  143.    ep = (struct b_coexpr *)coexp_salloc(); /* 3B2/15/4000 stack */
  144. #else                                   /* ATTM32 */
  145.    ep = (struct b_coexpr *)malloc((msize)stksize);
  146. #endif                                  /* ATTM32 */
  147.  
  148.    /*
  149.     * If malloc failed or if there have been too many co-expression allocations
  150.     * since a collection, attempt to free some co-expression blocks and retry.
  151.     */
  152.  
  153.    if (ep == NULL || alcnum > AlcMax) {
  154.  
  155.       collect(Static);
  156.  
  157. #ifdef ATTM32           /* not needed, but here to play it safe */
  158.       ep = (struct b_coexpr *)coexp_salloc(); /* 3B2/15/4000 stack */
  159. #else                                   /* ATTM32 */
  160.       ep = (struct b_coexpr *)malloc((msize)stksize);
  161. #endif                                  /* ATTM32 */
  162.  
  163.       }
  164.  
  165.    if (ep == NULL)
  166.       ReturnErrNum(305, NULL);
  167.  
  168.    alcnum++;                    /* increment allocation count since last g.c. */
  169.  
  170.    ep->title = T_Coexpr;
  171.    ep->size = 0;
  172.    ep->id = serial++;
  173.    ep->nextstk = stklist;
  174.    ep->es_tend = NULL;
  175.    ep->file_name = "";
  176.    ep->line_num = 0;
  177.    ep->freshblk = nulldesc;
  178.    ep->es_actstk = NULL;
  179.    stklist = ep;
  180.    return ep;
  181.    }
  182. #else                    /* COMPILER */
  183. #ifdef MultiThread
  184. /*
  185.  * If this is a new program being loaded, an icodesize>0 gives the
  186.  * hdr.hsize and a stacksize to use; allocate
  187.  * sizeof(progstate) + icodesize + mstksize
  188.  * Otherwise (icodesize==0), allocate a normal stksize...
  189.  */
  190. struct b_coexpr *alccoexp(icodesize, stacksize)
  191. long icodesize, stacksize;
  192. #else                    /* MultiThread */
  193. struct b_coexpr *alccoexp()
  194. #endif                    /* MultiThread */
  195.  
  196.    {
  197.    struct b_coexpr *ep;
  198.  
  199. #ifdef MultiThread
  200.    if (icodesize>0) {
  201. #ifdef ATTM32
  202. Deliberate Syntax Error
  203. #else                    /* ATTM32 */
  204.       ep = (struct b_coexpr *)
  205.     calloc(1, (msize)(stacksize+
  206.                icodesize+
  207.                sizeof(struct progstate)+
  208.                sizeof(struct b_coexpr)));
  209. #endif                    /* ATTM32 */
  210.       }
  211.    else
  212. #endif                    /* MultiThread */
  213.  
  214. #ifdef ATTM32
  215.    ep = (struct b_coexpr *)coexp_salloc(); /* 3B2/15/4000 stack */
  216. #else                                   /* ATTM32 */
  217.    ep = (struct b_coexpr *)malloc((msize)stksize);
  218. #endif                                  /* ATTM32 */
  219.  
  220.    /*
  221.     * If malloc failed or if there have been too many co-expression allocations
  222.     * since a collection, attempt to free some co-expression blocks and retry.
  223.     */
  224.  
  225.    if (ep == NULL || alcnum > AlcMax) {
  226.  
  227.       collect(Static);
  228.  
  229. #ifdef MultiThread
  230.       if (icodesize>0) {
  231. #ifdef ATTM32
  232. Deliberate Syntax Error
  233. #else                    /* ATTM32 */
  234.          ep = (struct b_coexpr *)
  235.         malloc((msize)(mstksize+icodesize+sizeof(struct progstate)));
  236. #endif                    /* ATTM32 */
  237.          }
  238.       else
  239. #endif                    /* MultiThread */
  240.  
  241. #ifdef ATTM32
  242.      ep = (struct b_coexpr *)coexp_salloc(); /* 3B2/15/4000 stack */
  243. #else                                   /* ATTM32 */
  244.          ep = (struct b_coexpr *)malloc((msize)stksize);
  245. #endif                                  /* ATTM32 */
  246.       }
  247.       if (ep == NULL)
  248.          ReturnErrNum(305, NULL);
  249.  
  250.    alcnum++;        /* increment allocation count since last g.c. */
  251.  
  252.    ep->title = T_Coexpr;
  253.    ep->es_actstk = NULL;
  254.    ep->size = 0;
  255. #ifdef MultiThread
  256.    ep->es_pfp = NULL;
  257.    ep->es_gfp = NULL;
  258.    ep->es_argp = NULL;
  259.    ep->tvalloc = NULL;
  260.  
  261.    if (icodesize>0)
  262.       ep->id = 1;
  263.    else
  264. #endif                    /* MultiThread */
  265.       ep->id = coexp_ser++;
  266.    ep->nextstk = stklist;
  267.    ep->es_tend = NULL;
  268.  
  269. #ifdef MultiThread
  270.    /*
  271.     * Initialize program state to self for &main; curpstate for others.
  272.     */
  273.    if(icodesize>0) ep->program = (struct progstate *)(ep+1);
  274.    else ep->program = curpstate;
  275. #endif                    /* MultiThread */
  276.  
  277.    stklist = ep;
  278.    return ep;
  279.    }
  280. #endif                    /* COMPILER */
  281.  
  282. /*
  283.  * alccset - allocate a cset in the block region.
  284.  */
  285.  
  286. struct b_cset *alccset()
  287.    {
  288.    register struct b_cset *blk;
  289.    register int i;
  290.  
  291.    AlcFixBlk(blk, b_cset, T_Cset)
  292.    blk->size = -1;              /* flag size as not yet computed */
  293.  
  294.    /*
  295.     * Zero the bit array.
  296.     */
  297.    for (i = 0; i < CsetSize; i++)
  298.      blk->bits[i] = 0;
  299.    return blk;
  300.    }
  301.  
  302. /*
  303.  * alcfile - allocate a file block in the block region.
  304.  */
  305.  
  306. struct b_file *alcfile(fd, status, name)
  307. FILE *fd;
  308. int status;
  309. dptr name;
  310.    {
  311.    tended struct descrip tname = *name;
  312.    register struct b_file *blk;
  313.  
  314.    AlcFixBlk(blk, b_file, T_File)
  315.    blk->fd = fd;
  316.    blk->status = status;
  317.    blk->fname = tname;
  318.    return blk;
  319.    }
  320.  
  321. /*
  322.  * alchash - allocate a hashed structure (set or table header) in the block
  323.  *  region.
  324.  */
  325. union block *alchash(tcode)
  326. int tcode;
  327.    {
  328.    register int i;
  329.    register struct b_set *ps;
  330.    register struct b_table *pt;
  331.    word serial;
  332.  
  333.    if (tcode == T_Table) {
  334.       serial = table_ser++;
  335.       AlcFixBlk(pt, b_table, T_Table);
  336.       ps = (struct b_set *)pt;
  337.       }
  338.    else {    /* tcode == T_Set */
  339.       serial = set_ser++;
  340.       AlcFixBlk(ps, b_set, T_Set);
  341.       }
  342.    ps->size = 0;
  343.    ps->id = serial;
  344.    ps->mask = 0;
  345.    for (i = 0; i < HSegs; i++)
  346.       ps->hdir[i] = NULL;
  347.    return (union block *)ps;
  348.    }
  349.  
  350. /*
  351.  * alcsegment - allocate a slot block in the block region.
  352.  */
  353.  
  354. struct b_slots *alcsegment(nslots)
  355. word nslots;
  356.    {
  357.    uword size;
  358.    register struct b_slots *blk;
  359.  
  360.    size = sizeof(struct b_slots) + WordSize * (nslots - HSlots);
  361.    AlcBlk(blk, b_slots, T_Slots, size);
  362.    blk->blksize = size;
  363.    while (--nslots >= 0)
  364.       blk->hslots[nslots] = NULL;
  365.    return blk;
  366.    }
  367.  
  368. /*
  369.  * alclist - allocate a list header block in the block region.
  370.  *
  371.  *  Forces a g.c. if there's not enough room for the whole list.
  372.  */
  373.  
  374. struct b_list *alclist(size)
  375. uword size;
  376.    {
  377.    register struct b_list *blk;
  378.  
  379.    if (!reserve(Blocks, (word)(sizeof(struct b_list) + sizeof (struct b_lelem)
  380.       + (size - 1) * sizeof(struct descrip)))) return NULL;
  381.    AlcFixBlk(blk, b_list, T_List)
  382.    blk->size = size;
  383.    blk->id = list_ser++;
  384.    blk->listhead = NULL;
  385.    blk->listtail = NULL;
  386.    return blk;
  387.    }
  388.  
  389. /*
  390.  * alclstb - allocate a list element block in the block region.
  391.  */
  392.  
  393. struct b_lelem *alclstb(nslots, first, nused)
  394. uword nslots, first, nused;
  395.    {
  396.    register struct b_lelem *blk;
  397.    register word i, size;
  398.  
  399.    AlcVarBlk(blk, b_lelem, T_Lelem, nslots)
  400.    blk->nslots = nslots;
  401.    blk->first = first;
  402.    blk->nused = nused;
  403.    blk->listprev = NULL;
  404.    blk->listnext = NULL;
  405.    /*
  406.     * Set all elements to &null.
  407.     */
  408.    for (i = 0; i < nslots; i++)
  409.       blk->lslots[i] = nulldesc;
  410.    return blk;
  411.    }
  412.  
  413. /*
  414.  * alcreal - allocate a real value in the block region.
  415.  */
  416.  
  417. struct b_real *alcreal(val)
  418. double val;
  419.    {
  420.    register struct b_real *blk;
  421.  
  422.    AlcFixBlk(blk, b_real, T_Real)
  423.  
  424. #ifdef Double
  425. /* access real values one word at a time */
  426.    { int *rp, *rq;
  427.      rp = (int *) &(blk->realval);
  428.      rq = (int *) &val;
  429.      *rp++ = *rq++;
  430.      *rp   = *rq;
  431.    }
  432. #else                                   /* Double */
  433.    blk->realval = val;
  434. #endif                                  /* Double */
  435.  
  436.    return blk;
  437.    }
  438.  
  439. /*
  440.  * alcrecd - allocate record with nflds fields in the block region.
  441.  */
  442.  
  443. struct b_record *alcrecd(nflds, recptr)
  444. int nflds;
  445. union block *recptr;
  446.    {
  447.    tended union block *trecptr = recptr;
  448.    register struct b_record *blk;
  449.    register int i;
  450.  
  451.    AlcVarBlk(blk, b_record, T_Record, nflds)
  452.    blk->recdesc = trecptr;
  453.    blk->id = (((struct b_proc *)recptr)->recid)++;
  454.    return blk;
  455.    }
  456.  
  457. /*
  458.  * alcrefresh - allocate a co-expression refresh block.
  459.  */
  460.  
  461. #if COMPILER
  462. struct b_refresh *alcrefresh(na, nl, nt, wrk_sz)
  463. int na;
  464. int nl;
  465. int nt;
  466. int wrk_sz;
  467.    {
  468.    struct b_refresh *blk;
  469.  
  470.    AlcVarBlk(blk, b_refresh, T_Refresh, na + nl)
  471.    blk->nlocals = nl;
  472.    blk->nargs = na;
  473.    blk->ntemps = nt;
  474.    blk->wrk_size = wrk_sz;
  475.    return blk;
  476.    }
  477. #else                    /* COMPILER */
  478. struct b_refresh *alcrefresh(entryx, na, nl)
  479. word *entryx;
  480. int na, nl;
  481.    {
  482.    int size;
  483.    struct b_refresh *blk;
  484.  
  485.    AlcVarBlk(blk, b_refresh, T_Refresh, na + nl);
  486.    blk->ep = entryx;
  487.    blk->numlocals = nl;
  488.    return blk;
  489.    }
  490. #endif                    /* COMPILER */
  491.  
  492. /*
  493.  * alcselem - allocate a set element block.
  494.  */
  495.  
  496. struct b_selem *alcselem(mbr,hn)
  497. uword hn;
  498. dptr mbr;
  499.  
  500.    {
  501.    tended struct descrip tmbr = *mbr;
  502.    register struct b_selem *blk;
  503.  
  504.    AlcFixBlk(blk, b_selem, T_Selem)
  505.    blk->clink = NULL;
  506.    blk->setmem = tmbr;
  507.    blk->hashnum = hn;
  508.    return blk;
  509.    }
  510.  
  511. /*
  512.  * alcstr - allocate a string in the string space.
  513.  */
  514.  
  515. char *alcstr(s, slen)
  516. register char *s;
  517. register word slen;
  518.    {
  519.    tended struct descrip ts;
  520.    register char *d;
  521.    char *ofree;
  522.  
  523. #ifdef MultiThread
  524.    StrLen(ts) = slen;
  525.    StrLoc(ts) = s;
  526. #ifdef EventMon
  527.    if (!noMTevents)
  528. #endif                    /* EventMon */
  529.       MMStr(slen);
  530.    s = StrLoc(ts);
  531. #endif                    /* MultiThread */
  532.  
  533.    /*
  534.     * Make sure there is enough room in the string space.
  535.     */
  536.    if (DiffPtrs(strend,strfree) < slen) {
  537.       StrLen(ts) = slen;
  538.       StrLoc(ts) = s;
  539.       if (!reserve(Strings, slen))
  540.          return NULL;
  541.       s = StrLoc(ts);
  542.       }
  543.  
  544.    strtotal += slen;
  545.  
  546.    /*
  547.     * Copy the string into the string space, saving a pointer to its
  548.     *  beginning.  Note that s may be null, in which case the space
  549.     *  is still to be allocated but nothing is to be copied into it.
  550.     */
  551.    ofree = d = strfree;
  552.    if (s) {
  553.       while (slen-- > 0)
  554.          *d++ = *s++;
  555.       }
  556.    else
  557.       d += slen;
  558.  
  559.    strfree = d;
  560.    return ofree;
  561.    }
  562.  
  563. /*
  564.  * alcsubs - allocate a substring trapped variable in the block region.
  565.  */
  566.  
  567. struct b_tvsubs *alcsubs(len, pos, var)
  568. word len, pos;
  569. dptr var;
  570.    {
  571.    tended struct descrip tvar = *var;
  572.    register struct b_tvsubs *blk;
  573.  
  574.    AlcFixBlk(blk, b_tvsubs, T_Tvsubs)
  575.    blk->sslen = len;
  576.    blk->sspos = pos;
  577.    blk->ssvar = tvar;
  578.    return blk;
  579.    }
  580.  
  581. /*
  582.  * alctelem - allocate a table element block in the block region.
  583.  */
  584.  
  585. struct b_telem *alctelem()
  586.    {
  587.    register struct b_telem *blk;
  588.  
  589.    AlcFixBlk(blk, b_telem, T_Telem)
  590.    blk->hashnum = 0;
  591.    blk->clink = NULL;
  592.    blk->tref = nulldesc;
  593.    return blk;
  594.    }
  595.  
  596. /*
  597.  * alctvtbl - allocate a table element trapped variable block in the block
  598.  *  region.
  599.  */
  600.  
  601. struct b_tvtbl *alctvtbl(tbl, ref, hashnum)
  602. register dptr tbl, ref;
  603. uword hashnum;
  604.    {
  605.    tended struct descrip ttbl = *tbl;
  606.    tended struct descrip tref = *ref;
  607.    register struct b_tvtbl *blk;
  608.  
  609.    AlcFixBlk(blk, b_tvtbl, T_Tvtbl)
  610.    blk->hashnum = hashnum;
  611.    blk->clink = BlkLoc(ttbl);
  612.    blk->tref = tref;
  613.    return blk;
  614.    }
  615.  
  616. /*
  617.  * deallocate - return a block to the heap.
  618.  *
  619.  *  The block must be the one that is at the very end of a block region.
  620.  */
  621. novalue deallocate (bp)
  622. union block *bp;
  623. {
  624.    word nbytes;
  625.    struct region *rp;
  626.  
  627.    nbytes = BlkSize(bp);
  628.    for (rp = curblock; rp; rp = rp->next)
  629.       if ((char *)bp + nbytes == rp->free)
  630.          break;
  631.    if (!rp)
  632.       for (rp = curblock->prev; rp; rp = rp->prev)
  633.      if ((char *)bp + nbytes == rp->free)
  634.             break;
  635.    if (!rp)
  636.       syserr ("deallocation botch");
  637.    rp->free = (char *)bp;
  638.    blktotal -= nbytes;
  639.    MMAlc(-nbytes, 0);
  640. }
  641.  
  642. /*
  643.  * reserve -- ensure space in either string or block region.
  644.  *
  645.  *   1. check for space in current region.
  646.  *   2. check for space in older regions.
  647.  *   3. check for space in newer regions.
  648.  *   4. set goal of 10% of size of newest region.
  649.  *   5. collect regions, newest to oldest, until goal met.
  650.  *   6. allocate new region at 200% the size of newest existing.
  651.  *   7. reset goal back to original request.
  652.  *   8. collect regions that were too small to bother with before.
  653.  *   9. search regions, newest to oldest.
  654.  *  10. give up and signal error.
  655.  */
  656.  
  657. char *reserve(region, nbytes)
  658. int region;
  659. word nbytes;
  660. {
  661.    struct region **pcurr, *curr, *rp;
  662.    word want, newsize;
  663.    extern int qualfail;
  664.  
  665.    if (region == Strings)
  666.       pcurr = &curstring;
  667.    else
  668.       pcurr = &curblock;
  669.    curr = *pcurr;
  670.  
  671.    /*
  672.     * Check for space available now.
  673.     */
  674.    if (DiffPtrs(curr->end, curr->free) >= nbytes)
  675.       return curr->free;        /* quick return: current region is OK */
  676.  
  677. #if SCCX_MX
  678.    if( (rp = findgap(curr, nbytes)) != 0) {    /* check all regions on chain */
  679. #else
  680.    if (rp = findgap(curr, nbytes)) {    /* check all regions on chain */
  681. #endif
  682.       *pcurr = rp;          /* switch regions */
  683.       return rp->free;
  684.       }
  685.  
  686.    /*
  687.     * Set "curr" to point to newest region.
  688.     */
  689.    while (curr->next)
  690.       curr = curr->next;
  691.  
  692.    /*
  693.     * Need to collect garbage.  To reduce thrashing, set a minimum requirement
  694.     *  of 10% of the size of the newest region, and collect regions until that
  695.     *  amount of free space appears in one of them.
  696.     */
  697.    want = (curr->size / 100) * memcushion;
  698.    if (want < nbytes)
  699.       want = nbytes;
  700.  
  701.    for (rp = curr; rp; rp = rp->prev)
  702.       if (rp->size >= want) {    /* if large enough to possibly succeed */
  703.          *pcurr = rp;
  704.          collect(region);
  705.          if (DiffPtrs(rp->end,rp->free) >= want)
  706.             return rp->free;
  707.          }
  708.  
  709.    /*
  710.     * That didn't work.  Allocate a new region with a size based on the
  711.     * newest previous region.
  712.     */
  713.    newsize = (curr->size / 100) * memgrowth;
  714.    if (newsize < nbytes)
  715.       newsize = nbytes;
  716.    if (newsize < MinAbrSize)
  717.       newsize = MinAbrSize;
  718.  
  719. #if SCCX_MX
  720.    if( (rp = newregion(nbytes, newsize)) != 0) {
  721. #else
  722.    if (rp = newregion(nbytes, newsize)) {
  723. #endif
  724.       rp->prev = curr;
  725.       rp->next = NULL;
  726.       curr->next = rp;
  727.       rp->Gnext = curr;
  728.       rp->Gprev = curr->Gprev;
  729.       if (curr->Gprev) curr->Gprev->Gnext = rp;
  730.       curr->Gprev = rp;
  731.       *pcurr = rp;
  732. #ifdef EventMon
  733.       if (!noMTevents) {
  734.          if (region == Strings) {
  735.             EVVal(rp->size, E_TenureString);
  736.             }
  737.          else {
  738.             EVVal(rp->size, E_TenureBlock);
  739.             }
  740.          }
  741. #endif                    /* EventMon */
  742.       return rp->free;
  743.       }
  744.  
  745.    /*
  746.     * Allocation failed.  Try to continue, probably thrashing all the way.
  747.     *  Collect the regions that weren't collected before and see if any
  748.     *  region has enough to satisfy the original request.
  749.     */
  750.    for (rp = curr; rp; rp = rp->prev)
  751.       if (rp->size < want) {        /* if not collected earlier */
  752.          *pcurr = rp;
  753.          collect(region);
  754.          if (DiffPtrs(rp->end,rp->free) >= want)
  755.             return rp->free;
  756.          }
  757. #if SCCX_MX
  758.    if( (rp = findgap(curr, nbytes)) != 0) {
  759. #else
  760.    if (rp = findgap(curr, nbytes)) {
  761. #endif
  762.       *pcurr = rp;
  763.       return rp->free;
  764.       }
  765.  
  766.    /*
  767.     * All attempts failed.
  768.     */
  769.    if (region == Blocks)
  770.       ReturnErrNum(307, 0);
  771.    else if (qualfail)
  772.       ReturnErrNum(304, 0);
  773.    else
  774.       ReturnErrNum(306, 0);
  775. }
  776.  
  777. /*
  778.  * findgap - search region chain for a region having at least nbytes available
  779.  */
  780. static struct region *findgap(curr, nbytes)
  781. struct region *curr;
  782. word nbytes;
  783.    {
  784.    struct region *rp;
  785.  
  786.    for (rp = curr; rp; rp = rp->prev)
  787.       if (DiffPtrs(rp->end, rp->free) >= nbytes)
  788.          return rp;
  789.    for (rp = curr->next; rp; rp = rp->next)
  790.       if (DiffPtrs(rp->end, rp->free) >= nbytes)
  791.          return rp;
  792.    return NULL;
  793.    }
  794.  
  795. /*
  796.  * newregion - try to malloc a new region and tenure the old one,
  797.  *  backing off if the requested size fails.
  798.  */
  799. static struct region *newregion(nbytes,stdsize)
  800. word nbytes,stdsize;
  801. {
  802.    uword minSize = MinAbrSize;
  803.    struct region *rp;
  804.  
  805. #if IntBits == 16
  806.    if ((uword)nbytes > (uword)MaxBlock)
  807.       return NULL;
  808.    if ((uword)stdsize > (uword)MaxBlock)
  809.       stdsize = (uword)MaxBlock;
  810. #endif                    /* IntBits == 16 */
  811.  
  812.    if ((uword)nbytes > minSize)
  813.       minSize = (uword)nbytes;
  814.  
  815.    rp = (struct region *)malloc(sizeof(struct region));
  816.    if (rp) {
  817.       rp->size = stdsize;
  818. #if IntBits == 16
  819.       if ((rp->size < nbytes) && (nbytes < (unsigned int)MaxBlock))
  820.          rp->size = Min(nbytes+stdsize,(unsigned int)MaxBlock);
  821. #else                    /* IntBits == 16 */
  822.       if (rp->size < nbytes)
  823.          rp->size = Max(nbytes+stdsize, nbytes);
  824. #endif                    /* IntBits == 16 */
  825.  
  826.       do {
  827.          rp->free = rp->base = (char *)AllocReg(rp->size);
  828.          if (rp->free != NULL) {
  829.             rp->end = rp->base + rp->size;
  830.             return rp;
  831.             }
  832.          else {
  833.             }
  834.          rp->size = (rp->size + nbytes)/2 - 1;
  835.          }
  836.       while (rp->size >= minSize);
  837.       free((char *)rp);
  838.       }
  839.    return NULL;
  840. }
  841.