Annotation of 43BSDReno/bin/csh/alloc.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1983 Regents of the University of California.
        !             3:  * All rights reserved.  The Berkeley software License Agreement
        !             4:  * specifies the terms and conditions for redistribution.
        !             5:  */
        !             6: 
        !             7: #ifndef lint
        !             8: /* From "@(#)malloc.c  5.5 (Berkeley) 2/25/86"; */
        !             9: static char *sccsid = "@(#)alloc.c     5.3 (Berkeley) 3/29/86";
        !            10: #endif not lint
        !            11: 
        !            12: /*
        !            13:  * malloc.c (Caltech) 2/21/82
        !            14:  * Chris Kingsley, kingsley@cit-20.
        !            15:  *
        !            16:  * This is a very fast storage allocator.  It allocates blocks of a small 
        !            17:  * number of different sizes, and keeps free lists of each size.  Blocks that
        !            18:  * don't exactly fit are passed up to the next larger size.  In this 
        !            19:  * implementation, the available sizes are 2^n-4 (or 2^n-10) bytes long.
        !            20:  * This is designed for use in a virtual memory environment.
        !            21:  */
        !            22: 
        !            23: #include <sys/types.h>
        !            24: 
        !            25: #define        NULL 0
        !            26: 
        !            27: /*
        !            28:  * The overhead on a block is at least 4 bytes.  When free, this space
        !            29:  * contains a pointer to the next free block, and the bottom two bits must
        !            30:  * be zero.  When in use, the first byte is set to MAGIC, and the second
        !            31:  * byte is the size index.  The remaining bytes are for alignment.
        !            32:  * If range checking is enabled then a second word holds the size of the
        !            33:  * requested block, less 1, rounded up to a multiple of sizeof(RMAGIC).
        !            34:  * The order of elements is critical: ov_magic must overlay the low order
        !            35:  * bits of ov_next, and ov_magic can not be a valid ov_next bit pattern.
        !            36:  */
        !            37: union  overhead {
        !            38:        union   overhead *ov_next;      /* when free */
        !            39:        struct {
        !            40:                u_char  ovu_magic;      /* magic number */
        !            41:                u_char  ovu_index;      /* bucket # */
        !            42: #ifdef RCHECK
        !            43:                u_short ovu_rmagic;     /* range magic number */
        !            44:                u_int   ovu_size;       /* actual block size */
        !            45: #endif
        !            46:        } ovu;
        !            47: #define        ov_magic        ovu.ovu_magic
        !            48: #define        ov_index        ovu.ovu_index
        !            49: #define        ov_rmagic       ovu.ovu_rmagic
        !            50: #define        ov_size         ovu.ovu_size
        !            51: };
        !            52: 
        !            53: #define        MAGIC           0xef            /* magic # on accounting info */
        !            54: #define RMAGIC         0x5555          /* magic # on range info */
        !            55: 
        !            56: #ifdef RCHECK
        !            57: #define        RSLOP           sizeof (u_short)
        !            58: #else
        !            59: #define        RSLOP           0
        !            60: #endif
        !            61: 
        !            62: /*
        !            63:  * nextf[i] is the pointer to the next free block of size 2^(i+3).  The
        !            64:  * smallest allocatable block is 8 bytes.  The overhead information
        !            65:  * precedes the data area returned to the user.
        !            66:  */
        !            67: #define        NBUCKETS 30
        !            68: static union overhead *nextf[NBUCKETS];
        !            69: extern char *sbrk();
        !            70: 
        !            71: static int pagesz;                     /* page size */
        !            72: static int pagebucket;                 /* page size bucket */
        !            73: 
        !            74: /*
        !            75:  * nmalloc[i] is the difference between the number of mallocs and frees
        !            76:  * for a given block size.
        !            77:  */
        !            78: static u_int nmalloc[NBUCKETS];
        !            79: 
        !            80: #if defined(DEBUG) || defined(RCHECK)
        !            81: #define        ASSERT(p)   if (!(p)) botch("p")
        !            82: static
        !            83: botch(s)
        !            84:        char *s;
        !            85: {
        !            86:        printf("\r\nassertion botched: %s\r\n", s);
        !            87:        abort();
        !            88: }
        !            89: #else
        !            90: #define        ASSERT(p)
        !            91: #endif
        !            92: 
        !            93: char *
        !            94: malloc(nbytes)
        !            95:        unsigned nbytes;
        !            96: {
        !            97:        register union overhead *op;
        !            98:        register int bucket;
        !            99:        register unsigned amt, n;
        !           100: 
        !           101:        /*
        !           102:         * First time malloc is called, setup page size and
        !           103:         * align break pointer so all data will be page aligned.
        !           104:         */
        !           105:        if (pagesz == 0) {
        !           106:                pagesz = n = getpagesize();
        !           107:                op = (union overhead *)sbrk(0);
        !           108:                n = n - sizeof (*op) - ((int)op & (n - 1));
        !           109:                if (n < 0)
        !           110:                        n += pagesz;
        !           111:                if (n) {
        !           112:                        if (sbrk(n) == (char *)-1)
        !           113:                                return (NULL);
        !           114:                }
        !           115:                bucket = 0;
        !           116:                amt = 8;
        !           117:                while (pagesz > amt) {
        !           118:                        amt <<= 1;
        !           119:                        bucket++;
        !           120:                }
        !           121:                pagebucket = bucket;
        !           122:        }
        !           123:        /*
        !           124:         * Convert amount of memory requested into closest block size
        !           125:         * stored in hash buckets which satisfies request.
        !           126:         * Account for space used per block for accounting.
        !           127:         */
        !           128:        if (nbytes <= (n = pagesz - sizeof (*op) - RSLOP)) {
        !           129: #ifndef RCHECK
        !           130:                amt = 8;        /* size of first bucket */
        !           131:                bucket = 0;
        !           132: #else
        !           133:                amt = 16;       /* size of first bucket */
        !           134:                bucket = 1;
        !           135: #endif
        !           136:                n = -(sizeof (*op) + RSLOP);
        !           137:        } else {
        !           138:                amt = pagesz;
        !           139:                bucket = pagebucket;
        !           140:        }
        !           141:        while (nbytes > amt + n) {
        !           142:                amt <<= 1;
        !           143:                if (amt == 0)
        !           144:                        return (NULL);
        !           145:                bucket++;
        !           146:        }
        !           147:        /*
        !           148:         * If nothing in hash bucket right now,
        !           149:         * request more memory from the system.
        !           150:         */
        !           151:        if ((op = nextf[bucket]) == NULL) {
        !           152:                morecore(bucket);
        !           153:                if ((op = nextf[bucket]) == NULL)
        !           154:                        return (NULL);
        !           155:        }
        !           156:        /* remove from linked list */
        !           157:        nextf[bucket] = op->ov_next;
        !           158:        op->ov_magic = MAGIC;
        !           159:        op->ov_index = bucket;
        !           160:        nmalloc[bucket]++;
        !           161: #ifdef RCHECK
        !           162:        /*
        !           163:         * Record allocated size of block and
        !           164:         * bound space with magic numbers.
        !           165:         */
        !           166:        op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
        !           167:        op->ov_rmagic = RMAGIC;
        !           168:        *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
        !           169: #endif
        !           170:        return ((char *)(op + 1));
        !           171: }
        !           172: 
        !           173: /*
        !           174:  * Allocate more memory to the indicated bucket.
        !           175:  */
        !           176: morecore(bucket)
        !           177:        int bucket;
        !           178: {
        !           179:        register union overhead *op;
        !           180:        register int sz;                /* size of desired block */
        !           181:        int amt;                        /* amount to allocate */
        !           182:        int nblks;                      /* how many blocks we get */
        !           183: 
        !           184:        /*
        !           185:         * sbrk_size <= 0 only for big, FLUFFY, requests (about
        !           186:         * 2^30 bytes on a VAX, I think) or for a negative arg.
        !           187:         */
        !           188:        sz = 1 << (bucket + 3);
        !           189: #ifdef DEBUG
        !           190:        ASSERT(sz > 0);
        !           191: #else
        !           192:        if (sz <= 0)
        !           193:                return;
        !           194: #endif
        !           195:        if (sz < pagesz) {
        !           196:                amt = pagesz;
        !           197:                nblks = amt / sz;
        !           198:        } else {
        !           199:                amt = sz + pagesz;
        !           200:                nblks = 1;
        !           201:        }
        !           202:        op = (union overhead *)sbrk(amt);
        !           203:        /* no more room! */
        !           204:        if ((int)op == -1)
        !           205:                return;
        !           206:        /*
        !           207:         * Add new memory allocated to that on
        !           208:         * free list for this hash bucket.
        !           209:         */
        !           210:        nextf[bucket] = op;
        !           211:        while (--nblks > 0) {
        !           212:                op->ov_next = (union overhead *)((caddr_t)op + sz);
        !           213:                op = (union overhead *)((caddr_t)op + sz);
        !           214:        }
        !           215: }
        !           216: 
        !           217: free(cp)
        !           218:        char *cp;
        !           219: {   
        !           220:        register int size;
        !           221:        register union overhead *op;
        !           222: 
        !           223:        if (cp == NULL)
        !           224:                return;
        !           225:        op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
        !           226:        /* 
        !           227:         * The following botch is because csh tries to free a free block
        !           228:         * when processing the =~ or !~ operators. -- layer@ucbmonet
        !           229:        */
        !           230: #ifdef CSHbotch /* was DEBUG */
        !           231:        ASSERT(op->ov_magic == MAGIC);          /* make sure it was in use */
        !           232: #else
        !           233:        if (op->ov_magic != MAGIC)
        !           234:                return;                         /* sanity */
        !           235: #endif
        !           236: #ifdef RCHECK
        !           237:        ASSERT(op->ov_rmagic == RMAGIC);
        !           238:        ASSERT(*(u_short *)((caddr_t)(op + 1) + op->ov_size) == RMAGIC);
        !           239: #endif
        !           240:        size = op->ov_index;
        !           241:        ASSERT(size < NBUCKETS);
        !           242:        op->ov_next = nextf[size];      /* also clobbers ov_magic */
        !           243:        nextf[size] = op;
        !           244:        nmalloc[size]--;
        !           245: }
        !           246: 
        !           247: /*
        !           248:  * When a program attempts "storage compaction" as mentioned in the
        !           249:  * old malloc man page, it realloc's an already freed block.  Usually
        !           250:  * this is the last block it freed; occasionally it might be farther
        !           251:  * back.  We have to search all the free lists for the block in order
        !           252:  * to determine its bucket: 1st we make one pass thru the lists
        !           253:  * checking only the first block in each; if that fails we search
        !           254:  * ``realloc_srchlen'' blocks in each list for a match (the variable
        !           255:  * is extern so the caller can modify it).  If that fails we just copy
        !           256:  * however many bytes was given to realloc() and hope it's not huge.
        !           257:  */
        !           258: int realloc_srchlen = 4;       /* 4 should be plenty, -1 =>'s whole list */
        !           259: 
        !           260: char *
        !           261: realloc(cp, nbytes)
        !           262:        char *cp; 
        !           263:        unsigned nbytes;
        !           264: {   
        !           265:        register u_int onb, i;
        !           266:        union overhead *op;
        !           267:        char *res;
        !           268:        int was_alloced = 0;
        !           269: 
        !           270:        if (cp == NULL)
        !           271:                return (malloc(nbytes));
        !           272:        op = (union overhead *)((caddr_t)cp - sizeof (union overhead));
        !           273:        if (op->ov_magic == MAGIC) {
        !           274:                was_alloced++;
        !           275:                i = op->ov_index;
        !           276:        } else {
        !           277:                /*
        !           278:                 * Already free, doing "compaction".
        !           279:                 *
        !           280:                 * Search for the old block of memory on the
        !           281:                 * free list.  First, check the most common
        !           282:                 * case (last element free'd), then (this failing)
        !           283:                 * the last ``realloc_srchlen'' items free'd.
        !           284:                 * If all lookups fail, then assume the size of
        !           285:                 * the memory block being realloc'd is the
        !           286:                 * largest possible (so that all "nbytes" of new
        !           287:                 * memory are copied into).  Note that this could cause
        !           288:                 * a memory fault if the old area was tiny, and the moon
        !           289:                 * is gibbous.  However, that is very unlikely.
        !           290:                 */
        !           291:                if ((i = findbucket(op, 1)) < 0 &&
        !           292:                    (i = findbucket(op, realloc_srchlen)) < 0)
        !           293:                        i = NBUCKETS;
        !           294:        }
        !           295:        onb = 1 << (i + 3);
        !           296:        if (onb < pagesz)
        !           297:                onb -= sizeof (*op) + RSLOP;
        !           298:        else
        !           299:                onb += pagesz - sizeof (*op) - RSLOP;
        !           300:        /* avoid the copy if same size block */
        !           301:        if (was_alloced) {
        !           302:                if (i) {
        !           303:                        i = 1 << (i + 2);
        !           304:                        if (i < pagesz)
        !           305:                                i -= sizeof (*op) + RSLOP;
        !           306:                        else
        !           307:                                i += pagesz - sizeof (*op) - RSLOP;
        !           308:                }
        !           309:                if (nbytes <= onb && nbytes > i) {
        !           310: #ifdef RCHECK
        !           311:                        op->ov_size = (nbytes + RSLOP - 1) & ~(RSLOP - 1);
        !           312:                        *(u_short *)((caddr_t)(op + 1) + op->ov_size) = RMAGIC;
        !           313: #endif
        !           314:                        return(cp);
        !           315:                } else
        !           316:                        free(cp);
        !           317:        }
        !           318:        if ((res = malloc(nbytes)) == NULL)
        !           319:                return (NULL);
        !           320:        if (cp != res)          /* common optimization if "compacting" */
        !           321:                bcopy(cp, res, (nbytes < onb) ? nbytes : onb);
        !           322:        return (res);
        !           323: }
        !           324: 
        !           325: /*
        !           326:  * Search ``srchlen'' elements of each free list for a block whose
        !           327:  * header starts at ``freep''.  If srchlen is -1 search the whole list.
        !           328:  * Return bucket number, or -1 if not found.
        !           329:  */
        !           330: static
        !           331: findbucket(freep, srchlen)
        !           332:        union overhead *freep;
        !           333:        int srchlen;
        !           334: {
        !           335:        register union overhead *p;
        !           336:        register int i, j;
        !           337: 
        !           338:        for (i = 0; i < NBUCKETS; i++) {
        !           339:                j = 0;
        !           340:                for (p = nextf[i]; p && j != srchlen; p = p->ov_next) {
        !           341:                        if (p == freep)
        !           342:                                return (i);
        !           343:                        j++;
        !           344:                }
        !           345:        }
        !           346:        return (-1);
        !           347: }
        !           348: 
        !           349: /*
        !           350:  * mstats - print out statistics about malloc
        !           351:  * 
        !           352:  * Prints two lines of numbers, one showing the length of the free list
        !           353:  * for each size category, the second showing the number of mallocs -
        !           354:  * frees for each size category.
        !           355:  */
        !           356: showall(s)
        !           357: char **s;
        !           358: {
        !           359:        register int i, j;
        !           360:        register union overhead *p;
        !           361:        int totfree = 0,
        !           362:        totused = 0;
        !           363: 
        !           364:        if (s[1])
        !           365:                printf("Memory allocation statistics %s\nfree:", s[1]);
        !           366:        for (i = 0; i < NBUCKETS; i++) {
        !           367:                for (j = 0, p = nextf[i]; p; p = p->ov_next, j++)
        !           368:                        ;
        !           369:                if (s[1])
        !           370:                        printf(" %d", j);
        !           371:                totfree += j * (1 << (i + 3));
        !           372:        }
        !           373:        if (s[1])
        !           374:                printf("\nused:");
        !           375:        for (i = 0; i < NBUCKETS; i++) {
        !           376:                if (s[1])
        !           377:                        printf(" %d", nmalloc[i]);
        !           378:                totused += nmalloc[i] * (1 << (i + 3));
        !           379:        }
        !           380:        if (s[1])
        !           381:                printf("\n");
        !           382:        printf("Total in use: %d, total free: %d\n", totused, totfree);
        !           383: }

unix.superglobalmegacorp.com

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