Annotation of OSKit-Mach/kern/zalloc.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1993-1987 Carnegie Mellon University.
                      4:  * Copyright (c) 1993,1994 The University of Utah and
                      5:  * the Computer Systems Laboratory (CSL).
                      6:  * All rights reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
                     15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
                     16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
                     17:  * THIS SOFTWARE.
                     18:  *
                     19:  * Carnegie Mellon requests users of this software to return to
                     20:  *
                     21:  *  Software Distribution Coordinator  or  [email protected]
                     22:  *  School of Computer Science
                     23:  *  Carnegie Mellon University
                     24:  *  Pittsburgh PA 15213-3890
                     25:  *
                     26:  * any improvements or extensions that they make and grant Carnegie Mellon
                     27:  * the rights to redistribute these changes.
                     28:  */
                     29: /*
                     30:  *     File:   kern/zalloc.c
                     31:  *     Author: Avadis Tevanian, Jr.
                     32:  *
                     33:  *     Zone-based memory allocator.  A zone is a collection of fixed size
                     34:  *     data blocks for which quick allocation/deallocation is possible.
                     35:  */
                     36: 
                     37: #include <kern/macro_help.h>
                     38: #include <kern/sched.h>
                     39: #include <kern/time_out.h>
                     40: #include <kern/zalloc.h>
                     41: #include <mach/vm_param.h>
                     42: #include <vm/vm_kern.h>
                     43: #include <machine/machspl.h>
                     44: 
                     45: #include <mach_debug.h>
                     46: #if    MACH_DEBUG
                     47: #include <mach/kern_return.h>
                     48: #include <mach/machine/vm_types.h>
                     49: #include <mach_debug/zone_info.h>
                     50: #include <kern/host.h>
                     51: #include <vm/vm_map.h>
                     52: #include <vm/vm_user.h>
                     53: #include <vm/vm_kern.h>
                     54: #endif
                     55: 
                     56: #define ADD_TO_ZONE(zone, element)                                     \
                     57: MACRO_BEGIN                                                            \
                     58:                *((vm_offset_t *)(element)) = (zone)->free_elements;    \
                     59:                (zone)->free_elements = (vm_offset_t) (element);        \
                     60:                zone_count_down(zone);                                  \
                     61: MACRO_END
                     62: 
                     63: #define REMOVE_FROM_ZONE(zone, ret, type)                              \
                     64: MACRO_BEGIN                                                            \
                     65:        (ret) = (type) (zone)->free_elements;                           \
                     66:        if ((ret) != (type) 0) {                                        \
                     67:                zone_count_up(zone);                                    \
                     68:                (zone)->free_elements = *((vm_offset_t *)(ret));        \
                     69:        }                                                               \
                     70: MACRO_END
                     71: 
                     72: /*
                     73:  * Support for garbage collection of unused zone pages:
                     74:  */
                     75: 
                     76: struct zone_page_table_entry {
                     77:        struct  zone_page_table_entry   *next;
                     78:        short   in_free_list;
                     79:        short   alloc_count;
                     80: };
                     81: 
                     82: extern struct zone_page_table_entry * zone_page_table;
                     83: extern vm_offset_t zone_map_min_address;
                     84: 
                     85: #define lock_zone_page_table() simple_lock(&zone_page_table_lock)
                     86: #define unlock_zone_page_table() simple_unlock(&zone_page_table_lock)
                     87: 
                     88: #define        zone_page(addr) \
                     89:     (&(zone_page_table[(atop(((vm_offset_t)addr) - zone_map_min_address))]))
                     90: 
                     91: 
                     92: extern void            zone_page_alloc();
                     93: extern void            zone_page_dealloc();
                     94: extern void            zone_page_in_use();
                     95: extern void            zone_page_free();
                     96: 
                     97: zone_t         zone_zone;      /* this is the zone containing other zones */
                     98: 
                     99: boolean_t      zone_ignore_overflow = TRUE;
                    100: 
                    101: vm_map_t       zone_map = VM_MAP_NULL;
                    102: vm_size_t      zone_map_size = 12 * 1024 * 1024;
                    103: 
                    104: /*
                    105:  *     The VM system gives us an initial chunk of memory.
                    106:  *     It has to be big enough to allocate the zone_zone
                    107:  *     and some initial kernel data structures, like kernel maps.
                    108:  *     It is advantageous to make it bigger than really necessary,
                    109:  *     because this memory is more efficient than normal kernel
                    110:  *     virtual memory.  (It doesn't have vm_page structures backing it
                    111:  *     and it may have other machine-dependent advantages.)
                    112:  *     So for best performance, zdata_size should approximate
                    113:  *     the amount of memory you expect the zone system to consume.
                    114:  */
                    115: 
                    116: vm_offset_t    zdata;
                    117: vm_size_t      zdata_size = 420 * 1024;
                    118: 
                    119: #define zone_lock(zone)                                        \
                    120: MACRO_BEGIN                                            \
                    121:        if (zone->type & ZONE_PAGEABLE) {               \
                    122:                lock_write(&zone->complex_lock);        \
                    123:        } else {                                        \
                    124:                simple_lock(&zone->lock);               \
                    125:        }                                               \
                    126: MACRO_END
                    127: 
                    128: #define zone_unlock(zone)                              \
                    129: MACRO_BEGIN                                            \
                    130:        if (zone->type & ZONE_PAGEABLE) {               \
                    131:                lock_done(&zone->complex_lock);         \
                    132:        } else {                                        \
                    133:                simple_unlock(&zone->lock);             \
                    134:        }                                               \
                    135: MACRO_END
                    136: 
                    137: #define zone_lock_init(zone)                           \
                    138: MACRO_BEGIN                                            \
                    139:        if (zone->type & ZONE_PAGEABLE) {               \
                    140:                lock_init(&zone->complex_lock, TRUE);   \
                    141:        } else {                                        \
                    142:                simple_lock_init(&zone->lock);          \
                    143:        }                                               \
                    144: MACRO_END
                    145: 
                    146: static vm_offset_t zget_space();
                    147: 
                    148: decl_simple_lock_data(,zget_space_lock)
                    149: vm_offset_t zalloc_next_space;
                    150: vm_offset_t zalloc_end_of_space;
                    151: vm_size_t zalloc_wasted_space;
                    152: 
                    153: /*
                    154:  *     Garbage collection map information
                    155:  */
                    156: decl_simple_lock_data(,zone_page_table_lock)
                    157: struct zone_page_table_entry * zone_page_table;
                    158: vm_offset_t                    zone_map_min_address;
                    159: vm_offset_t                    zone_map_max_address;
                    160: int                            zone_pages;
                    161: 
                    162: extern void zone_page_init();
                    163: 
                    164: #define        ZONE_PAGE_USED  0
                    165: #define ZONE_PAGE_UNUSED -1
                    166: 
                    167: 
                    168: /*
                    169:  *     Protects first_zone, last_zone, num_zones,
                    170:  *     and the next_zone field of zones.
                    171:  */
                    172: decl_simple_lock_data(,all_zones_lock)
                    173: zone_t                 first_zone;
                    174: zone_t                 *last_zone;
                    175: int                    num_zones;
                    176: 
                    177: /*
                    178:  *     zinit initializes a new zone.  The zone data structures themselves
                    179:  *     are stored in a zone, which is initially a static structure that
                    180:  *     is initialized by zone_init.
                    181:  */
                    182: zone_t zinit(size, max, alloc, memtype, name)
                    183:        vm_size_t       size;           /* the size of an element */
                    184:        vm_size_t       max;            /* maximum memory to use */
                    185:        vm_size_t       alloc;          /* allocation size */
                    186:        unsigned int    memtype;        /* flags specifying type of memory */
                    187:        char            *name;          /* a name for the zone */
                    188: {
                    189:        register zone_t         z;
                    190: 
                    191:        if (zone_zone == ZONE_NULL)
                    192:                z = (zone_t) zget_space(sizeof(struct zone));
                    193:        else
                    194:                z = (zone_t) zalloc(zone_zone);
                    195:        if (z == ZONE_NULL)
                    196:                panic("zinit");
                    197: 
                    198:        if (alloc == 0)
                    199:                alloc = PAGE_SIZE;
                    200: 
                    201:        if (size == 0)
                    202:                size = sizeof(z->free_elements);
                    203:        /*
                    204:         *      Round off all the parameters appropriately.
                    205:         */
                    206: 
                    207:        if ((max = round_page(max)) < (alloc = round_page(alloc)))
                    208:                max = alloc;
                    209: 
                    210:        z->free_elements = 0;
                    211:        z->cur_size = 0;
                    212:        z->max_size = max;
                    213:        z->elem_size = ((size-1) + sizeof(z->free_elements)) -
                    214:                        ((size-1) % sizeof(z->free_elements));
                    215: 
                    216:        z->alloc_size = alloc;
                    217:        z->type = memtype;
                    218:        z->zone_name = name;
                    219: #ifdef ZONE_COUNT
                    220:        z->count = 0;
                    221: #endif
                    222:        z->doing_alloc = FALSE;
                    223:        zone_lock_init(z);
                    224: 
                    225:        /*
                    226:         *      Add the zone to the all-zones list.
                    227:         */
                    228: 
                    229:        z->next_zone = ZONE_NULL;
                    230:        simple_lock(&all_zones_lock);
                    231:        *last_zone = z;
                    232:        last_zone = &z->next_zone;
                    233:        num_zones++;
                    234:        simple_unlock(&all_zones_lock);
                    235: 
                    236:        return(z);
                    237: }
                    238: 
                    239: /*
                    240:  *     Cram the given memory into the specified zone.
                    241:  */
                    242: void zcram(zone_t zone, vm_offset_t newmem, vm_size_t size)
                    243: {
                    244:        register vm_size_t      elem_size;
                    245: 
                    246:        if (newmem == (vm_offset_t) 0) {
                    247:                panic("zcram - memory at zero");
                    248:        }
                    249:        elem_size = zone->elem_size;
                    250: 
                    251:        zone_lock(zone);
                    252:        while (size >= elem_size) {
                    253:                ADD_TO_ZONE(zone, newmem);
                    254:                zone_page_alloc(newmem, elem_size);
                    255:                zone_count_up(zone);    /* compensate for ADD_TO_ZONE */
                    256:                size -= elem_size;
                    257:                newmem += elem_size;
                    258:                zone->cur_size += elem_size;
                    259:        }
                    260:        zone_unlock(zone);
                    261: }
                    262: 
                    263: /*
                    264:  * Contiguous space allocator for non-paged zones. Allocates "size" amount
                    265:  * of memory from zone_map.
                    266:  */
                    267: 
                    268: static vm_offset_t zget_space(vm_offset_t size)
                    269: {
                    270:        vm_offset_t     new_space = 0;
                    271:        vm_offset_t     result;
                    272:        vm_size_t       space_to_add = 0; /*'=0' to quiet gcc warnings */
                    273: 
                    274:        simple_lock(&zget_space_lock);
                    275:        while ((zalloc_next_space + size) > zalloc_end_of_space) {
                    276:                /*
                    277:                 *      Add at least one page to allocation area.
                    278:                 */
                    279: 
                    280:                space_to_add = round_page(size);
                    281: 
                    282:                if (new_space == 0) {
                    283:                        /*
                    284:                         *      Memory cannot be wired down while holding
                    285:                         *      any locks that the pageout daemon might
                    286:                         *      need to free up pages.  [Making the zget_space
                    287:                         *      lock a complex lock does not help in this
                    288:                         *      regard.]
                    289:                         *
                    290:                         *      Unlock and allocate memory.  Because several
                    291:                         *      threads might try to do this at once, don't
                    292:                         *      use the memory before checking for available
                    293:                         *      space again.
                    294:                         */
                    295: 
                    296:                        simple_unlock(&zget_space_lock);
                    297: 
                    298:                        if (kmem_alloc_wired(zone_map,
                    299:                                             &new_space, space_to_add)
                    300:                                                        != KERN_SUCCESS)
                    301:                                return(0);
                    302:                        zone_page_init(new_space, space_to_add,
                    303:                                                        ZONE_PAGE_USED);
                    304:                        simple_lock(&zget_space_lock);
                    305:                        continue;
                    306:                }
                    307: 
                    308: 
                    309:                /*
                    310:                 *      Memory was allocated in a previous iteration.
                    311:                 *
                    312:                 *      Check whether the new region is contiguous
                    313:                 *      with the old one.
                    314:                 */
                    315: 
                    316:                if (new_space != zalloc_end_of_space) {
                    317:                        /*
                    318:                         *      Throw away the remainder of the
                    319:                         *      old space, and start a new one.
                    320:                         */
                    321:                        zalloc_wasted_space +=
                    322:                                zalloc_end_of_space - zalloc_next_space;
                    323:                        zalloc_next_space = new_space;
                    324:                }
                    325: 
                    326:                zalloc_end_of_space = new_space + space_to_add;
                    327: 
                    328:                new_space = 0;
                    329:        }
                    330:        result = zalloc_next_space;
                    331:        zalloc_next_space += size;
                    332:        simple_unlock(&zget_space_lock);
                    333: 
                    334:        if (new_space != 0)
                    335:                kmem_free(zone_map, new_space, space_to_add);
                    336: 
                    337:        return(result);
                    338: }
                    339: 
                    340: 
                    341: /*
                    342:  *     Initialize the "zone of zones" which uses fixed memory allocated
                    343:  *     earlier in memory initialization.  zone_bootstrap is called
                    344:  *     before zone_init.
                    345:  */
                    346: void zone_bootstrap()
                    347: {
                    348:        simple_lock_init(&all_zones_lock);
                    349:        first_zone = ZONE_NULL;
                    350:        last_zone = &first_zone;
                    351:        num_zones = 0;
                    352: 
                    353:        simple_lock_init(&zget_space_lock);
                    354:        zalloc_next_space = zdata;
                    355:        zalloc_end_of_space = zdata + zdata_size;
                    356:        zalloc_wasted_space = 0;
                    357: 
                    358:        zone_zone = ZONE_NULL;
                    359:        zone_zone = zinit(sizeof(struct zone), 128 * sizeof(struct zone),
                    360:                          sizeof(struct zone), 0, "zones");
                    361: }
                    362: 
                    363: void zone_init()
                    364: {
                    365:        vm_offset_t     zone_min;
                    366:        vm_offset_t     zone_max;
                    367: 
                    368:        vm_size_t       zone_table_size;
                    369: 
                    370:        zone_map = kmem_suballoc(kernel_map, &zone_min, &zone_max,
                    371:                                 zone_map_size, FALSE);
                    372: 
                    373:        /*
                    374:         * Setup garbage collection information:
                    375:         */
                    376: 
                    377:        zone_table_size = atop(zone_max - zone_min) *
                    378:                                sizeof(struct zone_page_table_entry);
                    379:        if (kmem_alloc_wired(zone_map, (vm_offset_t *) &zone_page_table,
                    380:                             zone_table_size) != KERN_SUCCESS)
                    381:                panic("zone_init");
                    382:        zone_min = (vm_offset_t)zone_page_table + round_page(zone_table_size);
                    383:        zone_pages = atop(zone_max - zone_min);
                    384:        zone_map_min_address = zone_min;
                    385:        zone_map_max_address = zone_max;
                    386:        simple_lock_init(&zone_page_table_lock);
                    387:        zone_page_init(zone_min, zone_max - zone_min, ZONE_PAGE_UNUSED);
                    388: }
                    389: 
                    390: 
                    391: /*
                    392:  *     zalloc returns an element from the specified zone.
                    393:  */
                    394: vm_offset_t zalloc(zone_t zone)
                    395: {
                    396:        vm_offset_t     addr;
                    397: 
                    398:        if (zone == ZONE_NULL)
                    399:                panic ("zalloc: null zone");
                    400: 
                    401:        check_simple_locks();
                    402: 
                    403:        zone_lock(zone);
                    404:        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                    405:        while (addr == 0) {
                    406:                /*
                    407:                 *      If nothing was there, try to get more
                    408:                 */
                    409:                if (zone->doing_alloc) {
                    410:                        /*
                    411:                         *      Someone is allocating memory for this zone.
                    412:                         *      Wait for it to show up, then try again.
                    413:                         */
                    414:                        assert_wait((event_t)&zone->doing_alloc, TRUE);
                    415:                        /* XXX say wakeup needed */
                    416:                        zone_unlock(zone);
                    417:                        thread_block((void (*)()) 0);
                    418:                        zone_lock(zone);
                    419:                }
                    420:                else {
                    421:                        if ((zone->cur_size + (zone->type & ZONE_PAGEABLE ?
                    422:                                zone->alloc_size : zone->elem_size)) >
                    423:                            zone->max_size) {
                    424:                                if (zone->type & ZONE_EXHAUSTIBLE)
                    425:                                        break;
                    426:                                /*
                    427:                                 * Printf calls logwakeup, which calls
                    428:                                 * select_wakeup which will do a zfree
                    429:                                 * (which tries to take the select_zone
                    430:                                 * lock... Hang.  Release the lock now
                    431:                                 * so it can be taken again later.
                    432:                                 * NOTE: this used to be specific to
                    433:                                 * the select_zone, but for
                    434:                                 * cleanliness, we just unlock all
                    435:                                 * zones before this.
                    436:                                 */
                    437:                                if (!(zone->type & ZONE_FIXED)) {
                    438:                                        /*
                    439:                                         * We're willing to overflow certain
                    440:                                         * zones, but not without complaining.
                    441:                                         *
                    442:                                         * This is best used in conjunction
                    443:                                         * with the collecatable flag. What we
                    444:                                         * want is an assurance we can get the
                    445:                                         * memory back, assuming there's no
                    446:                                         * leak.
                    447:                                         */
                    448:                                        zone->max_size += (zone->max_size >> 1);
                    449:                                } else if (!zone_ignore_overflow) {
                    450:                                        zone_unlock(zone);
                    451:                                        printf("zone \"%s\" empty.\n",
                    452:                                                zone->zone_name);
                    453:                                        panic("zalloc: zone %s exhausted",
                    454:                                              zone->zone_name);
                    455:                                }
                    456:                        }
                    457: 
                    458:                        if (zone->type & ZONE_PAGEABLE)
                    459:                                zone->doing_alloc = TRUE;
                    460:                        zone_unlock(zone);
                    461: 
                    462:                        if (zone->type & ZONE_PAGEABLE) {
                    463:                                if (kmem_alloc_pageable(zone_map, &addr,
                    464:                                                        zone->alloc_size)
                    465:                                                        != KERN_SUCCESS)
                    466:                                        panic("zalloc: zone %s exhausted",
                    467:                                              zone->zone_name);
                    468:                                zcram(zone, addr, zone->alloc_size);
                    469:                                zone_lock(zone);
                    470:                                zone->doing_alloc = FALSE;
                    471:                                /* XXX check before doing this */
                    472:                                thread_wakeup((event_t)&zone->doing_alloc);
                    473: 
                    474:                                REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                    475:                        } else  if (zone->type & ZONE_COLLECTABLE) {
                    476:                                if (kmem_alloc_wired(zone_map,
                    477:                                                     &addr, zone->alloc_size)
                    478:                                                        != KERN_SUCCESS)
                    479:                                        panic("zalloc: zone %s exhausted",
                    480:                                              zone->zone_name);
                    481:                                zone_page_init(addr, zone->alloc_size,
                    482:                                                        ZONE_PAGE_USED);
                    483:                                zcram(zone, addr, zone->alloc_size);
                    484:                                zone_lock(zone);
                    485:                                REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                    486:                        } else {
                    487:                                addr = zget_space(zone->elem_size);
                    488:                                if (addr == 0)
                    489:                                        panic("zalloc: zone %s exhausted",
                    490:                                              zone->zone_name);
                    491: 
                    492:                                zone_lock(zone);
                    493:                                zone_count_up(zone);
                    494:                                zone->cur_size += zone->elem_size;
                    495:                                zone_unlock(zone);
                    496:                                zone_page_alloc(addr, zone->elem_size);
                    497:                                return(addr);
                    498:                        }
                    499:                }
                    500:        }
                    501: 
                    502:        zone_unlock(zone);
                    503:        return(addr);
                    504: }
                    505: 
                    506: 
                    507: /*
                    508:  *     zget returns an element from the specified zone
                    509:  *     and immediately returns nothing if there is nothing there.
                    510:  *
                    511:  *     This form should be used when you can not block (like when
                    512:  *     processing an interrupt).
                    513:  */
                    514: vm_offset_t zget(zone_t zone)
                    515: {
                    516:        register vm_offset_t    addr;
                    517: 
                    518:        if (zone == ZONE_NULL)
                    519:                panic ("zalloc: null zone");
                    520: 
                    521:        zone_lock(zone);
                    522:        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                    523:        zone_unlock(zone);
                    524: 
                    525:        return(addr);
                    526: }
                    527: 
                    528: boolean_t zone_check = FALSE;
                    529: 
                    530: void zfree(zone_t zone, vm_offset_t elem)
                    531: {
                    532:        zone_lock(zone);
                    533:        if (zone_check) {
                    534:                vm_offset_t this;
                    535: 
                    536:                /* check the zone's consistency */
                    537: 
                    538:                for (this = zone->free_elements;
                    539:                     this != 0;
                    540:                     this = * (vm_offset_t *) this)
                    541:                        if (this == elem)
                    542:                                panic("zfree");
                    543:        }
                    544:        ADD_TO_ZONE(zone, elem);
                    545:        zone_unlock(zone);
                    546: }
                    547: 
                    548: /*
                    549:  *  Zone garbage collection subroutines
                    550:  *
                    551:  *  These routines have in common the modification of entries in the
                    552:  *  zone_page_table.  The latter contains one entry for every page
                    553:  *  in the zone_map.
                    554:  *
                    555:  *  For each page table entry in the given range:
                    556:  *
                    557:  *     zone_page_in_use        - decrements in_free_list
                    558:  *     zone_page_free          - increments in_free_list
                    559:  *     zone_page_init          - initializes in_free_list and alloc_count
                    560:  *     zone_page_alloc         - increments alloc_count
                    561:  *     zone_page_dealloc       - decrements alloc_count
                    562:  *     zone_add_free_page_list - adds the page to the free list
                    563:  *
                    564:  *  Two counts are maintained for each page, the in_free_list count and
                    565:  *  alloc_count.  The alloc_count is how many zone elements have been
                    566:  *  allocated from a page.  (Note that the page could contain elements
                    567:  *  that span page boundaries.  The count includes these elements so
                    568:  *  one element may be counted in two pages.) In_free_list is a count
                    569:  *  of how many zone elements are currently free.  If in_free_list is
                    570:  *  equal to alloc_count then the page is eligible for garbage
                    571:  *  collection.
                    572:  *
                    573:  *  Alloc_count and in_free_list are initialized to the correct values
                    574:  *  for a particular zone when a page is zcram'ed into a zone.  Subsequent
                    575:  *  gets and frees of zone elements will call zone_page_in_use and
                    576:  *  zone_page_free which modify the in_free_list count.  When the zones
                    577:  *  garbage collector runs it will walk through a zones free element list,
                    578:  *  remove the elements that reside on collectable pages, and use
                    579:  *  zone_add_free_page_list to create a list of pages to be collected.
                    580:  */
                    581: 
                    582: void zone_page_in_use(addr, size)
                    583: vm_offset_t    addr;
                    584: vm_size_t      size;
                    585: {
                    586:        int i, j;
                    587:        if ((addr < zone_map_min_address) ||
                    588:            (addr+size > zone_map_max_address)) return;
                    589:        i = atop(addr-zone_map_min_address);
                    590:        j = atop((addr+size-1) - zone_map_min_address);
                    591:        lock_zone_page_table();
                    592:        for (; i <= j; i++) {
                    593:                zone_page_table[i].in_free_list--;
                    594:        }
                    595:        unlock_zone_page_table();
                    596: }
                    597: 
                    598: void zone_page_free(addr, size)
                    599: vm_offset_t    addr;
                    600: vm_size_t      size;
                    601: {
                    602:        int i, j;
                    603:        if ((addr < zone_map_min_address) ||
                    604:            (addr+size > zone_map_max_address)) return;
                    605:        i = atop(addr-zone_map_min_address);
                    606:        j = atop((addr+size-1) - zone_map_min_address);
                    607:        lock_zone_page_table();
                    608:        for (; i <= j; i++) {
                    609:                /* Set in_free_list to (ZONE_PAGE_USED + 1) if
                    610:                 * it was previously set to ZONE_PAGE_UNUSED.
                    611:                 */
                    612:                if (zone_page_table[i].in_free_list == ZONE_PAGE_UNUSED) {
                    613:                        zone_page_table[i].in_free_list = 1;
                    614:                } else {
                    615:                        zone_page_table[i].in_free_list++;
                    616:                }
                    617:        }
                    618:        unlock_zone_page_table();
                    619: }
                    620: 
                    621: void zone_page_init(addr, size, value)
                    622: 
                    623: vm_offset_t    addr;
                    624: vm_size_t      size;
                    625: int            value;
                    626: {
                    627:        int i, j;
                    628:        if ((addr < zone_map_min_address) ||
                    629:            (addr+size > zone_map_max_address)) return;
                    630:        i = atop(addr-zone_map_min_address);
                    631:        j = atop((addr+size-1) - zone_map_min_address);
                    632:        lock_zone_page_table();
                    633:        for (; i <= j; i++) {
                    634:                zone_page_table[i].alloc_count = value;
                    635:                zone_page_table[i].in_free_list = 0;
                    636:        }
                    637:        unlock_zone_page_table();
                    638: }
                    639: 
                    640: void zone_page_alloc(addr, size)
                    641: vm_offset_t    addr;
                    642: vm_size_t      size;
                    643: {
                    644:        int i, j;
                    645:        if ((addr < zone_map_min_address) ||
                    646:            (addr+size > zone_map_max_address)) return;
                    647:        i = atop(addr-zone_map_min_address);
                    648:        j = atop((addr+size-1) - zone_map_min_address);
                    649:        lock_zone_page_table();
                    650:        for (; i <= j; i++) {
                    651:                /* Set alloc_count to (ZONE_PAGE_USED + 1) if
                    652:                 * it was previously set to ZONE_PAGE_UNUSED.
                    653:                 */
                    654:                if (zone_page_table[i].alloc_count == ZONE_PAGE_UNUSED) {
                    655:                        zone_page_table[i].alloc_count = 1;
                    656:                } else {
                    657:                        zone_page_table[i].alloc_count++;
                    658:                }
                    659:        }
                    660:        unlock_zone_page_table();
                    661: }
                    662: 
                    663: void zone_page_dealloc(addr, size)
                    664: vm_offset_t    addr;
                    665: vm_size_t      size;
                    666: {
                    667:        int i, j;
                    668:        if ((addr < zone_map_min_address) ||
                    669:            (addr+size > zone_map_max_address)) return;
                    670:        i = atop(addr-zone_map_min_address);
                    671:        j = atop((addr+size-1) - zone_map_min_address);
                    672:        lock_zone_page_table();
                    673:        for (; i <= j; i++) {
                    674:                zone_page_table[i].alloc_count--;
                    675:        }
                    676:        unlock_zone_page_table();
                    677: }
                    678: 
                    679: void
                    680: zone_add_free_page_list(free_list, addr, size)
                    681:        struct zone_page_table_entry    **free_list;
                    682:        vm_offset_t     addr;
                    683:        vm_size_t       size;
                    684: {
                    685:        int i, j;
                    686:        if ((addr < zone_map_min_address) ||
                    687:            (addr+size > zone_map_max_address)) return;
                    688:        i = atop(addr-zone_map_min_address);
                    689:        j = atop((addr+size-1) - zone_map_min_address);
                    690:        lock_zone_page_table();
                    691:        for (; i <= j; i++) {
                    692:                if (zone_page_table[i].alloc_count == 0) {
                    693:                        zone_page_table[i].next = *free_list;
                    694:                        *free_list = &zone_page_table[i];
                    695:                        zone_page_table[i].alloc_count  = ZONE_PAGE_UNUSED;
                    696:                        zone_page_table[i].in_free_list = 0;
                    697:                }
                    698:        }
                    699:        unlock_zone_page_table();
                    700: }
                    701: 
                    702: 
                    703: /* This is used for walking through a zone's free element list.
                    704:  */
                    705: struct zone_free_entry {
                    706:        struct zone_free_entry * next;
                    707: };
                    708: 
                    709: 
                    710: /*     Zone garbage collection
                    711:  *
                    712:  *     zone_gc will walk through all the free elements in all the
                    713:  *     zones that are marked collectable looking for reclaimable
                    714:  *     pages.  zone_gc is called by consider_zone_gc when the system
                    715:  *     begins to run out of memory.
                    716:  */
                    717: static void zone_gc()
                    718: {
                    719:        int             max_zones;
                    720:        zone_t          z;
                    721:        int             i;
                    722:        register spl_t  s;
                    723:        struct zone_page_table_entry    *freep;
                    724:        struct zone_page_table_entry    *zone_free_page_list;
                    725: 
                    726:        simple_lock(&all_zones_lock);
                    727:        max_zones = num_zones;
                    728:        z = first_zone;
                    729:        simple_unlock(&all_zones_lock);
                    730: 
                    731:        zone_free_page_list = (struct zone_page_table_entry *) 0;
                    732: 
                    733:        for (i = 0; i < max_zones; i++) {
                    734:                struct zone_free_entry * last;
                    735:                struct zone_free_entry * elt;
                    736:                assert(z != ZONE_NULL);
                    737:        /* run this at splhigh so that interupt routines that use zones
                    738:           can not interupt while their zone is locked */
                    739:                s=splhigh();
                    740:                zone_lock(z);
                    741: 
                    742:                if ((z->type & (ZONE_PAGEABLE|ZONE_COLLECTABLE)) == ZONE_COLLECTABLE) {
                    743: 
                    744:                    /* Count the free elements in each page.  This loop
                    745:                     * requires that all in_free_list entries are zero.
                    746:                     */
                    747:                    elt = (struct zone_free_entry *)(z->free_elements);
                    748:                    while ((elt != (struct zone_free_entry *)0)) {
                    749:                           zone_page_free((vm_offset_t)elt, z->elem_size);
                    750:                           elt = elt->next;
                    751:                    }
                    752: 
                    753:                    /* Now determine which elements should be removed
                    754:                     * from the free list and, after all the elements
                    755:                     * on a page have been removed, add the element's
                    756:                     * page to a list of pages to be freed.
                    757:                     */
                    758:                    elt = (struct zone_free_entry *)(z->free_elements);
                    759:                    last = elt;
                    760:                    while ((elt != (struct zone_free_entry *)0)) {
                    761:                        if (((vm_offset_t)elt>=zone_map_min_address)&&
                    762:                            ((vm_offset_t)elt<=zone_map_max_address)&&
                    763:                            (zone_page(elt)->in_free_list ==
                    764:                             zone_page(elt)->alloc_count)) {
                    765: 
                    766:                            z->cur_size -= z->elem_size;
                    767:                            zone_page_in_use((vm_offset_t)elt, z->elem_size);
                    768:                            zone_page_dealloc((vm_offset_t)elt, z->elem_size);
                    769:                            if (zone_page(elt)->alloc_count == 0 ||
                    770:                              zone_page(elt+(z->elem_size-1))->alloc_count==0) {
                    771:                                    zone_add_free_page_list(
                    772:                                            &zone_free_page_list,
                    773:                                            (vm_offset_t)elt, z->elem_size);
                    774:                            }
                    775: 
                    776: 
                    777:                            if (elt == last) {
                    778:                                elt = elt->next;
                    779:                                z->free_elements =(vm_offset_t)elt;
                    780:                                last = elt;
                    781:                            } else {
                    782:                                last->next = elt->next;
                    783:                                elt = elt->next;
                    784:                            }
                    785:                        } else {
                    786:                            /* This element is not eligible for collection
                    787:                             * so clear in_free_list in preparation for a
                    788:                             * subsequent garbage collection pass.
                    789:                             */
                    790:                            if (((vm_offset_t)elt>=zone_map_min_address)&&
                    791:                                ((vm_offset_t)elt<=zone_map_max_address)) {
                    792:                                zone_page(elt)->in_free_list = 0;
                    793:                            }
                    794:                            last = elt;
                    795:                            elt = elt->next;
                    796:                        }
                    797:                    }
                    798:                }
                    799:                zone_unlock(z);
                    800:                splx(s);
                    801:                simple_lock(&all_zones_lock);
                    802:                z = z->next_zone;
                    803:                simple_unlock(&all_zones_lock);
                    804:        }
                    805: 
                    806:        for (freep = zone_free_page_list; freep != 0; freep = freep->next) {
                    807:                vm_offset_t     free_addr;
                    808: 
                    809:                free_addr = zone_map_min_address +
                    810:                        PAGE_SIZE * (freep - zone_page_table);
                    811:                kmem_free(zone_map, free_addr, PAGE_SIZE);
                    812:        }
                    813: }
                    814: 
                    815: boolean_t zone_gc_allowed = TRUE;
                    816: unsigned zone_gc_last_tick = 0;
                    817: unsigned zone_gc_max_rate = 0;         /* in ticks */
                    818: 
                    819: /*
                    820:  *     consider_zone_gc:
                    821:  *
                    822:  *     Called by the pageout daemon when the system needs more free pages.
                    823:  */
                    824: 
                    825: void
                    826: consider_zone_gc()
                    827: {
                    828:        /*
                    829:         *      By default, don't attempt zone GC more frequently
                    830:         *      than once a second.
                    831:         */
                    832: 
                    833:        if (zone_gc_max_rate == 0)
                    834:                zone_gc_max_rate = hz;
                    835: 
                    836:        if (zone_gc_allowed &&
                    837:            (sched_tick > (zone_gc_last_tick + zone_gc_max_rate))) {
                    838:                zone_gc_last_tick = sched_tick;
                    839:                zone_gc();
                    840:        }
                    841: }
                    842: 
                    843: #if    MACH_DEBUG
                    844: kern_return_t host_zone_info(host, namesp, namesCntp, infop, infoCntp)
                    845:        host_t          host;
                    846:        zone_name_array_t *namesp;
                    847:        unsigned int    *namesCntp;
                    848:        zone_info_array_t *infop;
                    849:        unsigned int    *infoCntp;
                    850: {
                    851:        zone_name_t     *names;
                    852:        vm_offset_t     names_addr;
                    853:        vm_size_t       names_size = 0; /*'=0' to quiet gcc warnings */
                    854:        zone_info_t     *info;
                    855:        vm_offset_t     info_addr;
                    856:        vm_size_t       info_size = 0; /*'=0' to quiet gcc warnings */
                    857:        unsigned int    max_zones, i;
                    858:        zone_t          z;
                    859:        kern_return_t   kr;
                    860: 
                    861:        if (host == HOST_NULL)
                    862:                return KERN_INVALID_HOST;
                    863: 
                    864:        /*
                    865:         *      We assume that zones aren't freed once allocated.
                    866:         *      We won't pick up any zones that are allocated later.
                    867:         */
                    868: 
                    869:        simple_lock(&all_zones_lock);
                    870:        max_zones = num_zones;
                    871:        z = first_zone;
                    872:        simple_unlock(&all_zones_lock);
                    873: 
                    874:        if (max_zones <= *namesCntp) {
                    875:                /* use in-line memory */
                    876: 
                    877:                names = *namesp;
                    878:        } else {
                    879:                names_size = round_page(max_zones * sizeof *names);
                    880:                kr = kmem_alloc_pageable(ipc_kernel_map,
                    881:                                         &names_addr, names_size);
                    882:                if (kr != KERN_SUCCESS)
                    883:                        return kr;
                    884: 
                    885:                names = (zone_name_t *) names_addr;
                    886:        }
                    887: 
                    888:        if (max_zones <= *infoCntp) {
                    889:                /* use in-line memory */
                    890: 
                    891:                info = *infop;
                    892:        } else {
                    893:                info_size = round_page(max_zones * sizeof *info);
                    894:                kr = kmem_alloc_pageable(ipc_kernel_map,
                    895:                                         &info_addr, info_size);
                    896:                if (kr != KERN_SUCCESS) {
                    897:                        if (names != *namesp)
                    898:                                kmem_free(ipc_kernel_map,
                    899:                                          names_addr, names_size);
                    900:                        return kr;
                    901:                }
                    902: 
                    903:                info = (zone_info_t *) info_addr;
                    904:        }
                    905: 
                    906:        for (i = 0; i < max_zones; i++) {
                    907:                zone_name_t *zn = &names[i];
                    908:                zone_info_t *zi = &info[i];
                    909:                struct zone zcopy;
                    910: 
                    911:                assert(z != ZONE_NULL);
                    912: 
                    913:                zone_lock(z);
                    914:                zcopy = *z;
                    915:                zone_unlock(z);
                    916: 
                    917:                simple_lock(&all_zones_lock);
                    918:                z = z->next_zone;
                    919:                simple_unlock(&all_zones_lock);
                    920: 
                    921:                /* assuming here the name data is static */
                    922:                (void) strncpy(zn->zn_name, zcopy.zone_name,
                    923:                               sizeof zn->zn_name);
                    924: 
                    925: #ifdef ZONE_COUNT
                    926:                zi->zi_count = zcopy.count;
                    927: #else
                    928:                zi->zi_count = 0;
                    929: #endif
                    930:                zi->zi_cur_size = zcopy.cur_size;
                    931:                zi->zi_max_size = zcopy.max_size;
                    932:                zi->zi_elem_size = zcopy.elem_size;
                    933:                zi->zi_alloc_size = zcopy.alloc_size;
                    934:                zi->zi_pageable = (zcopy.type & ZONE_PAGEABLE) != 0;
                    935:                zi->zi_exhaustible = (zcopy.type & ZONE_EXHAUSTIBLE) != 0;
                    936:                zi->zi_collectable = (zcopy.type & ZONE_COLLECTABLE) != 0;
                    937:        }
                    938: 
                    939:        if (names != *namesp) {
                    940:                vm_size_t used;
                    941:                vm_map_copy_t copy;
                    942: 
                    943:                used = max_zones * sizeof *names;
                    944: 
                    945:                if (used != names_size)
                    946:                        bzero((char *) (names_addr + used), names_size - used);
                    947: 
                    948:                kr = vm_map_copyin(ipc_kernel_map, names_addr, names_size,
                    949:                                   TRUE, &copy);
                    950:                assert(kr == KERN_SUCCESS);
                    951: 
                    952:                *namesp = (zone_name_t *) copy;
                    953:        }
                    954:        *namesCntp = max_zones;
                    955: 
                    956:        if (info != *infop) {
                    957:                vm_size_t used;
                    958:                vm_map_copy_t copy;
                    959: 
                    960:                used = max_zones * sizeof *info;
                    961: 
                    962:                if (used != info_size)
                    963:                        bzero((char *) (info_addr + used), info_size - used);
                    964: 
                    965:                kr = vm_map_copyin(ipc_kernel_map, info_addr, info_size,
                    966:                                   TRUE, &copy);
                    967:                assert(kr == KERN_SUCCESS);
                    968: 
                    969:                *infop = (zone_info_t *) copy;
                    970:        }
                    971:        *infoCntp = max_zones;
                    972: 
                    973:        return KERN_SUCCESS;
                    974: }
                    975: #endif /* MACH_DEBUG */

unix.superglobalmegacorp.com

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