Annotation of XNU/osfmk/kern/zalloc.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: /*
        !            51:  */
        !            52: /*
        !            53:  *     File:   kern/zalloc.c
        !            54:  *     Author: Avadis Tevanian, Jr.
        !            55:  *
        !            56:  *     Zone-based memory allocator.  A zone is a collection of fixed size
        !            57:  *     data blocks for which quick allocation/deallocation is possible.
        !            58:  */
        !            59: 
        !            60: #include <zone_debug.h>
        !            61: #include <norma_vm.h>
        !            62: #include <mach_kdb.h>
        !            63: #include <kern/assert.h>
        !            64: #include <kern/macro_help.h>
        !            65: #include <kern/sched.h>
        !            66: #include <kern/lock.h>
        !            67: #include <kern/sched_prim.h>
        !            68: #include <kern/misc_protos.h>
        !            69: #include <kern/zalloc.h>
        !            70: #include <kern/rtmalloc.h>
        !            71: #include <mach/vm_param.h>
        !            72: #include <vm/vm_kern.h>
        !            73: #include <machine/machparam.h>
        !            74: 
        !            75: 
        !            76: #if    MACH_ASSERT
        !            77: 
        !            78: /* Detect use of zone elt after freeing it by two methods:
        !            79:  * (1) Range-check the free-list "next" ptr for sanity.
        !            80:  * (2) Store the ptr in two different words, and compare them against
        !            81:  *     each other when re-using the zone elt, to detect modifications;
        !            82:  */
        !            83: 
        !            84: #if defined(__alpha)
        !            85: 
        !            86: #define is_kernel_data_addr(a)                                         \
        !            87:                (!(a) || IS_SYS_VA(a) && !((a) & (sizeof(long)-1)))
        !            88: 
        !            89: #else /* !defined(__alpha) */
        !            90: 
        !            91: #define is_kernel_data_addr(a)                                         \
        !            92:                (!(a) || (a) >= VM_MIN_KERNEL_ADDRESS && !((a) & 0x3))
        !            93: 
        !            94: #endif /* defined(__alpha) */
        !            95: 
        !            96: /* Should we set all words of the zone element to an illegal address
        !            97:  * when it is freed, to help catch usage after freeing?  The down-side
        !            98:  * is that this obscures the identity of the freed element.
        !            99:  */
        !           100: boolean_t zfree_clear = FALSE;
        !           101: 
        !           102: #define ADD_TO_ZONE(zone, element)                                     \
        !           103: MACRO_BEGIN                                                            \
        !           104:                if (zfree_clear)                                        \
        !           105:                {   int i;                                              \
        !           106:                    for (i=1;                                           \
        !           107:                         i < zone->elem_size/sizeof(vm_offset_t) - 1;   \
        !           108:                         i++)                                           \
        !           109:                    ((vm_offset_t *)(element))[i] = 0xdeadbeef;         \
        !           110:                }                                                       \
        !           111:                ((vm_offset_t *)(element))[0] = (zone)->free_elements;  \
        !           112:                (zone)->free_elements = (vm_offset_t) (element);        \
        !           113:                (zone)->count--;                                        \
        !           114: MACRO_END
        !           115: 
        !           116: #define REMOVE_FROM_ZONE(zone, ret, type)                              \
        !           117: MACRO_BEGIN                                                            \
        !           118:        (ret) = (type) (zone)->free_elements;                           \
        !           119:        if ((ret) != (type) 0) {                                        \
        !           120:            if (!is_kernel_data_addr(((vm_offset_t *)(ret))[0])) {      \
        !           121:                panic("A freed zone element has been modified.\n");     \
        !           122:            }                                                           \
        !           123:            (zone)->count++;                                            \
        !           124:            (zone)->free_elements = *((vm_offset_t *)(ret));            \
        !           125:        }                                                               \
        !           126: MACRO_END
        !           127: #else  /* MACH_ASSERT */
        !           128: 
        !           129: #define ADD_TO_ZONE(zone, element)                                     \
        !           130: MACRO_BEGIN                                                            \
        !           131:                *((vm_offset_t *)(element)) = (zone)->free_elements;    \
        !           132:                (zone)->free_elements = (vm_offset_t) (element);        \
        !           133:                (zone)->count--;                                        \
        !           134: MACRO_END
        !           135: 
        !           136: #define REMOVE_FROM_ZONE(zone, ret, type)                              \
        !           137: MACRO_BEGIN                                                            \
        !           138:        (ret) = (type) (zone)->free_elements;                           \
        !           139:        if ((ret) != (type) 0) {                                        \
        !           140:                (zone)->count++;                                        \
        !           141:                (zone)->free_elements = *((vm_offset_t *)(ret));        \
        !           142:        }                                                               \
        !           143: MACRO_END
        !           144: 
        !           145: #endif /* MACH_ASSERT */
        !           146: 
        !           147: #if    ZONE_DEBUG
        !           148: #define zone_debug_enabled(z) z->active_zones.next
        !           149: #endif /* ZONE_DEBUG */
        !           150: 
        !           151: /*
        !           152:  * Support for garbage collection of unused zone pages:
        !           153:  */
        !           154: 
        !           155: struct zone_page_table_entry {
        !           156:        struct  zone_page_table_entry   *next;
        !           157:        short   in_free_list;
        !           158:        short   alloc_count;
        !           159: };
        !           160: 
        !           161: extern struct zone_page_table_entry * zone_page_table;
        !           162: 
        !           163: #define lock_zone_page_table() simple_lock(&zone_page_table_lock)
        !           164: #define unlock_zone_page_table() simple_unlock(&zone_page_table_lock)
        !           165: 
        !           166: #define        zone_page(addr) \
        !           167:     (&(zone_page_table[(atop(((vm_offset_t)addr) - zone_map_min_address))]))
        !           168: 
        !           169: /* Forwards */
        !           170: void           zone_page_init(
        !           171:                                vm_offset_t     addr,
        !           172:                                vm_size_t       size,
        !           173:                                int             value);
        !           174: 
        !           175: void           zone_page_alloc(
        !           176:                                vm_offset_t     addr,
        !           177:                                vm_size_t       size);
        !           178: 
        !           179: void           zone_add_free_page_list(
        !           180:                                struct zone_page_table_entry    **free_list,
        !           181:                                vm_offset_t     addr,
        !           182:                                vm_size_t       size);
        !           183: void           zone_page_dealloc(
        !           184:                                vm_offset_t     addr,
        !           185:                                vm_size_t       size);
        !           186: 
        !           187: void           zone_page_in_use(
        !           188:                                vm_offset_t     addr,
        !           189:                                vm_size_t       size);
        !           190: 
        !           191: void           zone_page_free(
        !           192:                                vm_offset_t     addr,
        !           193:                                vm_size_t       size);
        !           194: 
        !           195: boolean_t      zone_page_collectable(
        !           196:                                vm_offset_t     addr,
        !           197:                                vm_size_t       size);
        !           198: 
        !           199: void           zone_page_keep(
        !           200:                                vm_offset_t     addr,
        !           201:                                vm_size_t       size);
        !           202: 
        !           203: #if    ZONE_DEBUG && MACH_KDB
        !           204: int            zone_count(
        !           205:                                zone_t          z,
        !           206:                                int             tail);
        !           207: #endif /* ZONE_DEBUG && MACH_KDB */
        !           208: 
        !           209: vm_map_t       zone_map = VM_MAP_NULL;
        !           210: 
        !           211: zone_t         zone_zone = ZONE_NULL;  /* the zone containing other zones */
        !           212: 
        !           213: /*
        !           214:  *     The VM system gives us an initial chunk of memory.
        !           215:  *     It has to be big enough to allocate the zone_zone
        !           216:  */
        !           217: 
        !           218: vm_offset_t    zdata;
        !           219: vm_size_t      zdata_size;
        !           220: 
        !           221: #define lock_zone(zone)                                        \
        !           222: MACRO_BEGIN                                            \
        !           223:        simple_lock(&zone->lock);                       \
        !           224: MACRO_END
        !           225: 
        !           226: #define unlock_zone(zone)                              \
        !           227: MACRO_BEGIN                                            \
        !           228:        simple_unlock(&zone->lock);                     \
        !           229: MACRO_END
        !           230: 
        !           231: #define lock_zone_init(zone)                           \
        !           232: MACRO_BEGIN                                            \
        !           233:        simple_lock_init(&zone->lock, ETAP_MISC_ZONE);  \
        !           234: MACRO_END
        !           235: 
        !           236: #define lock_try_zone(zone)    simple_lock_try(&zone->lock)
        !           237: 
        !           238: kern_return_t          zget_space(
        !           239:                                vm_offset_t size,
        !           240:                                vm_offset_t *result);
        !           241: 
        !           242: decl_simple_lock_data(,zget_space_lock)
        !           243: vm_offset_t    zalloc_next_space;
        !           244: vm_offset_t    zalloc_end_of_space;
        !           245: vm_size_t      zalloc_wasted_space;
        !           246: 
        !           247: /*
        !           248:  *     Garbage collection map information
        !           249:  */
        !           250: decl_simple_lock_data(,                zone_page_table_lock)
        !           251: struct zone_page_table_entry * zone_page_table;
        !           252: vm_offset_t                    zone_map_min_address;
        !           253: vm_offset_t                    zone_map_max_address;
        !           254: integer_t                      zone_pages;
        !           255: 
        !           256: /*
        !           257:  *     Exclude more than one concurrent garbage collection
        !           258:  */
        !           259: decl_mutex_data(,              zone_gc_lock)
        !           260: 
        !           261: #define from_zone_map(addr) \
        !           262:        ((vm_offset_t)(addr) >= zone_map_min_address && \
        !           263:         (vm_offset_t)(addr) <  zone_map_max_address)
        !           264: 
        !           265: #define        ZONE_PAGE_USED  0
        !           266: #define ZONE_PAGE_UNUSED -1
        !           267: 
        !           268: 
        !           269: /*
        !           270:  *     Protects first_zone, last_zone, num_zones,
        !           271:  *     and the next_zone field of zones.
        !           272:  */
        !           273: decl_simple_lock_data(,        all_zones_lock)
        !           274: zone_t                 first_zone;
        !           275: zone_t                 *last_zone;
        !           276: int                    num_zones;
        !           277: 
        !           278: /*
        !           279:  *     zinit initializes a new zone.  The zone data structures themselves
        !           280:  *     are stored in a zone, which is initially a static structure that
        !           281:  *     is initialized by zone_init.
        !           282:  */
        !           283: zone_t
        !           284: zinit(
        !           285:        vm_size_t       size,           /* the size of an element */
        !           286:        vm_size_t       max,            /* maximum memory to use */
        !           287:        vm_size_t       alloc,          /* allocation size */
        !           288:        char            *name)          /* a name for the zone */
        !           289: {
        !           290:        zone_t          z;
        !           291: 
        !           292:        if (zone_zone == ZONE_NULL) {
        !           293:                if (zget_space(sizeof(struct zone), (vm_offset_t *)&z)
        !           294:                    != KERN_SUCCESS)
        !           295:                        return(ZONE_NULL);
        !           296:        } else
        !           297:                z = (zone_t) zalloc(zone_zone);
        !           298:        if (z == ZONE_NULL)
        !           299:                return(ZONE_NULL);
        !           300: 
        !           301:        /*
        !           302:         *      Round off all the parameters appropriately.
        !           303:         */
        !           304:        if (size < sizeof(z->free_elements))
        !           305:                size = sizeof(z->free_elements);
        !           306:        size = ((size-1)  + sizeof(z->free_elements)) -
        !           307:                ((size-1) % sizeof(z->free_elements));
        !           308:        if (alloc == 0)
        !           309:                alloc = PAGE_SIZE;
        !           310:        alloc = round_page(alloc);
        !           311:        max   = round_page(max);
        !           312:        /*
        !           313:         * We look for an allocation size with least fragmentation
        !           314:         * in the range of 1 - 5 pages.  This size will be used unless
        !           315:         * the user suggestion is larger AND has less fragmentation
        !           316:         */
        !           317:        {       vm_size_t best, waste; unsigned int i;
        !           318:                best  = PAGE_SIZE;
        !           319:                waste = best % size;
        !           320:                for (i = 2; i <= 5; i++){       vm_size_t tsize, twaste;
        !           321:                        tsize  = i * PAGE_SIZE;
        !           322:                        twaste = tsize % size;
        !           323:                        if (twaste < waste)
        !           324:                                best = tsize, waste = twaste;
        !           325:                }
        !           326:                if (alloc <= best || (alloc % size >= waste))
        !           327:                        alloc = best;
        !           328:        }
        !           329:        if (max && (max < alloc))
        !           330:                max = alloc;
        !           331: 
        !           332:        z->free_elements = 0;
        !           333:        z->cur_size = 0;
        !           334:        z->max_size = max;
        !           335:        z->elem_size = size;
        !           336:        z->alloc_size = alloc;
        !           337:        z->zone_name = name;
        !           338:        z->count = 0;
        !           339:        z->doing_alloc = FALSE;
        !           340:        z->exhaustible = FALSE;
        !           341:        z->collectable = TRUE;
        !           342:        z->allows_foreign = FALSE;
        !           343:        z->expandable  = TRUE;
        !           344:        z->waiting = FALSE;
        !           345: 
        !           346: #if    ZONE_DEBUG
        !           347:        z->active_zones.next = z->active_zones.prev = 0;        
        !           348:        zone_debug_enable(z);
        !           349: #endif /* ZONE_DEBUG */
        !           350:        lock_zone_init(z);
        !           351: 
        !           352:        /*
        !           353:         *      Add the zone to the all-zones list.
        !           354:         */
        !           355: 
        !           356:        z->next_zone = ZONE_NULL;
        !           357:        simple_lock(&all_zones_lock);
        !           358:        *last_zone = z;
        !           359:        last_zone = &z->next_zone;
        !           360:        num_zones++;
        !           361:        simple_unlock(&all_zones_lock);
        !           362: 
        !           363:        return(z);
        !           364: }
        !           365: 
        !           366: /*
        !           367:  *     Cram the given memory into the specified zone.
        !           368:  */
        !           369: void
        !           370: zcram(
        !           371:        register zone_t         zone,
        !           372:        vm_offset_t             newmem,
        !           373:        vm_size_t               size)
        !           374: {
        !           375:        register vm_size_t      elem_size;
        !           376: 
        !           377:        /* Basic sanity checks */
        !           378:        assert(zone != ZONE_NULL && newmem != (vm_offset_t)0);
        !           379:        assert(!zone->collectable || zone->allows_foreign
        !           380:                || (from_zone_map(newmem) && from_zone_map(newmem+size-1)));
        !           381: 
        !           382:        elem_size = zone->elem_size;
        !           383: 
        !           384:        lock_zone(zone);
        !           385:        while (size >= elem_size) {
        !           386:                ADD_TO_ZONE(zone, newmem);
        !           387:                if (from_zone_map(newmem))
        !           388:                        zone_page_alloc(newmem, elem_size);
        !           389:                zone->count++;  /* compensate for ADD_TO_ZONE */
        !           390:                size -= elem_size;
        !           391:                newmem += elem_size;
        !           392:                zone->cur_size += elem_size;
        !           393:        }
        !           394:        unlock_zone(zone);
        !           395: }
        !           396: 
        !           397: /*
        !           398:  * Contiguous space allocator for non-paged zones. Allocates "size" amount
        !           399:  * of memory from zone_map.
        !           400:  */
        !           401: 
        !           402: kern_return_t
        !           403: zget_space(
        !           404:        vm_offset_t size,
        !           405:        vm_offset_t *result)
        !           406: {
        !           407:        vm_offset_t     new_space = 0;
        !           408:        vm_size_t       space_to_add;
        !           409: 
        !           410:        simple_lock(&zget_space_lock);
        !           411:        while ((zalloc_next_space + size) > zalloc_end_of_space) {
        !           412:                /*
        !           413:                 *      Add at least one page to allocation area.
        !           414:                 */
        !           415: 
        !           416:                space_to_add = round_page(size);
        !           417: 
        !           418:                if (new_space == 0) {
        !           419:                        kern_return_t retval;
        !           420:                        /*
        !           421:                         *      Memory cannot be wired down while holding
        !           422:                         *      any locks that the pageout daemon might
        !           423:                         *      need to free up pages.  [Making the zget_space
        !           424:                         *      lock a complex lock does not help in this
        !           425:                         *      regard.]
        !           426:                         *
        !           427:                         *      Unlock and allocate memory.  Because several
        !           428:                         *      threads might try to do this at once, don't
        !           429:                         *      use the memory before checking for available
        !           430:                         *      space again.
        !           431:                         */
        !           432: 
        !           433:                        simple_unlock(&zget_space_lock);
        !           434: 
        !           435:                        retval = kernel_memory_allocate(zone_map, &new_space,
        !           436:                                space_to_add, 0, KMA_KOBJECT|KMA_NOPAGEWAIT);
        !           437:                        if (retval != KERN_SUCCESS)
        !           438:                                return(retval);
        !           439:                        zone_page_init(new_space, space_to_add,
        !           440:                                                        ZONE_PAGE_USED);
        !           441:                        simple_lock(&zget_space_lock);
        !           442:                        continue;
        !           443:                }
        !           444: 
        !           445:                
        !           446:                /*
        !           447:                 *      Memory was allocated in a previous iteration.
        !           448:                 *
        !           449:                 *      Check whether the new region is contiguous
        !           450:                 *      with the old one.
        !           451:                 */
        !           452: 
        !           453:                if (new_space != zalloc_end_of_space) {
        !           454:                        /*
        !           455:                         *      Throw away the remainder of the
        !           456:                         *      old space, and start a new one.
        !           457:                         */
        !           458:                        zalloc_wasted_space +=
        !           459:                                zalloc_end_of_space - zalloc_next_space;
        !           460:                        zalloc_next_space = new_space;
        !           461:                }
        !           462: 
        !           463:                zalloc_end_of_space = new_space + space_to_add;
        !           464: 
        !           465:                new_space = 0;
        !           466:        }
        !           467:        *result = zalloc_next_space;
        !           468:        zalloc_next_space += size;              
        !           469:        simple_unlock(&zget_space_lock);
        !           470: 
        !           471:        if (new_space != 0)
        !           472:                kmem_free(zone_map, new_space, space_to_add);
        !           473: 
        !           474:        return(KERN_SUCCESS);
        !           475: }
        !           476: 
        !           477: 
        !           478: /*
        !           479:  *     Steal memory for the zone package.  Called from
        !           480:  *     vm_page_bootstrap().
        !           481:  */
        !           482: void
        !           483: zone_steal_memory(void)
        !           484: {
        !           485:        zdata_size = round_page(128*sizeof(struct zone));
        !           486:        zdata = pmap_steal_memory(zdata_size);
        !           487: }
        !           488: 
        !           489: 
        !           490: /*
        !           491:  * Fill a zone with enough memory to contain at least nelem elements.
        !           492:  * Memory is obtained with kmem_alloc_wired from the kernel_map.
        !           493:  * Return the number of elements actually put into the zone, which may
        !           494:  * be more than the caller asked for since the memory allocation is
        !           495:  * rounded up to a full page.
        !           496:  */
        !           497: int
        !           498: zfill(
        !           499:        zone_t  zone,
        !           500:        int     nelem)
        !           501: {
        !           502:        kern_return_t   kr;
        !           503:        vm_size_t       size;
        !           504:        vm_offset_t     memory;
        !           505:        int             nalloc;
        !           506: 
        !           507:        assert(nelem > 0);
        !           508:        if (nelem <= 0)
        !           509:                return 0;
        !           510: 
        !           511:        size = nelem * zone->elem_size;
        !           512:        size = round_page(size);
        !           513:        kr = kmem_alloc_wired(kernel_map, &memory, size);
        !           514:        if (kr != KERN_SUCCESS)
        !           515:                return 0;
        !           516: 
        !           517:        zone_change(zone, Z_FOREIGN, TRUE);
        !           518:        zcram(zone, memory, size);
        !           519:        nalloc = size / zone->elem_size;
        !           520:        assert(nalloc >= nelem);
        !           521: 
        !           522:        return nalloc;
        !           523: }
        !           524: 
        !           525: /*
        !           526:  *     Initialize the "zone of zones" which uses fixed memory allocated
        !           527:  *     earlier in memory initialization.  zone_bootstrap is called
        !           528:  *     before zone_init.
        !           529:  */
        !           530: void
        !           531: zone_bootstrap(void)
        !           532: {
        !           533:        vm_size_t zone_zone_size;
        !           534:        vm_offset_t zone_zone_space;
        !           535: 
        !           536:        simple_lock_init(&all_zones_lock, ETAP_MISC_ZONE_ALL);
        !           537: 
        !           538:        first_zone = ZONE_NULL;
        !           539:        last_zone = &first_zone;
        !           540:        num_zones = 0;
        !           541: 
        !           542:        simple_lock_init(&zget_space_lock, ETAP_MISC_ZONE_GET);
        !           543:        zalloc_next_space = zdata;
        !           544:        zalloc_end_of_space = zdata + zdata_size;
        !           545:        zalloc_wasted_space = 0;
        !           546: 
        !           547:        /* assertion: nobody else called zinit before us */
        !           548:        assert(zone_zone == ZONE_NULL);
        !           549:        zone_zone = zinit(sizeof(struct zone), 128 * sizeof(struct zone),
        !           550:                          sizeof(struct zone), "zones");
        !           551:        zone_change(zone_zone, Z_COLLECT, FALSE);
        !           552:        zone_zone_size = zalloc_end_of_space - zalloc_next_space;
        !           553:        zget_space(zone_zone_size, &zone_zone_space);
        !           554:        zcram(zone_zone, zone_zone_space, zone_zone_size);
        !           555: }
        !           556: 
        !           557: void
        !           558: zone_init(
        !           559:        vm_size_t max_zonemap_size)
        !           560: {
        !           561:        kern_return_t   retval;
        !           562:        vm_offset_t     zone_min;
        !           563:        vm_offset_t     zone_max;
        !           564:        vm_size_t       zone_table_size;
        !           565: 
        !           566:        retval = kmem_suballoc(kernel_map, &zone_min, max_zonemap_size,
        !           567:                                                FALSE, TRUE, &zone_map);
        !           568:        if (retval != KERN_SUCCESS)
        !           569:                panic("zone_init: kmem_suballoc failed");
        !           570:        zone_max = zone_min + round_page(max_zonemap_size);
        !           571:        /*
        !           572:         * Setup garbage collection information:
        !           573:         */
        !           574:        zone_table_size = atop(zone_max - zone_min) * 
        !           575:                                sizeof(struct zone_page_table_entry);
        !           576:        if (kmem_alloc_wired(zone_map, (vm_offset_t *) &zone_page_table,
        !           577:                             zone_table_size) != KERN_SUCCESS)
        !           578:                panic("zone_init");
        !           579:        zone_min = (vm_offset_t)zone_page_table + round_page(zone_table_size);
        !           580:        zone_pages = atop(zone_max - zone_min);
        !           581:        zone_map_min_address = zone_min;
        !           582:        zone_map_max_address = zone_max;
        !           583:        simple_lock_init(&zone_page_table_lock, ETAP_MISC_ZONE_PTABLE);
        !           584:        mutex_init(&zone_gc_lock, ETAP_NO_TRACE);
        !           585:        zone_page_init(zone_min, zone_max - zone_min, ZONE_PAGE_UNUSED);
        !           586: }
        !           587: 
        !           588: 
        !           589: /*
        !           590:  *     zalloc returns an element from the specified zone.
        !           591:  */
        !           592: vm_offset_t
        !           593: zalloc(
        !           594:        register zone_t zone)
        !           595: {
        !           596:        vm_offset_t     addr;
        !           597:        kern_return_t retval;
        !           598: 
        !           599:        assert(zone != ZONE_NULL);
        !           600:        check_simple_locks();
        !           601: 
        !           602:        lock_zone(zone);
        !           603: 
        !           604:        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
        !           605:        while (addr == 0) {
        !           606:                /*
        !           607:                 *      If nothing was there, try to get more
        !           608:                 */
        !           609:                if (zone->doing_alloc) {
        !           610:                        /*
        !           611:                         *      Someone is allocating memory for this zone.
        !           612:                         *      Wait for it to show up, then try again.
        !           613:                         */
        !           614:                        assert_wait((event_t)zone, THREAD_INTERRUPTIBLE);
        !           615:                        zone->waiting = TRUE;
        !           616:                        unlock_zone(zone);
        !           617:                        thread_block((void (*)(void)) 0);
        !           618:                        lock_zone(zone);
        !           619:                }
        !           620:                else {
        !           621:                        if ((zone->cur_size + zone->elem_size) >
        !           622:                            zone->max_size) {
        !           623:                                if (zone->exhaustible)
        !           624:                                        break;
        !           625:                                if (zone->expandable) {
        !           626:                                        /*
        !           627:                                         * We're willing to overflow certain
        !           628:                                         * zones, but not without complaining.
        !           629:                                         *
        !           630:                                         * This is best used in conjunction
        !           631:                                         * with the collectable flag. What we
        !           632:                                         * want is an assurance we can get the
        !           633:                                         * memory back, assuming there's no
        !           634:                                         * leak. 
        !           635:                                         */
        !           636:                                        zone->max_size += (zone->max_size >> 1);
        !           637:                                } else {
        !           638:                                        unlock_zone(zone);
        !           639:                                        panic("zalloc: zone \"%s\" empty.", zone->zone_name);
        !           640:                                }
        !           641:                        }
        !           642:                        zone->doing_alloc = TRUE;
        !           643:                        unlock_zone(zone);
        !           644: 
        !           645:                        if (zone->collectable) {
        !           646:                                vm_offset_t space;
        !           647:                                vm_size_t alloc_size;
        !           648: 
        !           649:                                if (vm_pool_low())
        !           650:                                        alloc_size = 
        !           651:                                          round_page(zone->elem_size);
        !           652:                                else
        !           653:                                        alloc_size = zone->alloc_size;
        !           654: 
        !           655:                                retval = kernel_memory_allocate(zone_map,
        !           656:                                        &space, alloc_size, 0,
        !           657:                                        KMA_KOBJECT|KMA_NOPAGEWAIT);
        !           658:                                if (retval == KERN_SUCCESS) {
        !           659:                                        zone_page_init(space, alloc_size,
        !           660:                                                ZONE_PAGE_USED);
        !           661:                                        zcram(zone, space, alloc_size);
        !           662:                                } else if (retval != KERN_RESOURCE_SHORTAGE) {
        !           663:                                        /* would like to cause a zone_gc() */
        !           664:                                        panic("zalloc");
        !           665:                                }
        !           666:                                lock_zone(zone);
        !           667:                                zone->doing_alloc = FALSE; 
        !           668:                                if (zone->waiting) {
        !           669:                                        zone->waiting = FALSE;
        !           670:                                        thread_wakeup((event_t)zone);
        !           671:                                }
        !           672:                                REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
        !           673:                                if (addr == 0 &&
        !           674:                                        retval == KERN_RESOURCE_SHORTAGE) {
        !           675:                                        unlock_zone(zone);
        !           676:                                        VM_PAGE_WAIT();
        !           677:                                        lock_zone(zone);
        !           678:                                }
        !           679:                        } else {
        !           680:                                vm_offset_t space;
        !           681:                                retval = zget_space(zone->elem_size, &space);
        !           682: 
        !           683:                                lock_zone(zone);
        !           684:                                zone->doing_alloc = FALSE; 
        !           685:                                if (zone->waiting) {
        !           686:                                        zone->waiting = FALSE;
        !           687:                                        thread_wakeup((event_t)zone);
        !           688:                                }
        !           689:                                if (retval == KERN_SUCCESS) {
        !           690:                                        zone->count++;
        !           691:                                        zone->cur_size += zone->elem_size;
        !           692: #if    ZONE_DEBUG
        !           693:                                        if (zone_debug_enabled(zone)) {
        !           694:                                            enqueue_tail(&zone->active_zones, (queue_entry_t)space);
        !           695:                                        }
        !           696: #endif
        !           697:                                        unlock_zone(zone);
        !           698:                                        zone_page_alloc(space, zone->elem_size);
        !           699: #if    ZONE_DEBUG
        !           700:                                        if (zone_debug_enabled(zone))
        !           701:                                                space += sizeof(queue_chain_t);
        !           702: #endif
        !           703:                                        return(space);
        !           704:                                }
        !           705:                                if (retval == KERN_RESOURCE_SHORTAGE) {
        !           706:                                        unlock_zone(zone);
        !           707:                                        VM_PAGE_WAIT();
        !           708:                                        lock_zone(zone);
        !           709:                                } else {
        !           710:                                        panic("zalloc");
        !           711:                                }
        !           712:                        }
        !           713:                }
        !           714:                if (addr == 0)
        !           715:                        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
        !           716:        }
        !           717: 
        !           718: #if    ZONE_DEBUG
        !           719:        if (addr && zone_debug_enabled(zone)) {
        !           720:                enqueue_tail(&zone->active_zones, (queue_entry_t)addr);
        !           721:                addr += sizeof(queue_chain_t);
        !           722:        }
        !           723: #endif
        !           724: 
        !           725:        unlock_zone(zone);
        !           726:        return(addr);
        !           727: }
        !           728: 
        !           729: 
        !           730: /*
        !           731:  *     zget returns an element from the specified zone
        !           732:  *     and immediately returns nothing if there is nothing there.
        !           733:  *
        !           734:  *     This form should be used when you can not block (like when
        !           735:  *     processing an interrupt).
        !           736:  */
        !           737: vm_offset_t
        !           738: zget(
        !           739:        register zone_t zone)
        !           740: {
        !           741:        register vm_offset_t    addr;
        !           742: 
        !           743:        assert( zone != ZONE_NULL );
        !           744: 
        !           745:        if (!lock_try_zone(zone))
        !           746:            return ((vm_offset_t)0);
        !           747: 
        !           748:        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
        !           749: #if    ZONE_DEBUG
        !           750:        if (addr && zone_debug_enabled(zone)) {
        !           751:                enqueue_tail(&zone->active_zones, (queue_entry_t)addr);
        !           752:                addr += sizeof(queue_chain_t);
        !           753:        }
        !           754: #endif /* ZONE_DEBUG */
        !           755:        unlock_zone(zone);
        !           756: 
        !           757:        return(addr);
        !           758: }
        !           759: 
        !           760: #if    ZONE_DEBUG
        !           761: boolean_t zone_check = TRUE;
        !           762: #else  /* ZONE_DEBUG */
        !           763: boolean_t zone_check = FALSE;
        !           764: #endif /* ZONE_DEBUG */
        !           765: 
        !           766: void
        !           767: zfree(
        !           768:        register zone_t zone,
        !           769:        vm_offset_t     elem)
        !           770: {
        !           771: 
        !           772: #if MACH_ASSERT
        !           773:        /* Basic sanity checks */
        !           774:        if (zone == ZONE_NULL || elem == (vm_offset_t)0)
        !           775:                panic("zfree: NULL");
        !           776:        /* zone_gc assumes zones are never freed */
        !           777:        if (zone == zone_zone)
        !           778:                panic("zfree: freeing to zone_zone breaks zone_gc!");
        !           779:        if (zone->collectable && !zone->allows_foreign &&
        !           780:            (!from_zone_map(elem) || !from_zone_map(elem+zone->elem_size-1)))
        !           781:                panic("zfree: non-allocated memory in collectable zone!");
        !           782: #endif
        !           783: 
        !           784:        lock_zone(zone);
        !           785: #if    ZONE_DEBUG
        !           786:        if (zone_debug_enabled(zone)) {
        !           787:                queue_t tmp_elem;
        !           788: 
        !           789:                elem -= sizeof(queue_chain_t);
        !           790:                if (zone_check) {
        !           791:                        /* check the zone's consistency */
        !           792: 
        !           793:                        for (tmp_elem = queue_first(&zone->active_zones);
        !           794:                             !queue_end(tmp_elem, &zone->active_zones);
        !           795:                             tmp_elem = queue_next(tmp_elem))
        !           796:                                if (elem == (vm_offset_t)tmp_elem)
        !           797:                                        break;
        !           798:                        if (elem != (vm_offset_t)tmp_elem)
        !           799:                                panic("zfree()ing element from wrong zone");
        !           800:                }
        !           801:                remqueue(&zone->active_zones, (queue_t) elem);
        !           802:        }
        !           803: #endif /* ZONE_DEBUG */
        !           804:        if (zone_check) {
        !           805:                vm_offset_t this;
        !           806: 
        !           807:                /* check the zone's consistency */
        !           808: 
        !           809:                for (this = zone->free_elements;
        !           810:                     this != 0;
        !           811:                     this = * (vm_offset_t *) this)
        !           812:                        if (!pmap_kernel_va(this) || this == elem)
        !           813:                                panic("zfree");
        !           814:        }
        !           815:        /*
        !           816:         * If elements have one or more pages, and memory is low,
        !           817:         * put it directly back into circulation rather than
        !           818:         * back into a zone, where a non-vm_privileged task can grab it.
        !           819:         * This lessens the impact of a privileged task cycling reserved
        !           820:         * memory into a publicly accessible zone.
        !           821:         */
        !           822:        if (zone->elem_size >= PAGE_SIZE && 
        !           823:            vm_pool_low()){
        !           824:                assert( !(zone->elem_size & (zone->alloc_size-1)) );
        !           825:                zone->count--;
        !           826:                zone->cur_size -= zone->elem_size;
        !           827:                zone_page_init(elem, zone->elem_size, ZONE_PAGE_UNUSED);
        !           828:                unlock_zone(zone);
        !           829:                kmem_free(zone_map, elem, zone->elem_size);
        !           830:                return;
        !           831:        }
        !           832:        ADD_TO_ZONE(zone, elem);
        !           833:        unlock_zone(zone);
        !           834: }
        !           835: 
        !           836: 
        !           837: /*     Change a zone's flags.
        !           838:  *     This routine must be called immediately after zinit.
        !           839:  */
        !           840: void
        !           841: zone_change(
        !           842:        zone_t          zone,
        !           843:        unsigned int    item,
        !           844:        boolean_t       value)
        !           845: {
        !           846:        assert( zone != ZONE_NULL );
        !           847:        assert( value == TRUE || value == FALSE );
        !           848: 
        !           849:        switch(item){
        !           850:                case Z_EXHAUST:
        !           851:                        zone->exhaustible = value;
        !           852:                        break;
        !           853:                case Z_COLLECT:
        !           854:                        zone->collectable = value;
        !           855:                        break;
        !           856:                case Z_EXPAND:
        !           857:                        zone->expandable = value;
        !           858:                        break;
        !           859:                case Z_FOREIGN:
        !           860:                        zone->allows_foreign = value;
        !           861:                        break;
        !           862: #if MACH_ASSERT
        !           863:                default:
        !           864:                        panic("Zone_change: Wrong Item Type!");
        !           865:                        /* break; */
        !           866: #endif
        !           867:        }
        !           868:        lock_zone_init(zone);
        !           869: }
        !           870: 
        !           871: /*
        !           872:  * Return the expected number of free elements in the zone.
        !           873:  * This calculation will be incorrect if items are zfree'd that
        !           874:  * were never zalloc'd/zget'd. The correct way to stuff memory
        !           875:  * into a zone is by zcram.
        !           876:  */
        !           877: 
        !           878: integer_t
        !           879: zone_free_count(zone_t zone)
        !           880: {
        !           881:        integer_t free_count;
        !           882: 
        !           883:        lock_zone(zone);
        !           884:        free_count = zone->cur_size/zone->elem_size - zone->count;
        !           885:        unlock_zone(zone);
        !           886: 
        !           887:        assert(free_count >= 0);
        !           888: 
        !           889:        return(free_count);
        !           890: }
        !           891: 
        !           892: /*
        !           893:  *     zprealloc preallocates wired memory, exanding the specified
        !           894:  *      zone to the specified size
        !           895:  */
        !           896: void
        !           897: zprealloc(
        !           898:        zone_t  zone,
        !           899:        vm_size_t size)
        !           900: {
        !           901:         vm_offset_t addr;
        !           902: 
        !           903:        if (size != 0) {
        !           904:                if (kmem_alloc_wired(zone_map, &addr, size) != KERN_SUCCESS)
        !           905:                  panic("zprealloc");
        !           906:                zone_page_init(addr, size, ZONE_PAGE_USED);
        !           907:                zcram(zone, addr, size);
        !           908:        }
        !           909: }
        !           910: 
        !           911: /*
        !           912:  *  Zone garbage collection subroutines
        !           913:  *
        !           914:  *  These routines have in common the modification of entries in the
        !           915:  *  zone_page_table.  The latter contains one entry for every page
        !           916:  *  in the zone_map.  
        !           917:  *
        !           918:  *  For each page table entry in the given range:
        !           919:  *
        !           920:  *     zone_page_collectable   - test if one (in_free_list == alloc_count)
        !           921:  *     zone_page_keep          - reset in_free_list
        !           922:  *     zone_page_in_use        - decrements in_free_list
        !           923:  *     zone_page_free          - increments in_free_list
        !           924:  *     zone_page_init          - initializes in_free_list and alloc_count
        !           925:  *     zone_page_alloc         - increments alloc_count
        !           926:  *     zone_page_dealloc       - decrements alloc_count
        !           927:  *     zone_add_free_page_list - adds the page to the free list
        !           928:  *   
        !           929:  *  Two counts are maintained for each page, the in_free_list count and
        !           930:  *  alloc_count.  The alloc_count is how many zone elements have been
        !           931:  *  allocated from a page.  (Note that the page could contain elements
        !           932:  *  that span page boundaries.  The count includes these elements so
        !           933:  *  one element may be counted in two pages.) In_free_list is a count
        !           934:  *  of how many zone elements are currently free.  If in_free_list is
        !           935:  *  equal to alloc_count then the page is eligible for garbage
        !           936:  *  collection.
        !           937:  *
        !           938:  *  Alloc_count and in_free_list are initialized to the correct values
        !           939:  *  for a particular zone when a page is zcram'ed into a zone.  Subsequent
        !           940:  *  gets and frees of zone elements will call zone_page_in_use and 
        !           941:  *  zone_page_free which modify the in_free_list count.  When the zones
        !           942:  *  garbage collector runs it will walk through a zones free element list,
        !           943:  *  remove the elements that reside on collectable pages, and use 
        !           944:  *  zone_add_free_page_list to create a list of pages to be collected.
        !           945:  */
        !           946: 
        !           947: boolean_t
        !           948: zone_page_collectable(
        !           949:        vm_offset_t     addr,
        !           950:        vm_size_t       size)
        !           951: {
        !           952:        natural_t i, j;
        !           953: 
        !           954: #if MACH_ASSERT
        !           955:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !           956:                panic("zone_page_collectable");
        !           957: #endif
        !           958: 
        !           959:        i = atop(addr-zone_map_min_address);
        !           960:        j = atop((addr+size-1) - zone_map_min_address);
        !           961:        lock_zone_page_table();
        !           962:        for (; i <= j; i++) {
        !           963:                if (zone_page_table[i].in_free_list ==
        !           964:                    zone_page_table[i].alloc_count) {
        !           965:                        unlock_zone_page_table();
        !           966:                        return (TRUE);
        !           967:                }
        !           968:        }
        !           969:        unlock_zone_page_table();
        !           970:        return (FALSE);
        !           971: }
        !           972: 
        !           973: void
        !           974: zone_page_keep(
        !           975:        vm_offset_t     addr,
        !           976:        vm_size_t       size)
        !           977: {
        !           978:        natural_t i, j;
        !           979: 
        !           980: #if MACH_ASSERT
        !           981:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !           982:                panic("zone_page_keep");
        !           983: #endif
        !           984: 
        !           985:        i = atop(addr-zone_map_min_address);
        !           986:        j = atop((addr+size-1) - zone_map_min_address);
        !           987:        lock_zone_page_table();
        !           988:        for (; i <= j; i++) {
        !           989:                zone_page_table[i].in_free_list = 0;
        !           990:        }
        !           991:        unlock_zone_page_table();
        !           992: }
        !           993: 
        !           994: void
        !           995: zone_page_in_use(
        !           996:        vm_offset_t     addr,
        !           997:        vm_size_t       size)
        !           998: {
        !           999:        natural_t i, j;
        !          1000: 
        !          1001: #if MACH_ASSERT
        !          1002:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !          1003:                panic("zone_page_in_use");
        !          1004: #endif
        !          1005: 
        !          1006:        i = atop(addr-zone_map_min_address);
        !          1007:        j = atop((addr+size-1) - zone_map_min_address);
        !          1008:        lock_zone_page_table();
        !          1009:        for (; i <= j; i++) {
        !          1010:                if (zone_page_table[i].in_free_list > 0)
        !          1011:                        zone_page_table[i].in_free_list--;
        !          1012:        }
        !          1013:        unlock_zone_page_table();
        !          1014: }
        !          1015: 
        !          1016: void
        !          1017: zone_page_free(
        !          1018:        vm_offset_t     addr,
        !          1019:        vm_size_t       size)
        !          1020: {
        !          1021:        natural_t i, j;
        !          1022: 
        !          1023: #if MACH_ASSERT
        !          1024:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !          1025:                panic("zone_page_free");
        !          1026: #endif
        !          1027: 
        !          1028:        i = atop(addr-zone_map_min_address);
        !          1029:        j = atop((addr+size-1) - zone_map_min_address);
        !          1030:        lock_zone_page_table();
        !          1031:        for (; i <= j; i++) {
        !          1032:                assert(zone_page_table[i].in_free_list >= 0);
        !          1033:                zone_page_table[i].in_free_list++;
        !          1034:        }
        !          1035:        unlock_zone_page_table();
        !          1036: }
        !          1037: 
        !          1038: void
        !          1039: zone_page_init(
        !          1040:        vm_offset_t     addr,
        !          1041:        vm_size_t       size,
        !          1042:        int             value)
        !          1043: {
        !          1044:        natural_t i, j;
        !          1045: 
        !          1046: #if MACH_ASSERT
        !          1047:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !          1048:                panic("zone_page_init");
        !          1049: #endif
        !          1050: 
        !          1051:        i = atop(addr-zone_map_min_address);
        !          1052:        j = atop((addr+size-1) - zone_map_min_address);
        !          1053:        lock_zone_page_table();
        !          1054:        for (; i <= j; i++) {
        !          1055:                zone_page_table[i].alloc_count = value;
        !          1056:                zone_page_table[i].in_free_list = 0;
        !          1057:        }
        !          1058:        unlock_zone_page_table();
        !          1059: }
        !          1060: 
        !          1061: void
        !          1062: zone_page_alloc(
        !          1063:        vm_offset_t     addr,
        !          1064:        vm_size_t       size)
        !          1065: {
        !          1066:        natural_t i, j;
        !          1067: 
        !          1068: #if MACH_ASSERT
        !          1069:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !          1070:                panic("zone_page_alloc");
        !          1071: #endif
        !          1072: 
        !          1073:        i = atop(addr-zone_map_min_address);
        !          1074:        j = atop((addr+size-1) - zone_map_min_address);
        !          1075:        lock_zone_page_table();
        !          1076:        for (; i <= j; i++) {
        !          1077:                /* Set alloc_count to (ZONE_PAGE_USED + 1) if
        !          1078:                 * it was previously set to ZONE_PAGE_UNUSED.
        !          1079:                 */
        !          1080:                if (zone_page_table[i].alloc_count == ZONE_PAGE_UNUSED) {
        !          1081:                        zone_page_table[i].alloc_count = 1;
        !          1082:                } else {
        !          1083:                        zone_page_table[i].alloc_count++;
        !          1084:                }
        !          1085:        }
        !          1086:        unlock_zone_page_table();
        !          1087: }
        !          1088: 
        !          1089: void
        !          1090: zone_page_dealloc(
        !          1091:        vm_offset_t     addr,
        !          1092:        vm_size_t       size)
        !          1093: {
        !          1094:        natural_t i, j;
        !          1095: 
        !          1096: #if MACH_ASSERT
        !          1097:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !          1098:                panic("zone_page_dealloc");
        !          1099: #endif
        !          1100: 
        !          1101:        i = atop(addr-zone_map_min_address);
        !          1102:        j = atop((addr+size-1) - zone_map_min_address);
        !          1103:        lock_zone_page_table();
        !          1104:        for (; i <= j; i++) {
        !          1105:                zone_page_table[i].alloc_count--;
        !          1106:        }
        !          1107:        unlock_zone_page_table();
        !          1108: }
        !          1109: 
        !          1110: void
        !          1111: zone_add_free_page_list(
        !          1112:        struct zone_page_table_entry    **free_list,
        !          1113:        vm_offset_t     addr,
        !          1114:        vm_size_t       size)
        !          1115: {
        !          1116:        natural_t i, j;
        !          1117: 
        !          1118: #if MACH_ASSERT
        !          1119:        if (!from_zone_map(addr) || !from_zone_map(addr+size-1))
        !          1120:                panic("zone_add_free_page_list");
        !          1121: #endif
        !          1122: 
        !          1123:        i = atop(addr-zone_map_min_address);
        !          1124:        j = atop((addr+size-1) - zone_map_min_address);
        !          1125:        lock_zone_page_table();
        !          1126:        for (; i <= j; i++) {
        !          1127:                if (zone_page_table[i].alloc_count == 0) {
        !          1128:                        zone_page_table[i].next = *free_list;
        !          1129:                        *free_list = &zone_page_table[i];
        !          1130:                        zone_page_table[i].alloc_count  = ZONE_PAGE_UNUSED;
        !          1131:                        zone_page_table[i].in_free_list = 0;
        !          1132:                }
        !          1133:        }
        !          1134:        unlock_zone_page_table();
        !          1135: }
        !          1136: 
        !          1137: 
        !          1138: /* This is used for walking through a zone's free element list.
        !          1139:  */
        !          1140: struct zone_free_entry {
        !          1141:        struct zone_free_entry * next;
        !          1142: };
        !          1143: 
        !          1144: int reclaim_page_count = 0;
        !          1145: 
        !          1146: /*     Zone garbage collection
        !          1147:  *
        !          1148:  *     zone_gc will walk through all the free elements in all the
        !          1149:  *     zones that are marked collectable looking for reclaimable
        !          1150:  *     pages.  zone_gc is called by consider_zone_gc when the system
        !          1151:  *     begins to run out of memory.
        !          1152:  */
        !          1153: void
        !          1154: zone_gc(void)
        !          1155: {
        !          1156:        unsigned int    max_zones;
        !          1157:        zone_t          z;
        !          1158:        unsigned int    i;
        !          1159:        struct zone_page_table_entry    *freep;
        !          1160:        struct zone_page_table_entry    *zone_free_page_list;
        !          1161: 
        !          1162:        mutex_lock(&zone_gc_lock);
        !          1163: 
        !          1164:        simple_lock(&all_zones_lock);
        !          1165:        max_zones = num_zones;
        !          1166:        z = first_zone;
        !          1167:        simple_unlock(&all_zones_lock);
        !          1168: 
        !          1169: #if MACH_ASSERT
        !          1170:        lock_zone_page_table();
        !          1171:        for (i = 0; i < zone_pages; i++)
        !          1172:                assert(zone_page_table[i].in_free_list == 0);
        !          1173:        unlock_zone_page_table();
        !          1174: #endif /* MACH_ASSERT */
        !          1175: 
        !          1176:        zone_free_page_list = (struct zone_page_table_entry *) 0;
        !          1177: 
        !          1178:        for (i = 0; i < max_zones; i++) {
        !          1179:                struct zone_free_entry * last;
        !          1180:                struct zone_free_entry * elt;
        !          1181:                assert(z != ZONE_NULL);
        !          1182: 
        !          1183:                if (!z->collectable) {
        !          1184:                        simple_lock(&all_zones_lock);
        !          1185:                        z = z->next_zone;
        !          1186:                        simple_unlock(&all_zones_lock);
        !          1187:                        continue;
        !          1188:                }
        !          1189:                lock_zone(z);
        !          1190: 
        !          1191:                /*
        !          1192:                 * Do a quick feasability check before we scan the zone: 
        !          1193:                 * skip unless there is likelihood of getting 1+ pages back.
        !          1194:                 */
        !          1195:                if ((z->cur_size - z->count * z->elem_size) <= (2*PAGE_SIZE)){
        !          1196:                        unlock_zone(z);         
        !          1197:                        simple_lock(&all_zones_lock);
        !          1198:                        z = z->next_zone;
        !          1199:                        simple_unlock(&all_zones_lock);
        !          1200:                        continue;
        !          1201:                }
        !          1202: 
        !          1203:                /* Count the free elements in each page.  This loop
        !          1204:                 * requires that all in_free_list entries are zero.
        !          1205:                 */
        !          1206:                for (elt = (struct zone_free_entry *)(z->free_elements);
        !          1207:                        elt != (struct zone_free_entry *)0; elt = elt->next) {
        !          1208: 
        !          1209:                        if (!from_zone_map(elt)) continue;
        !          1210: 
        !          1211:                        zone_page_free((vm_offset_t)elt, z->elem_size);
        !          1212:                }
        !          1213: 
        !          1214:                /* Now determine which elements should be removed
        !          1215:                 * from the free list and, after all the elements
        !          1216:                 * on a page have been removed, add the element's
        !          1217:                 * page to a list of pages to be freed.
        !          1218:                 */
        !          1219:                elt = (struct zone_free_entry *)(z->free_elements);
        !          1220:                last = elt;
        !          1221:                while ((elt != (struct zone_free_entry *)0)) {
        !          1222:                        if (!from_zone_map(elt)) {
        !          1223:                                last = elt;
        !          1224:                                elt = elt->next;
        !          1225:                                continue;
        !          1226:                        }
        !          1227:                        if (zone_page_collectable((vm_offset_t)elt,
        !          1228:                                                  z->elem_size)) {
        !          1229:                                z->cur_size -= z->elem_size;
        !          1230:                                zone_page_in_use((vm_offset_t)elt,
        !          1231:                                                 z->elem_size);
        !          1232:                                zone_page_dealloc((vm_offset_t)elt,
        !          1233:                                                  z->elem_size);
        !          1234:                                zone_add_free_page_list(&zone_free_page_list, 
        !          1235:                                                        (vm_offset_t)elt,
        !          1236:                                                        z->elem_size);
        !          1237:                                if (elt == last) {
        !          1238:                                        elt = elt->next;
        !          1239:                                        z->free_elements =(vm_offset_t)elt;
        !          1240:                                        last = elt;
        !          1241:                                } else {
        !          1242:                                        last->next = elt->next;
        !          1243:                                        elt = elt->next;
        !          1244:                                }
        !          1245:                        } else {
        !          1246:                                /* This element is not eligible for collection
        !          1247:                                 * so clear in_free_list in preparation for a
        !          1248:                                 * subsequent garbage collection pass.
        !          1249:                                 */
        !          1250:                                zone_page_keep((vm_offset_t)elt, z->elem_size);
        !          1251:                                last = elt;
        !          1252:                                elt = elt->next;
        !          1253:                        }
        !          1254:                } /* end while(elt) */
        !          1255: 
        !          1256:                unlock_zone(z);
        !          1257:                simple_lock(&all_zones_lock);
        !          1258:                /*
        !          1259:                 * Note that this scheme of locking only to walk the zone list
        !          1260:                 * assumes that zones are never freed (checked by zfree)
        !          1261:                 */
        !          1262:                z = z->next_zone;
        !          1263:                simple_unlock(&all_zones_lock);
        !          1264:        }
        !          1265: 
        !          1266:        for (freep = zone_free_page_list; freep != 0; freep = freep->next) {
        !          1267:                vm_offset_t     free_addr;
        !          1268: 
        !          1269:                free_addr = zone_map_min_address + 
        !          1270:                        PAGE_SIZE * (freep - zone_page_table);
        !          1271:                kmem_free(zone_map, free_addr, PAGE_SIZE);
        !          1272:                reclaim_page_count++;
        !          1273:        }
        !          1274:        mutex_unlock(&zone_gc_lock);
        !          1275: }
        !          1276: 
        !          1277: boolean_t zone_gc_allowed = TRUE;      /* XXX */
        !          1278: unsigned zone_gc_last_tick = 0;
        !          1279: unsigned zone_gc_max_rate = 0;         /* in ticks */
        !          1280: 
        !          1281: /*
        !          1282:  *     consider_zone_gc:
        !          1283:  *
        !          1284:  *     Called by the pageout daemon when the system needs more free pages.
        !          1285:  */
        !          1286: 
        !          1287: void
        !          1288: consider_zone_gc(void)
        !          1289: {
        !          1290:        /*
        !          1291:         *      By default, don't attempt zone GC more frequently
        !          1292:         *      than once a second (which is one scheduler tick).
        !          1293:         */
        !          1294: 
        !          1295:        if (zone_gc_max_rate == 0)
        !          1296:                zone_gc_max_rate = 2;           /* sched_tick is a 1 second resolution 2 here insures at least 1 second interval */
        !          1297: 
        !          1298:        if (zone_gc_allowed &&
        !          1299:            (sched_tick > (zone_gc_last_tick + zone_gc_max_rate))) {
        !          1300:                zone_gc_last_tick = sched_tick;
        !          1301:                zone_gc();
        !          1302:        }
        !          1303: }
        !          1304: 
        !          1305: #include <mach/kern_return.h>
        !          1306: #include <mach/machine/vm_types.h>
        !          1307: #include <mach_debug/zone_info.h>
        !          1308: #include <kern/host.h>
        !          1309: #include <vm/vm_map.h>
        !          1310: #include <vm/vm_user.h>
        !          1311: #include <vm/vm_kern.h>
        !          1312: 
        !          1313: #include <mach/mach_host_server.h>
        !          1314: 
        !          1315: kern_return_t
        !          1316: host_zone_info(
        !          1317:        host_t                  host,
        !          1318:        zone_name_array_t       *namesp,
        !          1319:        mach_msg_type_number_t  *namesCntp,
        !          1320:        zone_info_array_t       *infop,
        !          1321:        mach_msg_type_number_t  *infoCntp)
        !          1322: {
        !          1323:        zone_name_t     *names;
        !          1324:        vm_offset_t     names_addr;
        !          1325:        vm_size_t       names_size;
        !          1326:        zone_info_t     *info;
        !          1327:        vm_offset_t     info_addr;
        !          1328:        vm_size_t       info_size;
        !          1329:        unsigned int    max_zones, i;
        !          1330:        zone_t          z;
        !          1331:        kern_return_t   kr;
        !          1332: 
        !          1333:        if (host == HOST_NULL)
        !          1334:                return KERN_INVALID_HOST;
        !          1335: 
        !          1336:        /*
        !          1337:         *      We assume that zones aren't freed once allocated.
        !          1338:         *      We won't pick up any zones that are allocated later.
        !          1339:         */
        !          1340: 
        !          1341:        simple_lock(&all_zones_lock);
        !          1342:        max_zones = num_zones;
        !          1343:        z = first_zone;
        !          1344:        simple_unlock(&all_zones_lock);
        !          1345: 
        !          1346:        if (max_zones <= *namesCntp) {
        !          1347:                /* use in-line memory */
        !          1348: 
        !          1349:                names = *namesp;
        !          1350:        } else {
        !          1351:                names_size = round_page(max_zones * sizeof *names);
        !          1352:                kr = kmem_alloc_pageable(ipc_kernel_map,
        !          1353:                                         &names_addr, names_size);
        !          1354:                if (kr != KERN_SUCCESS)
        !          1355:                        return kr;
        !          1356: 
        !          1357:                names = (zone_name_t *) names_addr;
        !          1358:        }
        !          1359: 
        !          1360:        if (max_zones <= *infoCntp) {
        !          1361:                /* use in-line memory */
        !          1362: 
        !          1363:                info = *infop;
        !          1364:        } else {
        !          1365:                info_size = round_page(max_zones * sizeof *info);
        !          1366:                kr = kmem_alloc_pageable(ipc_kernel_map,
        !          1367:                                         &info_addr, info_size);
        !          1368:                if (kr != KERN_SUCCESS) {
        !          1369:                        if (names != *namesp)
        !          1370:                                kmem_free(ipc_kernel_map,
        !          1371:                                          names_addr, names_size);
        !          1372:                        return kr;
        !          1373:                }
        !          1374: 
        !          1375:                info = (zone_info_t *) info_addr;
        !          1376:        }
        !          1377: 
        !          1378:        for (i = 0; i < max_zones; i++) {
        !          1379:                zone_name_t *zn = &names[i];
        !          1380:                zone_info_t *zi = &info[i];
        !          1381:                struct zone zcopy;
        !          1382: 
        !          1383:                assert(z != ZONE_NULL);
        !          1384: 
        !          1385:                lock_zone(z);
        !          1386:                zcopy = *z;
        !          1387:                unlock_zone(z);
        !          1388: 
        !          1389:                simple_lock(&all_zones_lock);
        !          1390:                z = z->next_zone;
        !          1391:                simple_unlock(&all_zones_lock);
        !          1392: 
        !          1393:                /* assuming here the name data is static */
        !          1394:                (void) strncpy(zn->zn_name, zcopy.zone_name,
        !          1395:                               sizeof zn->zn_name);
        !          1396: 
        !          1397:                zi->zi_count = zcopy.count;
        !          1398:                zi->zi_cur_size = zcopy.cur_size;
        !          1399:                zi->zi_max_size = zcopy.max_size;
        !          1400:                zi->zi_elem_size = zcopy.elem_size;
        !          1401:                zi->zi_alloc_size = zcopy.alloc_size;
        !          1402:                zi->zi_exhaustible = zcopy.exhaustible;
        !          1403:                zi->zi_collectable = zcopy.collectable;
        !          1404:        }
        !          1405: 
        !          1406:        if (names != *namesp) {
        !          1407:                vm_size_t used;
        !          1408:                vm_map_copy_t copy;
        !          1409: 
        !          1410:                used = max_zones * sizeof *names;
        !          1411: 
        !          1412:                if (used != names_size)
        !          1413:                        bzero((char *) (names_addr + used), names_size - used);
        !          1414: 
        !          1415:                kr = vm_map_copyin(ipc_kernel_map, names_addr, names_size,
        !          1416:                                   TRUE, &copy);
        !          1417:                assert(kr == KERN_SUCCESS);
        !          1418: 
        !          1419:                *namesp = (zone_name_t *) copy;
        !          1420:        }
        !          1421:        *namesCntp = max_zones;
        !          1422: 
        !          1423:        if (info != *infop) {
        !          1424:                vm_size_t used;
        !          1425:                vm_map_copy_t copy;
        !          1426: 
        !          1427:                used = max_zones * sizeof *info;
        !          1428: 
        !          1429:                if (used != info_size)
        !          1430:                        bzero((char *) (info_addr + used), info_size - used);
        !          1431: 
        !          1432:                kr = vm_map_copyin(ipc_kernel_map, info_addr, info_size,
        !          1433:                                   TRUE, &copy);
        !          1434:                assert(kr == KERN_SUCCESS);
        !          1435: 
        !          1436:                *infop = (zone_info_t *) copy;
        !          1437:        }
        !          1438:        *infoCntp = max_zones;
        !          1439: 
        !          1440:        return KERN_SUCCESS;
        !          1441: }
        !          1442: 
        !          1443: #if    MACH_KDB
        !          1444: #include <ddb/db_command.h>
        !          1445: #include <ddb/db_output.h>
        !          1446: #include <kern/kern_print.h>
        !          1447: 
        !          1448: const char *zone_labels =
        !          1449: "ENTRY       COUNT   TOT_SZ   MAX_SZ ELT_SZ ALLOC_SZ NAME";
        !          1450: 
        !          1451: /* Forwards */
        !          1452: void   db_print_zone(
        !          1453:                zone_t          addr);
        !          1454: 
        !          1455: #if    ZONE_DEBUG
        !          1456: void   db_zone_check_active(
        !          1457:                zone_t          zone);
        !          1458: void   db_zone_print_active(
        !          1459:                zone_t          zone);
        !          1460: #endif /* ZONE_DEBUG */
        !          1461: void   db_zone_print_free(
        !          1462:                zone_t          zone);
        !          1463: void
        !          1464: db_print_zone(
        !          1465:        zone_t          addr)
        !          1466: {
        !          1467:        struct zone zcopy;
        !          1468: 
        !          1469:        zcopy = *addr;
        !          1470: 
        !          1471:        db_printf("%8x %8x %8x %8x %6x %8x %s ",
        !          1472:                  addr, zcopy.count, zcopy.cur_size,
        !          1473:                  zcopy.max_size, zcopy.elem_size,
        !          1474:                  zcopy.alloc_size, zcopy.zone_name);
        !          1475:        if (zcopy.exhaustible)
        !          1476:                db_printf("H");
        !          1477:        if (zcopy.collectable)
        !          1478:                db_printf("C");
        !          1479:        if (zcopy.expandable)
        !          1480:                db_printf("X");
        !          1481:        db_printf("\n");
        !          1482: }
        !          1483: 
        !          1484: /*ARGSUSED*/
        !          1485: void
        !          1486: db_show_one_zone(
        !          1487:         db_expr_t       addr,
        !          1488:         int            have_addr,
        !          1489:         db_expr_t      count,
        !          1490:         char *          modif)
        !          1491: {
        !          1492:        struct zone *z = (zone_t)addr;
        !          1493: 
        !          1494:        if (z == ZONE_NULL || !have_addr){
        !          1495:                db_error("No Zone\n");
        !          1496:                /*NOTREACHED*/
        !          1497:        }
        !          1498: 
        !          1499:        db_printf("%s\n", zone_labels);
        !          1500:        db_print_zone(z);
        !          1501: }
        !          1502: 
        !          1503: /*ARGSUSED*/
        !          1504: void
        !          1505: db_show_all_zones(
        !          1506:         db_expr_t      addr,
        !          1507:         int            have_addr,
        !          1508:         db_expr_t      count,
        !          1509:         char *         modif)
        !          1510: {
        !          1511:        zone_t          z;
        !          1512:        unsigned total = 0;
        !          1513: 
        !          1514:        /*
        !          1515:         * Don't risk hanging by unconditionally locking,
        !          1516:         * risk of incoherent data is small (zones aren't freed).
        !          1517:         */
        !          1518:        have_addr = simple_lock_try(&all_zones_lock);
        !          1519:        count = num_zones;
        !          1520:        z = first_zone;
        !          1521:        if (have_addr) {
        !          1522:                simple_unlock(&all_zones_lock);
        !          1523:        }
        !          1524: 
        !          1525:        db_printf("%s\n", zone_labels);
        !          1526:        for (  ; count > 0; count--) {
        !          1527:                if (!z) {
        !          1528:                        db_error("Mangled Zone List\n");
        !          1529:                        /*NOTREACHED*/
        !          1530:                }
        !          1531:                db_print_zone(z);
        !          1532:                total += z->cur_size,
        !          1533: 
        !          1534:                have_addr = simple_lock_try(&all_zones_lock);
        !          1535:                z = z->next_zone;
        !          1536:                if (have_addr) {
        !          1537:                        simple_unlock(&all_zones_lock);
        !          1538:                }
        !          1539:        }
        !          1540:        db_printf("\nTotal              %8x", total);
        !          1541:        db_printf("\n\nzone_gc() has reclaimed %d pages\n",
        !          1542:                  reclaim_page_count);
        !          1543: }
        !          1544: 
        !          1545: #if    ZONE_DEBUG
        !          1546: void
        !          1547: db_zone_check_active(
        !          1548:        zone_t  zone)
        !          1549: {
        !          1550:        int count = 0;
        !          1551:        queue_t tmp_elem;
        !          1552: 
        !          1553:        if (!zone_debug_enabled(zone) || !zone_check)
        !          1554:                return;
        !          1555:        tmp_elem = queue_first(&zone->active_zones);
        !          1556:        while (count < zone->count) {
        !          1557:                count++;
        !          1558:                if (tmp_elem == 0) {
        !          1559:                        printf("unexpected zero element, zone=0x%x, count=%d\n",
        !          1560:                                zone, count);
        !          1561:                        assert(FALSE);
        !          1562:                        break;
        !          1563:                }
        !          1564:                if (queue_end(tmp_elem, &zone->active_zones)) {
        !          1565:                        printf("unexpected queue_end, zone=0x%x, count=%d\n",
        !          1566:                                zone, count);
        !          1567:                        assert(FALSE);
        !          1568:                        break;
        !          1569:                }
        !          1570:                tmp_elem = queue_next(tmp_elem);
        !          1571:        }
        !          1572:        if (!queue_end(tmp_elem, &zone->active_zones)) {
        !          1573:                printf("not at queue_end, zone=0x%x, tmp_elem=0x%x\n",
        !          1574:                        zone, tmp_elem);
        !          1575:                assert(FALSE);
        !          1576:        }
        !          1577: }
        !          1578: 
        !          1579: void
        !          1580: db_zone_print_active(
        !          1581:        zone_t  zone)
        !          1582: {
        !          1583:        int count = 0;
        !          1584:        queue_t tmp_elem;
        !          1585: 
        !          1586:        if (!zone_debug_enabled(zone)) {
        !          1587:                printf("zone 0x%x debug not enabled\n", zone);
        !          1588:                return;
        !          1589:        }
        !          1590:        if (!zone_check) {
        !          1591:                printf("zone_check FALSE\n");
        !          1592:                return;
        !          1593:        }
        !          1594: 
        !          1595:        printf("zone 0x%x, active elements %d\n", zone, zone->count);
        !          1596:        printf("active list:\n");
        !          1597:        tmp_elem = queue_first(&zone->active_zones);
        !          1598:        while (count < zone->count) {
        !          1599:                printf("  0x%x", tmp_elem);
        !          1600:                count++;
        !          1601:                if ((count % 6) == 0)
        !          1602:                        printf("\n");
        !          1603:                if (tmp_elem == 0) {
        !          1604:                        printf("\nunexpected zero element, count=%d\n", count);
        !          1605:                        break;
        !          1606:                }
        !          1607:                if (queue_end(tmp_elem, &zone->active_zones)) {
        !          1608:                        printf("\nunexpected queue_end, count=%d\n", count);
        !          1609:                        break;
        !          1610:                }
        !          1611:                tmp_elem = queue_next(tmp_elem);
        !          1612:        }
        !          1613:        if (!queue_end(tmp_elem, &zone->active_zones))
        !          1614:                printf("\nnot at queue_end, tmp_elem=0x%x\n", tmp_elem);
        !          1615:        else
        !          1616:                printf("\n");
        !          1617: }
        !          1618: #endif /* ZONE_DEBUG */
        !          1619: 
        !          1620: void
        !          1621: db_zone_print_free(
        !          1622:        zone_t  zone)
        !          1623: {
        !          1624:        int count = 0;
        !          1625:        int freecount;
        !          1626:        vm_offset_t elem;
        !          1627: 
        !          1628:        freecount = zone_free_count(zone);
        !          1629:        printf("zone 0x%x, free elements %d\n", zone, freecount);
        !          1630:        printf("free list:\n");
        !          1631:        elem = zone->free_elements;
        !          1632:        while (count < freecount) {
        !          1633:                printf("  0x%x", elem);
        !          1634:                count++;
        !          1635:                if ((count % 6) == 0)
        !          1636:                        printf("\n");
        !          1637:                if (elem == 0) {
        !          1638:                        printf("\nunexpected zero element, count=%d\n", count);
        !          1639:                        break;
        !          1640:                }
        !          1641:                elem = *((vm_offset_t *)elem);
        !          1642:        }
        !          1643:        if (elem != 0)
        !          1644:                printf("\nnot at end of free list, elem=0x%x\n", elem);
        !          1645:        else
        !          1646:                printf("\n");
        !          1647: }
        !          1648: 
        !          1649: #endif /* MACH_KDB */
        !          1650: 
        !          1651: 
        !          1652: #if    ZONE_DEBUG
        !          1653: 
        !          1654: /* should we care about locks here ? */
        !          1655: 
        !          1656: #if    MACH_KDB
        !          1657: vm_offset_t
        !          1658: next_element(
        !          1659:        zone_t          z,
        !          1660:        vm_offset_t     elt)
        !          1661: {
        !          1662:        if (!zone_debug_enabled(z))
        !          1663:                return(0);
        !          1664:        elt -= sizeof(queue_chain_t);
        !          1665:        elt = (vm_offset_t) queue_next((queue_t) elt);
        !          1666:        if ((queue_t) elt == &z->active_zones)
        !          1667:                return(0);
        !          1668:        elt += sizeof(queue_chain_t);
        !          1669:        return(elt);
        !          1670: }
        !          1671: 
        !          1672: vm_offset_t
        !          1673: first_element(
        !          1674:        zone_t          z)
        !          1675: {
        !          1676:        vm_offset_t     elt;
        !          1677: 
        !          1678:        if (!zone_debug_enabled(z))
        !          1679:                return(0);
        !          1680:        if (queue_empty(&z->active_zones))
        !          1681:                return(0);
        !          1682:        elt = (vm_offset_t) queue_first(&z->active_zones);
        !          1683:        elt += sizeof(queue_chain_t);
        !          1684:        return(elt);
        !          1685: }
        !          1686: 
        !          1687: /*
        !          1688:  * Second arg controls how many zone elements are printed:
        !          1689:  *   0 => none
        !          1690:  *   n, n < 0 => all
        !          1691:  *   n, n > 0 => last n on active list
        !          1692:  */
        !          1693: int
        !          1694: zone_count(
        !          1695:        zone_t          z,
        !          1696:        int             tail)
        !          1697: {
        !          1698:        vm_offset_t     elt;
        !          1699:        int             count = 0;
        !          1700:        boolean_t       print = (tail != 0);
        !          1701: 
        !          1702:        if (tail < 0)
        !          1703:                tail = z->count;
        !          1704:        if (z->count < tail)
        !          1705:                tail = 0;
        !          1706:        tail = z->count - tail;
        !          1707:        for (elt = first_element(z); elt; elt = next_element(z, elt)) {
        !          1708:                if (print && tail <= count)
        !          1709:                        db_printf("%8x\n", elt);
        !          1710:                count++;
        !          1711:        }
        !          1712:        assert(count == z->count);
        !          1713:        return(count);
        !          1714: }
        !          1715: #endif /* MACH_KDB */
        !          1716: 
        !          1717: #define zone_in_use(z)         ( z->count || z->free_elements )
        !          1718: 
        !          1719: void
        !          1720: zone_debug_enable(
        !          1721:        zone_t          z)
        !          1722: {
        !          1723:        if (zone_debug_enabled(z) || zone_in_use(z) ||
        !          1724:            z->alloc_size < (z->elem_size + sizeof(queue_chain_t)))
        !          1725:                return;
        !          1726:        queue_init(&z->active_zones);
        !          1727:        z->elem_size += sizeof(queue_chain_t);
        !          1728: }
        !          1729: 
        !          1730: void
        !          1731: zone_debug_disable(
        !          1732:        zone_t          z)
        !          1733: {
        !          1734:        if (!zone_debug_enabled(z) || zone_in_use(z))
        !          1735:                return;
        !          1736:        z->elem_size -= sizeof(queue_chain_t);
        !          1737:        z->active_zones.next = z->active_zones.prev = 0;        
        !          1738: }
        !          1739: #endif /* ZONE_DEBUG */

unix.superglobalmegacorp.com

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