Annotation of coherent/b/STREAMS/coh.386/alloc.c, revision 1.1.1.1

1.1       root        1: /* $Header: /src386/STREAMS/coh.386/RCS/alloc.c,v 2.3 93/08/09 13:35:06 bin Exp Locker: bin $ */
                      2: /* (lgl-
                      3:  *     The information contained herein is a trade secret of Mark Williams
                      4:  *     Company, and  is confidential information.  It is provided  under a
                      5:  *     license agreement,  and may be  copied or disclosed  only under the
                      6:  *     terms of  that agreement.  Any  reproduction or disclosure  of this
                      7:  *     material without the express written authorization of Mark Williams
                      8:  *     Company or persuant to the license agreement is unlawful.
                      9:  *
                     10:  *     COHERENT Version 2.3.37
                     11:  *     Copyright (c) 1982, 1983, 1984.
                     12:  *     An unpublished work by Mark Williams Company, Chicago.
                     13:  *     All rights reserved.
                     14:  -lgl) */
                     15: /*
                     16:  * Coherent.
                     17:  * Storage allocator.
                     18:  *
                     19:  * $Log:       alloc.c,v $
                     20:  * Revision 2.3  93/08/09  13:35:06  bin
                     21:  * Kernel 82 changes
                     22:  * 
                     23:  * Revision 2.2  93/07/26  14:28:19  nigel
                     24:  * Nigel's R80
                     25:  * 
                     26:  * Revision 1.4  93/04/14  10:06:13  root
                     27:  * r75
                     28:  * 
                     29:  * Revision 1.2  92/01/06  11:58:31  hal
                     30:  * Compile with cc.mwc.
                     31:  * 
                     32:  * Revision 1.1        88/03/24  16:13:25      src
                     33:  * Initial revision
                     34:  * 
                     35:  */
                     36: 
                     37: #include <common/ccompat.h>
                     38: #include <common/__parith.h>
                     39: #include <common/_tricks.h>
                     40: #include <kernel/param.h>
                     41: #include <sys/debug.h>
                     42: 
                     43: #include <sys/coherent.h>
                     44: #include <sys/errno.h>
                     45: #include <sys/proc.h>
                     46: 
                     47: #include <kernel/alloc.h>
                     48: 
                     49: /*
                     50:  * Alloc definitions. These used to be in <sys/machine.h> for some unknown
                     51:  * and unknowable reason. They belong here, so now here they are. Since the
                     52:  * person(s) who wrote this stuff neglected to mention what the alignment
                     53:  * issues are, we'll stay with what they did.
                     54:  *
                     55:  * This stuff is aligned on double-byte boundaries and the pointer to the
                     56:  * next block in a circular list is tagged with the status of the current
                     57:  * block. Blocks are not coalesced when freed, that is done by the allocator
                     58:  * when trying to locate a sufficiently large free block.
                     59:  *
                     60:  * As an extra twist, you might have wondered why alloc () tries to loop
                     61:  * twice over the whole arena. It does that because it looks for an exact fit
                     62:  * (after coalescing). The allocator has no memory because there is no actual
                     63:  * overall arena structure, so every call to alloc () will try to coalesce the
                     64:  * entire arena unless there is an exact-sized hole.
                     65:  */
                     66: 
                     67: enum {
                     68:        BLOCK_FREE      = 0,
                     69:        BLOCK_USED
                     70: };
                     71: 
                     72: #define        ALIGN_MASK      1
                     73: #define        align(p)        ((ALL *) ((__ptr_arith_t) (p) & ~ ALIGN_MASK))
                     74: #define        link(p)         align ((p)->a_link)
                     75: #define        tstfree(p)      (((p)->a_link & BLOCK_USED) == BLOCK_FREE)
                     76: 
                     77: #define        MAKE_LINK(a,f)  ((__ptr_arith_t) a + (f))
                     78: #define        MAKE_FREE(a)    ((a)->a_link &= ~ BLOCK_USED)
                     79: #define        MAKE_USED(a)    ((a)->a_link |= BLOCK_USED)
                     80: 
                     81: 
                     82: typedef union all_u {
                     83:        __ptr_arith_t   a_link;
                     84: } ALL;
                     85: 
                     86: 
                     87: #define        NEXT_FIT        1
                     88: 
                     89: #if    NEXT_FIT
                     90: 
                     91: struct _heap {
                     92:        ALL           * _next_block;
                     93: };
                     94: 
                     95: #define        HEAP_CONTROL_SIZE       sizeof (heap_t)
                     96: #define        START_BLOCK(heap)       ((heap)->_next_block)
                     97: #define        SET_START_BLOCK(heap,newstart) \
                     98:                                ((heap)->_next_block = (newstart))
                     99: #else
                    100: 
                    101: #define        HEAP_CONTROL_SIZE       0
                    102: #define        START_BLOCK(heap)       ((ALL *) (heap))
                    103: #define        SET_START_BLOCK(heap,newstart)  ((void) 0)
                    104: 
                    105: #endif
                    106: 
                    107: #ifndef TEST   /* Do not test setarena() or alloc() or free().  */
                    108: 
                    109: /*
                    110:  * Create an arena.
                    111:  */
                    112: 
                    113: heap_t *
                    114: setarena(cp, n)
                    115: register char *cp;
                    116: {
                    117:        ALL           * first_block;
                    118:        ALL           * last_block;
                    119:        heap_t        * heap_control;
                    120: 
                    121:        /*
                    122:         * Begin by aligning the memory passed in and rounding down the size.
                    123:         */
                    124: 
                    125:        {
                    126:                int             align = (__ptr_arith_t) cp & ALIGN_MASK;
                    127: 
                    128:                if (align) {
                    129:                        align = ALIGN_MASK + 1 - align;
                    130:                        cp += align;
                    131:                        n -= align;
                    132:                }
                    133: 
                    134:                n &= ~ sizeof (ALL *);
                    135:        }
                    136: 
                    137:        /*
                    138:         * Make room for a heap control area.
                    139:         */
                    140: 
                    141:        heap_control = (heap_t *) cp;
                    142: 
                    143:        cp += HEAP_CONTROL_SIZE;
                    144:        n -= HEAP_CONTROL_SIZE;
                    145: 
                    146:        first_block = (ALL *) cp;
                    147:        if ((last_block = (ALL *) (cp + n) - 1) < first_block)
                    148:                panic("Arena %x too small", (int) cp);
                    149: 
                    150:        /*
                    151:         * The initial memory arena consists of a circular list of blocks,
                    152:         * one large free block and one tiny used block at the end. In the
                    153:         * original "design", there was no heap control block.
                    154:         */
                    155: 
                    156:        first_block->a_link = MAKE_LINK (last_block, BLOCK_FREE);
                    157:        last_block->a_link = MAKE_LINK (first_block, BLOCK_USED);
                    158: 
                    159:        SET_START_BLOCK (heap_control, first_block);
                    160:        return heap_control;
                    161: }
                    162: 
                    163: 
                    164: #if    0
                    165: /*
                    166:  * NIGEL: This code intrigues me... let's keep statistics.
                    167:  */
                    168: 
                    169: typedef        unsigned long   stat_t;
                    170: 
                    171: static stat_t          _allocations;
                    172: static stat_t          _block_tests;
                    173: static stat_t          _block_fits;
                    174: static stat_t          _exact_fits;
                    175: 
                    176: #define        ADD_STAT(stat)  ((stat += 1) == 0 ? stat -- : 0)
                    177: 
                    178: void dumpstats () {
                    179:        printf ("allocations = %d\ntotal tests = %d\n"
                    180:                "total matches =  %d\nexact fits = %d\n",
                    181:                _allocations, _block_tests, _block_fits, _exact_fits);
                    182: }
                    183: #else
                    184: # define       ADD_STAT(stat)  ((void) 0)
                    185: #endif
                    186: 
                    187: /*
                    188:  * Allocate `l' bytes of memory.
                    189:  */
                    190: 
                    191: __VOID__ *
                    192: alloc (heap_control, size)
                    193: heap_t       * heap_control;
                    194: size_t         size;
                    195: {
                    196:        register ALL *scan_block;
                    197:        register ALL *next_block;
                    198:        register unsigned i;
                    199:        register unsigned n;
                    200:        register unsigned s;
                    201: 
                    202:        ADD_STAT (_allocations);
                    203: 
                    204:        n = 1 + __DIVIDE_ROUNDUP (size, sizeof (ALL));
                    205: 
                    206: #if    EXACT_FIT
                    207:        for (i = 0 ; i < 2 ; i ++) {
                    208: #endif
                    209:                for (scan_block = START_BLOCK (heap_control) ;
                    210:                     link (scan_block) != START_BLOCK (heap_control) ;
                    211:                     scan_block = link (scan_block)) {
                    212:                        ASSERT (vtop (scan_block) != NULL);
                    213:                        ADD_STAT (_block_tests);
                    214: 
                    215:                        if (! tstfree (scan_block))
                    216:                                continue;
                    217: 
                    218:                       for (next_block = link (scan_block) ;
                    219:                            tstfree (next_block) ;
                    220:                            next_block = link (next_block))
                    221:                                if (next_block == START_BLOCK (heap_control))
                    222:                                        break;
                    223: 
                    224:                        scan_block->a_link = MAKE_LINK (next_block,
                    225:                                                        BLOCK_FREE);
                    226:                        if ((s = next_block - scan_block) < n)
                    227:                                continue;
                    228: 
                    229:                        ADD_STAT (_block_fits);
                    230: 
                    231:                        if (s > n) {
                    232: #if    EXACT_FIT
                    233:        /*
                    234:         * This innocent-looking line of code is what makes this system prefer
                    235:         * exact fits (which only happen about 10% of the time from the
                    236:         * statistics which I have collected).
                    237:         */
                    238:                                if (i == 0)
                    239:                                        continue;
                    240: #endif
                    241:                                (scan_block + n)->a_link =
                    242:                                        MAKE_LINK (next_block, BLOCK_FREE);
                    243:                                next_block = scan_block + n;
                    244:                                scan_block->a_link = MAKE_LINK (next_block,
                    245:                                                                BLOCK_FREE);
                    246:                        }
                    247:                        MAKE_USED (scan_block);
                    248:                        SET_START_BLOCK (heap_control, next_block);
                    249: #if    0
                    250:                        memset (scan_block + 1, 0, size);
                    251: #endif
                    252: #if    EXACT_FIT
                    253:                        if (i == 0)
                    254:                                ADD_STAT (_exact_fits);
                    255: #endif
                    256:                        return (__VOID__ *) (scan_block + 1);
                    257:                }
                    258: #if    EXACT_FIT
                    259:        }
                    260: #endif
                    261:        u.u_error = ENOSPC;
                    262:        return NULL;
                    263: }
                    264: 
                    265: /*
                    266:  * Free memory.
                    267:  */
                    268: free(cp)
                    269: char *cp;
                    270: {
                    271:        register ALL *ap;
                    272:        extern char __end;
                    273: 
                    274: #if 0
                    275:        ap = ((ALL *)cp) - 1;
                    276:        if (ap<(ALL *)&__end || tstfree(ap))
                    277:                panic("Bad free %x\n", (unsigned)cp);
                    278: #else
                    279:        ap = ((ALL *)cp) - 1;
                    280:        if (ap<(ALL *)&__end) {
                    281:                int *r = (int *)(&cp);  /* return address */
                    282:                printf("cp=%x ap=%x &__end=%x\n", cp, ap, &__end);
                    283:                panic("Bad free() from eip=%x\n", *(r-1));
                    284:        }
                    285:        if (tstfree(ap)) {
                    286:                int *r = (int *)(&cp);  /* return address */
                    287:                printf("cp=%x tstfree(%x)=%x\n", cp, ap, tstfree(ap));
                    288:                panic("Bad free() from eip=%x\n", *(r-1));
                    289:        }
                    290: #endif
                    291:        MAKE_FREE (ap);
                    292: }
                    293: 
                    294: #endif /* TEST */
                    295: 
                    296: #ifdef _I386
                    297: /*
                    298:  * unsigned char *palloc(int size);
                    299:  *
                    300:  * Allocate 'size' bytes of kernel space, which does not cross a click
                    301:  * boundary.  Returns a pointer to the space allocated on success,
                    302:  * NULL on failure.
                    303:  *
                    304:  * Allocate twice as much memory as we need, and then return a chunk that
                    305:  * does not cross a click boundary.  Immediately before the chunk that
                    306:  * we return, we store the true address of the chunk that was kalloc()'d.
                    307:  *
                    308:  * Since this routine is for relatively small short-lived objects,
                    309:  * which we expect to allocate frequently, speed is more important than
                    310:  * space overhead.
                    311:  *
                    312:  * We assume that kalloc() returns word aligned addresses.
                    313:  *
                    314:  * There are two cases:
                    315:  * There is enough room before the click boundary (or there is no click
                    316:  *     boundary) for the pointer and the memory we need.
                    317:  * Otherwise, return the chunk starting at the click boundary, storing
                    318:  *     the pointer right before the click boundary.  This trick allows
                    319:  *     us to allocate up to 1 full click.
                    320:  *
                    321:  * If kalloc() did NOT return word aligned chunks, then there would be
                    322:  * a third case, where there might not be enough space for the pointer
                    323:  * before the click boundary.
                    324:  */
                    325: 
                    326: #define c_boundry(x)   ctob(btoc((x)+1)) /* Next click boundary above x.  */
                    327: #define VOID   unsigned char
                    328: 
                    329: #ifdef TEST
                    330: #undef kalloc
                    331: #undef kfree
                    332: VOID *kalloc();
                    333: void kfree();
                    334: #endif /* TEST */
                    335: 
                    336: VOID *
                    337: palloc(size)
                    338:        int size;       /* Size in bytes of area to allocate.  */
                    339: {
                    340:        VOID *local_arena;      /* Value returned by kalloc().  */
                    341:        VOID *boundry;          /* Next click boundry above local_arena.  */
                    342:        VOID *retval;           /* What we give back to our caller.  */
                    343: 
                    344:        if (size > NBPC)
                    345:                panic("palloc(%x): can not palloc more than 1 click.", size);
                    346: 
                    347:        /* Fetch twice as much space as requested, plus a pointer.  */
                    348:        if ((local_arena = (VOID *) kalloc (sizeof (VOID *) + (2 * size)))
                    349:            == NULL)
                    350:                return NULL;
                    351:        
                    352:        boundry = (VOID *) c_boundry (local_arena);
                    353: 
                    354:        T_PIGGY(0x2000, printf("b: %x ", boundry));
                    355: 
                    356:        /* First case:  enough space before the boundry.  */
                    357:        if ( (boundry - local_arena) >= (size + sizeof(VOID *)) ) {
                    358: 
                    359:                T_PIGGY(0x2000, printf("c1 "));
                    360: 
                    361:                * (VOID **)local_arena = local_arena;
                    362:                retval = local_arena + sizeof(VOID *);
                    363:        } else if ((boundry - local_arena) < sizeof(VOID *)) {
                    364:                /*
                    365:                 * Second case: There is not enough space before the
                    366:                 * boundry for the whole pointer.
                    367:                 */
                    368:                T_PIGGY(0x2000, printf("c2 "));
                    369: 
                    370:                * (VOID **)local_arena = local_arena;
                    371:                retval = local_arena + sizeof(VOID *);
                    372:        } else {
                    373: 
                    374:                T_PIGGY(0x2000, printf("c3: %x ", (boundry - local_arena)));
                    375: 
                    376:                * (VOID **)(boundry - sizeof(VOID *)) = local_arena;
                    377:                retval = boundry;
                    378:        }
                    379: 
                    380:        T_PIGGY( 0x2000,
                    381:                printf("palloc(%x) = %x:%x (was %x:%x), ",
                    382:                        size, retval, (retval+size)-1,
                    383:                        local_arena, (local_arena+(2*size)+sizeof(VOID *))-1)
                    384:        );
                    385: 
                    386: #if    0
                    387:        /*
                    388:         * NIGEL: Things in trace macros must now be expressions. These ones
                    389:         * weren't worth cleaning up.
                    390:         */
                    391:        T_PIGGY( 0x2000,
                    392:                if ((retval+size)-1 > (local_arena+(2*size)+sizeof(VOID *))-1) {
                    393:                        printf("\npalloc() overrun\n");
                    394:                }
                    395:                if (retval < local_arena) {
                    396:                        printf("\npalloc() underrun\n");
                    397:                }
                    398:        );
                    399: #endif
                    400: 
                    401:        return (VOID *) retval;
                    402: } /* palloc() */
                    403: 
                    404: /*
                    405:  * void pfree(VOID *ptr);
                    406:  * Free the chunk of memory 'ptr' allocated by palloc().
                    407:  *
                    408:  * Note that 'ptr' is really a VOID *, but we call it VOID **
                    409:  * to simplify arithmetic.
                    410:  *
                    411:  * The address returned by kalloc() is stored immediately
                    412:  * before the chunk returned by palloc().
                    413:  */
                    414: void
                    415: pfree(ptr)
                    416:        VOID *ptr[];
                    417: {
                    418:        T_PIGGY(0x2000, printf("pfree(%x):kfree(%x), ", ptr, *(ptr-1)));
                    419:        kfree(*(ptr-1));
                    420: } /* pfree() */
                    421: 
                    422: 
                    423: #ifdef TEST
                    424: 
                    425: #include <sys/compat.h>
                    426: #include <stdio.h>
                    427: #include <stdarg.h>
                    428: 
                    429: #define FOURK  4096    /* How many bytes in 4K?  */
                    430: #define NUM_TESTS 40   /* How many tests do we run?  */
                    431: #define SMALL_NUMBER 6 /* A small number whose exact value we don't care about.  */
                    432: #define HUGE   (100*FOURK)     /* Allocate from this pool.  */
                    433: #define IGNORE(v)      (v==v)  /* Lint food.  */
                    434: 
                    435: unsigned t_piggy = 0x2000;     /* Turn on TRACER bits.  */
                    436: 
                    437: main()
                    438: {
                    439:        int i;
                    440:        VOID *chunk;
                    441: 
                    442:        for (i = 0; i < NUM_TESTS; ++i) {
                    443:                if (NULL == (chunk = palloc(SMALL_NUMBER))) {
                    444:                        printf("No more fake memory to eat.\n");
                    445:                        printf("This is probably a bug.\n");
                    446:                        exit(1);
                    447:                }
                    448: 
                    449:                printf("chunk: %x\n", chunk);
                    450:        }
                    451: } /* main() for TEST */
                    452: 
                    453: /*
                    454:  * Print a message and die.
                    455:  */
                    456: 
                    457: panic(format)
                    458: char * format;
                    459: {
                    460:        va_list args;
                    461:        va_start (args, format);
                    462:        vprintf (format, args);
                    463:        va_end (args);
                    464:        exit(1);
                    465: }
                    466: 
                    467: /*
                    468:  * Fake kalloc() for use by palloc().
                    469:  * Allocate a chunk of some non-existant memory space.
                    470:  */
                    471: VOID *
                    472: kalloc(size)
                    473:        int size;
                    474: {
                    475:        static VOID *base = NULL;
                    476:        static VOID *top_free = NULL;
                    477:        VOID *retval;
                    478: 
                    479: 
                    480:        /*
                    481:         * First time through, allocate a nice big chunk of memory
                    482:         * to carve up.
                    483:         */
                    484:        if (NULL == base) {
                    485:                if (NULL == (base = malloc(HUGE))) {
                    486:                        printf("Can not malloc %d bytes.\n", HUGE);
                    487:                        exit(1);
                    488:                }
                    489:                /* Make sure we start close to a click boundry.  */
                    490:                top_free = c_boundry(base) + SMALL_NUMBER;
                    491:        }
                    492: 
                    493:        retval = top_free;
                    494:        /*
                    495:         * We want to encourage test addresses to migrate accross
                    496:         * click boundries.
                    497:         */
                    498:        if (size < (FOURK - 1)) {
                    499:                top_free += (FOURK - 1);
                    500:        } else {
                    501:                top_free += size;
                    502:        }
                    503: 
                    504:        return(retval);
                    505: } /* kalloc() */
                    506: 
                    507: /*
                    508:  * Fake kfree for pfree() to use.
                    509:  */
                    510: void
                    511: kfree(addr)
                    512:        VOID *addr;
                    513: {
                    514:        IGNORE(addr);
                    515:        /* Do nothing!  */
                    516: } /* kfree() */
                    517: 
                    518: #endif /* TEST */
                    519: 
                    520: #endif /* _I386 */

unix.superglobalmegacorp.com

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