Annotation of researchv10no/cmd/trace/cmalloc.c, revision 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.