Annotation of researchv10no/cmd/trace/cmalloc.c, revision 1.1.1.1

1.1       root        1: #ifdef debug
                      2: #define ASSERT(p) if(!(p))botch("p");else
                      3: botch(s)
                      4: char *s;
                      5: {
                      6:        printf("assertion botched: %s\n",s);
                      7:        abort();
                      8: }
                      9: #else
                     10: #define ASSERT(p)
                     11: #endif
                     12: 
                     13: /*     C storage allocator
                     14:  *     circular first-fit strategy
                     15:  *     works with noncontiguous, but monotonically linked, arena
                     16:  *     each block is preceded by a ptr to the (pointer of) 
                     17:  *     the next following block
                     18:  *     blocks are exact number of words long 
                     19:  *     aligned to the data type requirements of ALIGN
                     20:  *     pointers to blocks must have BUSY bit 0
                     21:  *     bit in ptr is 1 for busy, 0 for idle
                     22:  *     gaps in arena are merely noted as busy blocks
                     23:  *     last block of arena is empty and
                     24:  *     has a pointer to first
                     25:  *     idle blocks are coalesced during space search
                     26:  *
                     27:  *     a different implementation may need to redefine
                     28:  *     ALIGN, NALIGN, BLOCK, BUSY, INT
                     29:  *     where INT is integer type to which a pointer can be cast
                     30: */
                     31: #define INT int
                     32: #define ALIGN int
                     33: #define NALIGN 1
                     34: #define WORD sizeof(union store)
                     35: #define BLOCK 1024
                     36: #define BUSY 1
                     37: #define NULL 0
                     38: #define testbusy(p) ((INT)(p)&BUSY)
                     39: #define setbusy(p) (union store *)((INT)(p)|BUSY)
                     40: #define clearbusy(p) (union store *)((INT)(p)&~BUSY)
                     41: 
                     42: union store {
                     43:              union store *ptr;
                     44:              ALIGN dummy[NALIGN];
                     45:              int calloc;       /*calloc clears an array of integers*/
                     46: };
                     47: 
                     48: static union store alloca;     /* initial arena */
                     49: static union store *allocb = &alloca;  /*arena base*/
                     50: static union store *allocp = &alloca;  /*search ptr*/
                     51: static union store *alloct = &alloca;  /*arena top; for speedier ialloc*/
                     52: static union store allocx, allocy;     /*for benefit of realloc*/
                     53: extern char *sbrk();
                     54: 
                     55: /* a cache list of frequently-used sizes is maintained. From each
                     56:  * cache entry hangs a chain of available blocks (marked busy
                     57:  * to keep out of the first fit search)  
                     58: */
                     59: #define CACHEMAX 100   /* largest block to be cached (in words) */
                     60: #ifndef pdp11
                     61: #define CACHESIZ 13    /* number of entries (prime) */
                     62: #else
                     63: #define CACHESIZ 0
                     64: #endif
                     65: static struct cache {
                     66:        int size;
                     67:        union store *chain;
                     68: } cache[CACHESIZ];
                     69: 
                     70: char *
                     71: malloc(nbytes)
                     72: unsigned nbytes;
                     73: {
                     74:        register union store *p, *q;
                     75:        register nw;
                     76:        register temp;
                     77:        register struct cache *cp;
                     78: 
                     79:        ASSERT(allock(allocp)&1);
                     80:        nw = (nbytes+WORD+WORD-1)/WORD;
                     81:        if(CACHESIZ && nw<CACHEMAX && nw>2) {   /* see note + below */
                     82:                cp = cache + nw%CACHESIZ;
                     83:                p = cp->chain;
                     84:                if(p && nw==cp->size) {
                     85:                        cp->chain = p[1].ptr;
                     86:                        ASSERT(testbusy(p->ptr));
                     87:                        ASSERT(clearbusy(p->ptr)-p==nw);
                     88:                        return (char*)(p+1);
                     89:                }
                     90:        }
                     91:        ASSERT(allock(allocp)&3);
                     92:        for(; ; ) {     /* done at most twice */
                     93:                p = allocp;
                     94:                if(alloca.ptr!=0)               /*C can't initialize union*/
                     95:                for(temp=0; ; ) {
                     96:                        if(!testbusy(p->ptr)) {
                     97:                                while(!testbusy((q=p->ptr)->ptr)) {
                     98:                                        ASSERT(q>p);
                     99:                                        p->ptr = q->ptr;
                    100:                                }
                    101:                                allocp = p;
                    102:                                if(q>=p+nw && p+nw>=p)  /*room; no wrap*/
                    103:                                        goto found;
                    104:                        }
                    105:                        q = p;
                    106:                        p = clearbusy(p->ptr);
                    107:                        if(p <= q) {
                    108:                                ASSERT(p==allocb);
                    109:                                if(++temp>1)
                    110:                                        break;
                    111:                        }
                    112:                }
                    113:                temp = nw;
                    114:                p = (union store *)sbrk(0);
                    115:                q = allocp->ptr;
                    116:                if(!testbusy(q) && q+1 == p)
                    117:                        temp -= p - allocp;
                    118:                temp = ((temp+BLOCK/WORD)/(BLOCK/WORD))*(BLOCK/WORD);
                    119:                if(p+temp <= p)
                    120:                        return(NULL);
                    121:                for( ; ; ) {
                    122:                        register s;
                    123:                        q = (union store *)sbrk(temp*WORD);
                    124:                        if((INT)q != -1)
                    125:                                break;
                    126:                        for(cp=cache; cp<cache+CACHESIZ; cp++) {
                    127:                                for(p=cp->chain; p; p=p[1].ptr) {
                    128:                                        ASSERT(testbusy(p->ptr));
                    129:                                        p->ptr = clearbusy(p->ptr);
                    130:                                        ASSERT(p->ptr-p==cp->size);
                    131:                                }
                    132:                                cp->chain = 0;
                    133:                        }
                    134:                        s = (temp-nw)/2;
                    135:                        if(s <= 0)
                    136:                                return(NULL);
                    137:                        temp -= s;
                    138:                }
                    139:                ialloc((char *)q, (unsigned)temp*WORD);
                    140:        }
                    141: found:
                    142:        q = p + nw;
                    143:        if(p->ptr > q) {
                    144:                allocx = *q;
                    145:                q->ptr = p->ptr;
                    146:        }
                    147:        p->ptr = setbusy(q);
                    148:        ASSERT(allock(allocp)&7);
                    149:        return((char *)(p+1));
                    150: }
                    151: /* + note CACHESIZ is tested for conditional compilation; nw>2 assumes there's
                    152:  * no point in caching smaller sizes (they are rarely used and always
                    153:  * can be allocated) and protects against the old storage compaction trick:
                    154:  * free(p); free(dummy);dummy=malloc(1);realloc(p)
                    155:  * (otherwise free(dummy) would destroy allocy, which pertains to p)
                    156: */
                    157: 
                    158: /*     freeing strategy tuned for LIFO allocation
                    159: */
                    160: free(ap)
                    161: char *ap;
                    162: {
                    163:        register union store *p = (union store *)ap, *q;
                    164:        register nw;
                    165:        register struct cache *cp;
                    166: 
                    167:        --p;
                    168:        ASSERT(allock(p));
                    169:        ASSERT(testbusy(p->ptr));
                    170:        nw = clearbusy(p->ptr) - p;
                    171:        ASSERT(nw>0);
                    172:        if(CACHESIZ && nw<CACHEMAX && nw>2) {
                    173:                cp = cache + nw%CACHESIZ;
                    174:                if(nw != cp->size) {
                    175:                        q = cp->chain;
                    176:                        if(q) {
                    177:                                ASSERT(testbusy(q->ptr));
                    178:                                q->ptr = clearbusy(q->ptr);
                    179:                                ASSERT(q->ptr-q==cp->size);
                    180:                                cp->chain = q[1].ptr;
                    181:                        }
                    182:                        if(!q)
                    183:                                cp->size = nw;
                    184:                        else
                    185:                                goto nocache;
                    186:                }
                    187:                allocy = p[1];
                    188:                p[1].ptr = cp->chain;
                    189:                cp->chain = p;
                    190:                ASSERT(allock(allocp)&017);
                    191:                return;
                    192:        }
                    193: nocache:
                    194:        allocp = p;
                    195:        p->ptr = clearbusy(p->ptr);
                    196:        ASSERT(allock(allocp)&037);
                    197:        ASSERT(p->ptr<=alloct);
                    198: }
                    199: 
                    200: /* ialloc(q, nbytes) inserts a block that did not come
                    201:  * from malloc into the arena
                    202:  *
                    203:  * q points to new block
                    204:  * r points to last of new block
                    205:  * p points to last cell of arena before new block
                    206:  * s points to first cell of arena after new block
                    207: */
                    208: ialloc(qq, nbytes)
                    209: char *qq;
                    210: unsigned nbytes;
                    211: {
                    212:        register union store *p, *q, *s;
                    213:        union store *r;
                    214: 
                    215:        q = (union store *)qq;
                    216:        r = q + (nbytes/WORD) - 1;
                    217:        q->ptr = r;
                    218:        if(alloca.ptr==0)               /*C can't initialize union*/
                    219:                alloca.ptr = &alloca;
                    220:        if(q > alloct) {
                    221:                p = alloct;
                    222:                alloct = r;
                    223:        } else
                    224:                allocp = p = allocb;
                    225:        for( ; ; p=s) {
                    226:                s = clearbusy(p->ptr);
                    227:                if(s==allocb)
                    228:                        break;
                    229:                ASSERT(s>p);
                    230:                if(s>r) {
                    231:                        if(p<q)
                    232:                                break;
                    233:                        else
                    234:                                ASSERT(p>r);
                    235:                }
                    236:        }
                    237:        p->ptr = q==p+1? q: setbusy(q);
                    238:        r->ptr = s==r+1? s: setbusy(s);
                    239:        if(allocb > q)
                    240:                allocp = allocb = q;
                    241: }
                    242: 
                    243: /*     realloc(p, nbytes) reallocates a block obtained from malloc()
                    244:  *     and freed since last call of malloc()
                    245:  *     to have new size nbytes, and old content
                    246:  *     returns new location, or 0 on failure
                    247: */
                    248: 
                    249: char *
                    250: realloc(pp, nbytes)
                    251: char *pp;
                    252: unsigned nbytes;
                    253: {
                    254:        register union store *q;
                    255:        register union store *p = (union store *)pp;
                    256:        register union store *s, *t;
                    257:        register unsigned nw;
                    258:        struct cache *cp;
                    259:        unsigned onw;
                    260: 
                    261:        q = p-1;
                    262:        ASSERT(allock(q));
                    263:        if(testbusy(q->ptr)) {
                    264:                allocp = q;
                    265:                q->ptr = clearbusy(q->ptr);
                    266:                if(CACHESIZ) {
                    267:                        nw = q->ptr - q;
                    268:                        cp = cache + nw%CACHESIZ;
                    269:                        if(cp->chain==q) {
                    270:                                ASSERT(cp->size==nw);
                    271:                                cp->chain = p->ptr;     /*p->ptr==q[1].ptr*/
                    272:                                *p = allocy;
                    273:                        } else
                    274:                                ASSERT(notonchain(q,cp->chain));
                    275:                }
                    276:        }
                    277:        onw = q->ptr - p;
                    278:        q = (union store *)malloc(nbytes);
                    279:        if(q==NULL || q==p)
                    280:                return((char *)q);
                    281:        ASSERT(q<p||q>p[-1].ptr);
                    282:        s = p;
                    283:        t = q;
                    284:        nw = (nbytes+WORD-1)/WORD;
                    285:        if(nw<onw)
                    286:                onw = nw;
                    287:        while(onw--!=0)
                    288:                *t++ = *s++;
                    289:        ASSERT(clearbusy(q[-1].ptr)-q==nw);
                    290:        if(q<p && q+nw>=p)
                    291:                q[q+nw-p] = allocx;
                    292:        ASSERT(allock(q-1));
                    293:        return((char *)q);
                    294: }
                    295: 
                    296: #ifdef debug
                    297: 
                    298: notonchain(p,q)
                    299: union store *p, *q;
                    300: {
                    301:        for(;q; q=clearbusy(q->ptr))
                    302:                if(q==p)
                    303:                        return 0;
                    304:        return 1;
                    305: }
                    306: 
                    307: allock(q)
                    308: union store *q;
                    309: {
                    310: #ifdef longdebug
                    311:        register union store *p, *r;
                    312:        int x;
                    313:        for(x=0; x<CACHESIZ; x++) {
                    314:                p = cache[x].chain;
                    315:                if(p==0)
                    316:                        continue;
                    317:                for( ; p; p=p[1].ptr) {
                    318:                        ASSERT(testbusy(p->ptr));
                    319:                        ASSERT(clearbusy(p->ptr)-p==cache[x].size);
                    320:                }
                    321:        }
                    322:        x = 0;
                    323:        p = allocb;
                    324:        if(alloca.ptr==0)
                    325:                return(1);
                    326:        for( ; (r=clearbusy(p->ptr)) > p; p=r) {
                    327:                if(p==q)
                    328:                        x++;
                    329:        }
                    330:        return(r==allocb&(x==1|p==q));
                    331: #else
                    332:        return(q>=allocb);
                    333: #endif
                    334: }
                    335: #endif

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.