Annotation of 43BSD/bin/csh/alloc.c, revision 1.1.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.