Annotation of 43BSDReno/lib/libc/stdlib/malloc.c, revision 1.1

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

unix.superglobalmegacorp.com

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