Annotation of kernel/kern/zalloc.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1993,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:  * Copyright (c) 1995, 1997 Apple Computer, Inc.
                     52:  *
                     53:  * HISTORY
                     54:  *
                     55:  * 23 June 1995 ? at NeXT
                     56:  *     Pulled over from CMU (MK83), added local
                     57:  *     mods: freespace suballocator and sorted
                     58:  *     zone free lists to reduce fragmentation.
                     59:  */
                     60: /*
                     61:  *     File:   kern/zalloc.c
                     62:  *     Author: Avadis Tevanian, Jr.
                     63:  *
                     64:  *     Zone-based memory allocator.  A zone is a collection of fixed size
                     65:  *     data blocks for which quick allocation/deallocation is possible.
                     66:  */
                     67:  
                     68: #import <mach/features.h>
                     69: 
                     70: #include <kern/macro_help.h>
                     71: #include <kern/sched.h>
                     72: #include <kern/time_out.h>
                     73: #include <kern/zalloc.h>
                     74: #include <mach/vm_param.h>
                     75: #include <vm/vm_kern.h>
                     76: 
                     77: #if    MACH_DEBUG
                     78: #include <mach/kern_return.h>
                     79: #include <mach/machine/vm_types.h>
                     80: #include <mach_debug/zone_info.h>
                     81: #include <kern/host.h>
                     82: #include <vm/vm_map.h>
                     83: #include <vm/vm_user.h>
                     84: #include <vm/vm_kern.h>
                     85: #endif
                     86: 
                     87: #define ADD_TO_ZONE(zone, element)                                     \
                     88: MACRO_BEGIN                                                            \
                     89:        vm_offset_t     cur, *last;                                     \
                     90:                if (            (zone)->last_insert != 0        &&      \
                     91:                                (element) > (zone)->last_insert )       \
                     92:                        (vm_offset_t)last = (zone)->last_insert;        \
                     93:                else                                                    \
                     94:                        last = &(zone)->free_elements;                  \
                     95:                while (         (cur = *last) != 0      &&              \
                     96:                                (element) > cur         )               \
                     97:                        (vm_offset_t)last = cur;                        \
                     98:                *(vm_offset_t *)(element) = cur;                        \
                     99:                *last = (element);                                      \
                    100:                (zone)->last_insert = (element);                        \
                    101:                (zone)->count--;                                        \
                    102: MACRO_END
                    103: 
                    104: #define REMOVE_FROM_ZONE(zone, ret, type)                              \
                    105: MACRO_BEGIN                                                            \
                    106:        (ret) = (type) (zone)->free_elements;                           \
                    107:        if ((ret) != (type) 0) {                                        \
                    108:                (zone)->count++;                                        \
                    109:                (zone)->free_elements = *(vm_offset_t *)(ret);          \
                    110:                if ((zone)->last_insert == (vm_offset_t)(ret))          \
                    111:                        (zone)->last_insert = 0;                        \
                    112:        }                                                               \
                    113: MACRO_END
                    114: 
                    115: zone_t         zone_zone;      /* this is the zone containing other zones */
                    116: 
                    117: boolean_t      zone_ignore_overflow = TRUE;
                    118: 
                    119: vm_map_t       zone_map = VM_MAP_NULL;
                    120: vm_size_t      zone_map_size;
                    121: vm_size_t      zone_map_size_min = 12 * 1024 * 1024;
                    122: vm_size_t      zone_map_size_max = 128 * 1024 * 1024;
                    123: vm_offset_t    zone_min, zone_max;
                    124: 
                    125: /*
                    126:  *     The VM system gives us an initial chunk of memory.
                    127:  *     It has to be big enough to allocate the zone_zone
                    128:  *     and some initial kernel data structures, like kernel maps.
                    129:  *     It is advantageous to make it bigger than really necessary,
                    130:  *     because this memory is more efficient than normal kernel
                    131:  *     virtual memory.  (It doesn't have vm_page structures backing it
                    132:  *     and it may have other machine-dependent advantages.)
                    133:  *     So for best performance, zdata_size should approximate
                    134:  *     the amount of memory you expect the zone system to consume.
                    135:  */
                    136: 
                    137: vm_offset_t    zdata;
                    138: vm_size_t      zdata_size = 512 * 1024;
                    139: 
                    140: #define lock_zone(zone)                                        \
                    141: MACRO_BEGIN                                            \
                    142:        if ((zone)->pageable) {                         \
                    143:                lock_write(&(zone)->complex_lock);      \
                    144:        } else {                                        \
                    145:                spl_t s = splhigh();                    \
                    146:                simple_lock(&(zone)->lock);             \
                    147:                (zone)->lock_ipl = s;                   \
                    148:        }                                               \
                    149: MACRO_END
                    150: 
                    151: #define unlock_zone(zone)                              \
                    152: MACRO_BEGIN                                            \
                    153:        if ((zone)->pageable) {                         \
                    154:                lock_done(&(zone)->complex_lock);       \
                    155:        } else {                                        \
                    156:                spl_t s = (zone)->lock_ipl;             \
                    157:                simple_unlock(&(zone)->lock);           \
                    158:                splx(s);                                \
                    159:        }                                               \
                    160: MACRO_END
                    161: 
                    162: #define lock_zone_init(zone)                           \
                    163: MACRO_BEGIN                                            \
                    164:        if ((zone)->pageable) {                         \
                    165:                lock_init(&(zone)->complex_lock, TRUE); \
                    166:        } else {                                        \
                    167:                simple_lock_init(&(zone)->lock);        \
                    168:        }                                               \
                    169: MACRO_END
                    170: 
                    171: vm_offset_t zget_space(
                    172:        struct zone_free_space  *free_space,
                    173:        vm_size_t               size,
                    174:        boolean_t               canblock);
                    175: 
                    176: decl_simple_lock_data(,zget_space_lock)
                    177: 
                    178: /*
                    179:  * A free list entry, which is created
                    180:  * at the front of an available region
                    181:  * of memory.  The 'pred' field points
                    182:  * at the 'next' pointer of the previous
                    183:  * entry (or the head pointer).
                    184:  */
                    185: struct zone_free_space_entry {
                    186:        struct zone_free_space_entry    *next;
                    187:        vm_size_t                       length;
                    188:        struct zone_free_space_entry    **pred;
                    189:        int                             _pad[1];
                    190: };
                    191: #define ZONE_MIN_ALLOC         16      /*
                    192:                                         * *Must* be:
                    193:                                         *  a power of two
                    194:                                         *      and
                    195:                                         *  at least sizeof (struct
                    196:                                         * zone_free_space_entry)
                    197:                                         */
                    198: 
                    199: /*
                    200:  * An entry in the free list hint table,
                    201:  * which allows for quickly locating a
                    202:  * suitably sized region needed to satisfy
                    203:  * a request.
                    204:  */
                    205: struct zone_free_space_hint {
                    206:        struct zone_free_space_entry    *entry;
                    207:        int                             _pad[3];
                    208: };
                    209: 
                    210: /*
                    211:  * Structure used to manage memory which
                    212:  * has been obtained from the system, but
                    213:  * which is not currently owned by any zone.
                    214:  * The main two parameters are 'alloc_unit'
                    215:  * and 'alloc_max'.  The former specifies the
                    216:  * allocation granularity.  Allocation requests
                    217:  * will be rounded up to this size, which must
                    218:  * be a power of two.  The size of the largest
                    219:  * (suggested) allocation request is specified
                    220:  * by 'alloc_max'.  The free list is headed by
                    221:  * 'entries', and is a doubly linked list of
                    222:  * free regions, sorted by ascending address.
                    223:  * There also is a table of hints, indexed by
                    224:  * region size, which is used to speed up the
                    225:  * allocations when the free list becomes
                    226:  * especially large.  It contains one entry
                    227:  * per size value between alloc_unit and alloc_max.
                    228:  */ 
                    229: struct zone_free_space {
                    230:        vm_size_t                       alloc_unit;
                    231:        vm_size_t                       alloc_max;
                    232:        struct zone_free_space_entry    *entries;
                    233:        integer_t                       num_entries;
                    234:        integer_t                       hash_shift;
                    235:        struct zone_free_space_hint     *hints;
                    236:        integer_t                       num_hints;
                    237: };
                    238: 
                    239: struct zone_free_space         *zone_free_space[8];
                    240: integer_t                      zone_free_space_count;
                    241: 
                    242: /*
                    243:  * There is a default allocation space (zone_free_space[0]),
                    244:  * which is special.  It is statically allocated, contains
                    245:  * a single hint, and space is not reclaimed from it.  It
                    246:  * is used to allocate space for non collectable zones,
                    247:  * as well as resources needed for bootstrapping purposes.
                    248:  */
                    249: struct zone_free_space_hint    _zone_default_space_hint;
                    250: struct zone_free_space         _zone_default_space;
                    251: #define        zone_default_space      (&_zone_default_space)
                    252: 
                    253: static void zone_free_space_select(zone_t      zone);
                    254: 
                    255: #define zone_collectable(z)    ((z)->free_space != 0 && \
                    256:                                        (z)->free_space != zone_default_space)
                    257: 
                    258: /*
                    259:  * Compute the hash address for an element
                    260:  * of a particular size.  Oversized requests
                    261:  * all land in the last bucket.
                    262:  */
                    263: static __inline__
                    264: integer_t
                    265: zone_free_space_hash(
                    266:        struct zone_free_space          *freespace,
                    267:        vm_size_t                       size
                    268: )
                    269: {
                    270:        integer_t               hash;
                    271:        
                    272:        if ((hash = size >> freespace->hash_shift) >
                    273:                                        freespace->num_hints)
                    274:                return (freespace->num_hints);
                    275:        else
                    276:                return (hash);
                    277: }
                    278: #define        zone_free_space_hint_from_hash(freespace, hash) \
                    279:                                        ((freespace)->hints + (hash) - 1)
                    280: 
                    281: /*
                    282:  * Return the hint entry for an element of
                    283:  * a particular size.
                    284:  */
                    285: static __inline__
                    286: struct zone_free_space_hint *
                    287: zone_free_space_hint(
                    288:        struct zone_free_space          *freespace,
                    289:        vm_size_t                       size
                    290: )
                    291: {
                    292:        return zone_free_space_hint_from_hash(freespace,
                    293:                                        zone_free_space_hash(freespace, size));
                    294: }
                    295: 
                    296: /*
                    297:  * Conditionally insert the entry into the
                    298:  * hint table such that the hint indicates
                    299:  * the lowest addressed entry of the particular
                    300:  * size.
                    301:  */
                    302: static __inline__
                    303: void
                    304: zone_free_space_hint_insert(
                    305:        struct zone_free_space          *freespace,
                    306:        struct zone_free_space_entry    *entry
                    307: )
                    308: {
                    309:        struct zone_free_space_hint     *hint;
                    310: 
                    311:        hint = zone_free_space_hint(freespace, entry->length);
                    312:        if (hint->entry == 0 || entry < hint->entry)
                    313:                hint->entry = entry;
                    314: }
                    315: 
                    316: /*
                    317:  * Delete the entry from the hint table (if
                    318:  * present), and locate the next entry of the
                    319:  * particular size by searching forwards in
                    320:  * the free list.  For the 'alloc_max' hint,
                    321:  * we choose the next entry of size >= alloc_max.
                    322:  */
                    323: static
                    324: void
                    325: zone_free_space_hint_delete(
                    326:        struct zone_free_space          *freespace,
                    327:        struct zone_free_space_entry    *entry
                    328: )
                    329: {
                    330:        integer_t                       hash;
                    331:        struct zone_free_space_hint     *hint;
                    332: 
                    333:        hash = zone_free_space_hash(freespace, entry->length);
                    334:        hint = zone_free_space_hint_from_hash(freespace, hash);
                    335: 
                    336:        if (entry == hint->entry) {
                    337:                if (hash < freespace->num_hints) {
                    338:                        struct zone_free_space_entry
                    339:                                        *cur, **last = &entry->next;
                    340: 
                    341:                        while ((cur = *last) != 0 &&
                    342:                                        cur->length != entry->length)
                    343:                                last = &cur->next;
                    344: 
                    345:                        hint->entry = cur;
                    346:                }
                    347:                else {
                    348:                        struct zone_free_space_entry
                    349:                                        *cur, **last = &entry->next;
                    350: 
                    351:                        while ((cur = *last) != 0 &&
                    352:                                        cur->length < freespace->alloc_max)
                    353:                                last = &cur->next;
                    354: 
                    355:                        hint->entry = cur;
                    356:                }
                    357:        }
                    358: }
                    359: 
                    360: /*
                    361:  * Update the hint for an entry which has been
                    362:  * expanded from the front.  In this case, the
                    363:  * header has moved (and is no longer valid),
                    364:  * so we need both the length and the address
                    365:  * of the old entry.  This could be accomplished
                    366:  * with separate delete/insert operations, but
                    367:  * this is much more efficient for several
                    368:  * important cases.
                    369:  */
                    370: static
                    371: void
                    372: zone_free_space_hint_prepend(
                    373:        struct zone_free_space          *freespace,
                    374:        struct zone_free_space_entry    *entry,
                    375:        vm_size_t                       old_length,
                    376:        void                            *old_entry
                    377: )
                    378: {
                    379:        integer_t                       old_hash, new_hash;
                    380:        struct zone_free_space_hint     *hint;
                    381: 
                    382:        /*
                    383:         * Calculate both the new and the old hash
                    384:         * addresses, as well as the old hint structure,
                    385:         * which we are likely to need.
                    386:         */
                    387:        new_hash = zone_free_space_hash(freespace, entry->length);
                    388:        old_hash = zone_free_space_hash(freespace, old_length);
                    389:        hint = zone_free_space_hint_from_hash(freespace, old_hash);
                    390: 
                    391:        /*
                    392:         * Hash address has changed.
                    393:         */
                    394:        if (old_hash != new_hash) {
                    395:                /*
                    396:                 * Old hint was valid, update it.
                    397:                 */
                    398:                if (old_entry == hint->entry) {
                    399:                        if (old_hash < freespace->num_hints) {
                    400:                                struct zone_free_space_entry
                    401:                                                *cur, **last = &entry->next;
                    402: 
                    403:                                while ((cur = *last) != 0 &&
                    404:                                                cur->length != old_length)
                    405:                                        last = &cur->next;
                    406: 
                    407:                                hint->entry = cur;
                    408:                        }
                    409:                        else {
                    410:                                struct zone_free_space_entry
                    411:                                                *cur, **last = &entry->next;
                    412: 
                    413:                                while ((cur = *last) != 0 &&
                    414:                                                cur->length < 
                    415:                                                        freespace->alloc_max)
                    416:                                        last = &cur->next;
                    417: 
                    418:                                hint->entry = cur;
                    419:                        }
                    420:                }
                    421: 
                    422:                /*
                    423:                 * Insert a hint for the new entry.
                    424:                 */
                    425:                hint = zone_free_space_hint_from_hash(freespace, new_hash);
                    426:                if (hint->entry == 0 || entry < hint->entry)
                    427:                        hint->entry = entry;
                    428:        }
                    429:        /*
                    430:         * If the hash address has not
                    431:         * changed, always replace a valid
                    432:         * old hint with the new one.
                    433:         */
                    434:        else if (old_entry == hint->entry)
                    435:                hint->entry = entry;
                    436: }
                    437: 
                    438: /*
                    439:  * Update the hint for an entry which has been
                    440:  * expanded on the end.  This could be accomplished
                    441:  * with separate delete/insert operations, but
                    442:  * this is much more efficient for several
                    443:  * important cases.
                    444:  */
                    445: static
                    446: void
                    447: zone_free_space_hint_append(
                    448:        struct zone_free_space          *freespace,
                    449:        struct zone_free_space_entry    *entry,
                    450:        vm_size_t                       old_length
                    451: )
                    452: {
                    453:        integer_t                       old_hash, new_hash;
                    454:        struct zone_free_space_hint     *hint;
                    455: 
                    456:        /*
                    457:         * Calculate both the new and the old hash
                    458:         * addresses.
                    459:         */
                    460:        new_hash = zone_free_space_hash(freespace, entry->length);
                    461:        old_hash = zone_free_space_hash(freespace, old_length);
                    462: 
                    463:        if (old_hash != new_hash) {
                    464:                hint = zone_free_space_hint_from_hash(freespace, old_hash);
                    465:                /*
                    466:                 * Old hint was valid, update it.
                    467:                 */
                    468:                if (entry == hint->entry) {
                    469:                        if (old_hash < freespace->num_hints) {
                    470:                                struct zone_free_space_entry
                    471:                                                *cur, **last = &entry->next;
                    472: 
                    473:                                while ((cur = *last) != 0 &&
                    474:                                                cur->length != old_length)
                    475:                                        last = &cur->next;
                    476: 
                    477:                                hint->entry = cur;
                    478:                        }
                    479:                        else {
                    480:                                struct zone_free_space_entry
                    481:                                                *cur, **last = &entry->next;
                    482: 
                    483:                                while ((cur = *last) != 0 &&
                    484:                                                cur->length < 
                    485:                                                        freespace->alloc_max)
                    486:                                        last = &cur->next;
                    487: 
                    488:                                hint->entry = cur;
                    489:                        }
                    490:                }
                    491: 
                    492:                /*
                    493:                 * Insert a hint for the new entry.
                    494:                 */
                    495:                hint = zone_free_space_hint_from_hash(freespace, new_hash);
                    496:                if (hint->entry == 0 || entry < hint->entry)
                    497:                        hint->entry = entry;
                    498:        }
                    499: }
                    500: 
                    501: /*
                    502:  * Locate a suitably sized entry, using the
                    503:  * allocation hints.  The entry is removed
                    504:  * from the hint table, which is also updated
                    505:  * accordingly.  The entry's position in the
                    506:  * free list is not affected.
                    507:  */
                    508: static
                    509: struct zone_free_space_entry *
                    510: zone_free_space_lookup(
                    511:        struct zone_free_space          *freespace,
                    512:        vm_size_t                       size
                    513: )
                    514: {
                    515:        integer_t                       hash;
                    516:        struct zone_free_space_hint     *hint;
                    517:        struct zone_free_space_entry    *entry;
                    518: 
                    519:        /*
                    520:         * Perform a couple of quick checks:
                    521:         * 1) an empty free list or
                    522:         * 2) a suitable first entry
                    523:         */
                    524:        if ((entry = freespace->entries) == 0)
                    525:                return (entry);
                    526:        else if (entry->length >= size) {
                    527:                zone_free_space_hint_delete(freespace, entry);
                    528:                
                    529:                return (entry);
                    530:        }
                    531: 
                    532:        /*
                    533:         * Calculate the hash address and hint
                    534:         * entry corresponding to the request
                    535:         * size.  We start there and move on to
                    536:         * the larger hints if needed.
                    537:         */
                    538:        hash = zone_free_space_hash(freespace, size); 
                    539:        hint = zone_free_space_hint_from_hash(freespace, hash);
                    540: 
                    541:        /*
                    542:         * This loop checks the exact sized hints
                    543:         * (hash to [num_hints - 1]).  If we encounter
                    544:         * a valid hint, we return that entry, after
                    545:         * first searching ahead in the free list to
                    546:         * replace it.  If we come to the end of
                    547:         * the free list while searching, we end up
                    548:         * invalidating this hint.
                    549:         */
                    550:        while (hash < freespace->num_hints) {
                    551:                if ((entry = hint->entry) != 0) {
                    552:                        struct zone_free_space_entry
                    553:                                        *cur, **last = &entry->next;
                    554: 
                    555:                        while ((cur = *last) != 0 &&
                    556:                                        cur->length != entry->length)
                    557:                                last = &cur->next;
                    558: 
                    559:                        hint->entry = cur;
                    560:                        
                    561:                        return (entry);
                    562:                }
                    563:                
                    564:                hash++; hint++;
                    565:        }
                    566: 
                    567:        /*
                    568:         * Now check the last bucket.
                    569:         */
                    570:        if ((entry = hint->entry) != 0) {
                    571:                struct zone_free_space_entry
                    572:                                *cur, **last = &entry->next;
                    573: 
                    574:                /*
                    575:                 * The last bucket contains the lowest
                    576:                 * addressed entry >= alloc_max, which
                    577:                 * isn't necessarily big enough for this
                    578:                 * request.  If it isn't big enough, then
                    579:                 * search ahead in the free list for a
                    580:                 * suitable entry to return.  In this case
                    581:                 * we also leave the current hint alone
                    582:                 * since we aren't going to use it.
                    583:                 */
                    584:                if (entry->length < size) {
                    585:                        while ((cur = *last) != 0 &&
                    586:                                        cur->length < size)
                    587:                                last = &cur->next;
                    588:                                
                    589:                        return (cur);
                    590:                }
                    591: 
                    592:                while ((cur = *last) != 0 &&
                    593:                                cur->length < freespace->alloc_max)
                    594:                        last = &cur->next;
                    595: 
                    596:                hint->entry = cur;
                    597:        }
                    598:        
                    599:        return (entry);
                    600: }
                    601: 
                    602: /*
                    603:  *     Protects first_zone, last_zone, num_zones,
                    604:  *     and the next_zone field of zones.
                    605:  */
                    606: decl_simple_lock_data(,all_zones_lock)
                    607: zone_t                 first_zone;
                    608: zone_t                 *last_zone;
                    609: int                    num_zones;
                    610: 
                    611: /*
                    612:  *     zinit initializes a new zone.  The zone data structures themselves
                    613:  *     are stored in a zone, which is initially a static structure that
                    614:  *     is initialized by zone_init.
                    615:  */
                    616: zone_t zinit(size, max, alloc, pageable, name)
                    617:        vm_size_t       size;           /* the size of an element */
                    618:        vm_size_t       max;            /* maximum memory to use */
                    619:        vm_size_t       alloc;          /* allocation size */
                    620:        boolean_t       pageable;       /* is this zone pageable? */
                    621:        char            *name;          /* a name for the zone */
                    622: {
                    623:        register zone_t         z;
                    624: 
                    625:        if (zone_zone == ZONE_NULL)
                    626:                z = (zone_t) zget_space(
                    627:                                zone_default_space,
                    628:                                sizeof(struct zone),
                    629:                                FALSE);
                    630:        else
                    631:                z = (zone_t) zalloc(zone_zone);
                    632:        if (z == ZONE_NULL)
                    633:                panic("zinit");
                    634: 
                    635:        if (alloc == 0)
                    636:                alloc = PAGE_SIZE;
                    637: 
                    638:        if (size == 0)
                    639:                size = sizeof(z->free_elements);
                    640: 
                    641:        size = ((size + (ZONE_MIN_ALLOC - 1)) & ~(ZONE_MIN_ALLOC - 1));
                    642: 
                    643:        /*
                    644:         *      Round off all the parameters appropriately.
                    645:         */
                    646: 
                    647:        if ((max = round_page(max)) < (alloc = round_page(alloc)))
                    648:                max = alloc;
                    649: 
                    650:        z->last_insert = z->free_elements = 0;
                    651:        z->cur_size = 0;
                    652:        z->max_size = max;
                    653:        z->elem_size = size;
                    654: 
                    655:        z->alloc_size = alloc;
                    656:        z->pageable = pageable;
                    657:        z->zone_name = name;
                    658:        z->count = 0;
                    659:        z->doing_alloc = FALSE;
                    660:        z->exhaustible = z->sleepable = FALSE;
                    661:        z->expandable  = TRUE;
                    662:        lock_zone_init(z);
                    663:        zone_free_space_select(z);
                    664: 
                    665:        /*
                    666:         *      Add the zone to the all-zones list.
                    667:         */
                    668: 
                    669:        z->next_zone = ZONE_NULL;
                    670:        simple_lock(simple_lock_addr(all_zones_lock));
                    671:        *last_zone = z;
                    672:        last_zone = &z->next_zone;
                    673:        num_zones++;
                    674:        simple_unlock(simple_lock_addr(all_zones_lock));
                    675: 
                    676:        return(z);
                    677: }
                    678: 
                    679: /*
                    680:  *     Cram the given memory into the specified zone.
                    681:  */
                    682: void zcram(zone, newmem, size)
                    683:        register zone_t         zone;
                    684:        vm_offset_t             newmem;
                    685:        vm_size_t               size;
                    686: {
                    687:        register vm_size_t      elem_size;
                    688: 
                    689:        if (newmem == (vm_offset_t) 0) {
                    690:                panic("zcram - memory at zero");
                    691:        }
                    692:        elem_size = zone->elem_size;
                    693: 
                    694:        lock_zone(zone);
                    695:        while (size >= elem_size) {
                    696:                ADD_TO_ZONE(zone, newmem);
                    697:                zone->count++;  /* compensate for ADD_TO_ZONE */
                    698:                size -= elem_size;
                    699:                newmem += elem_size;
                    700:                zone->cur_size += elem_size;
                    701:        }
                    702:        unlock_zone(zone);
                    703: }
                    704: 
                    705: /*
                    706:  * Allocate (return) a new zone element from a new memory
                    707:  * region.  Remaining memory from the new region is added
                    708:  * to the specified freelist.  Before generating the new 
                    709:  * element, an attempt is made to combine the new region
                    710:  * with an existing entry.  New elements are always taken
                    711:  * from the front of a free region.
                    712:  */
                    713: vm_offset_t zone_free_space_add(freespace, size, new_space, space_to_add)
                    714:        struct zone_free_space *freespace;
                    715:        vm_size_t size;
                    716:        vm_offset_t new_space;
                    717:        vm_size_t space_to_add;
                    718: {
                    719:        struct zone_free_space_entry    *cur, **last;
                    720: 
                    721:        if (freespace == 0)
                    722:                freespace = zone_default_space;
                    723: 
                    724:        /*
                    725:         * Search the free list for an existing
                    726:         * abutting entry.
                    727:         */
                    728:        last = &freespace->entries;
                    729:        while ((cur = *last) != 0 &&
                    730:                        (vm_offset_t)cur < new_space &&
                    731:                        ((vm_offset_t)cur + cur->length) != new_space)
                    732:                last = &cur->next;
                    733:                        
                    734:        if (cur == 0 || ((vm_offset_t)cur + cur->length) < new_space) {
                    735:                /*
                    736:                 * No entry was found to combine with.
                    737:                 * Take the new element from the front
                    738:                 * of the new region, and insert the
                    739:                 * remainder as a new entry.
                    740:                 */
                    741:                if ((space_to_add - size) >= ZONE_MIN_ALLOC) {
                    742:                        /*
                    743:                         * If we are not at the end of
                    744:                         * the free list, then insert the
                    745:                         * new entry after the current entry.
                    746:                         */
                    747:                        if (cur != 0)
                    748:                                last = &cur->next;
                    749:                        (vm_offset_t)cur = new_space + size;
                    750:                        cur->length = space_to_add - size;
                    751:                        if (cur->next = *last)
                    752:                                cur->next->pred = &cur->next;
                    753:                        cur->pred = last;
                    754:                        *last = cur;
                    755:                        freespace->num_entries++;
                    756: 
                    757:                        /*
                    758:                         * Insert this entry into the hint
                    759:                         * table.
                    760:                         */
                    761:                        zone_free_space_hint_insert(freespace, cur);
                    762:                }
                    763:        }
                    764:        else
                    765:        if (((vm_offset_t)cur + cur->length) == new_space) {
                    766:                struct zone_free_space_entry    *new;
                    767: 
                    768:                /*
                    769:                 * Delete the existing entry from the
                    770:                 * hint table.  It is very likely that
                    771:                 * the hash address will be changing
                    772:                 * anyways.
                    773:                 */
                    774:                zone_free_space_hint_delete(freespace, cur);
                    775: 
                    776:                /*
                    777:                 * Combine the new region with an existing
                    778:                 * entry, and take the new element from the
                    779:                 * front of the aggregate region.  Create a
                    780:                 * new entry for the remainder, and insert it
                    781:                 * in place of the existing entry.
                    782:                 */
                    783:                new_space = (vm_offset_t)cur;
                    784:                (vm_offset_t)new = (vm_offset_t)cur + size;
                    785:                new->length = cur->length + space_to_add - size;
                    786:                if (new->next = cur->next)
                    787:                        new->next->pred = &new->next;
                    788:                new->pred = last;
                    789:                *last = new;
                    790: 
                    791:                /*
                    792:                 * Insert this entry into the hint
                    793:                 * table.
                    794:                 */
                    795:                zone_free_space_hint_insert(freespace, new);
                    796:        }
                    797:        
                    798:        return (new_space);
                    799: }
                    800: 
                    801: #if    0
                    802: /* NOT USED and OUTDATED */
                    803: /*
                    804:  * Ensure that no portion of the specified region
                    805:  * is represented on the free list (either wholly
                    806:  * or in part).
                    807:  */
                    808: void zone_free_space_remove(freespace, address, size)
                    809:        struct zone_free_space *freespace;
                    810:        vm_offset_t address;
                    811:        vm_size_t size;
                    812: {
                    813:        struct zone_free_space_entry
                    814:                        *cur, **last;
                    815: 
                    816:        if (freespace == 0)
                    817:                freespace = zone_default_space;
                    818: 
                    819:        /*
                    820:         * Search the free list, looking for
                    821:         * the first suitable entry.
                    822:         */
                    823:        last = &freespace->entries;
                    824:        while ((cur = *last) != 0) {
                    825:                if ((vm_offset_t)cur >= address) {
                    826:                        /*
                    827:                         * Entry is above (and does not
                    828:                         * overlap) the region. (skip)
                    829:                         */
                    830:                        if ((vm_offset_t)cur >= (address + size))
                    831:                                last = &cur->next;
                    832:                        else {
                    833:                                /*
                    834:                                 * Entry is entirely contained
                    835:                                 * within the region. (remove)
                    836:                                 */
                    837:                                if (((vm_offset_t)cur + cur->length) <=
                    838:                                                        (address + size)) {
                    839:                                        *last = cur->next;
                    840:                                        freespace->num_entries--;
                    841:                                }
                    842:                                else {
                    843:                                        struct zone_free_space_entry    *new;
                    844: 
                    845:                                        /*
                    846:                                         * Entry overlaps the end
                    847:                                         * of the region. (clip)
                    848:                                         */
                    849:                                        (vm_offset_t)new = address + size;
                    850:                                        new->length = cur->length - 
                    851:                                                        ((vm_offset_t)new -
                    852:                                                         (vm_offset_t)cur);
                    853:                                        new->next = cur->next;
                    854:                                        *last = new;
                    855:                                }
                    856: 
                    857:                                break;
                    858:                        }
                    859:                }
                    860:                else {
                    861:                        /*
                    862:                         * Entry is entirely below the
                    863:                         * region. (skip)
                    864:                         */
                    865:                        if (((vm_offset_t)cur + cur->length) <= address)
                    866:                                last = &cur->next;
                    867:                        else {
                    868:                                /*
                    869:                                 * Entry overlaps the front
                    870:                                 * of the region. (clip)
                    871:                                 */
                    872:                                cur->length = address - (vm_offset_t)cur;
                    873:                                break;
                    874:                        }
                    875:                }
                    876:        }
                    877: }
                    878: #endif
                    879: 
                    880: /*
                    881:  * Return the elements on the zone free list back
                    882:  * to the free space pool, coalescing with existing
                    883:  * space where possible.  Caller must hold the
                    884:  * zget_space_lock, as well as the lock on the zone.
                    885:  */
                    886: void zone_collect(zone)
                    887:        struct zone     *zone;
                    888: {
                    889:        struct zone_free_space_entry    *cur, **last, *new;
                    890:        vm_offset_t                     *free, *elem, next;
                    891:        vm_size_t                       elem_size = zone->elem_size;
                    892:        struct zone_free_space          *freespace = zone->free_space;
                    893: 
                    894:        if (!zone_collectable(zone))
                    895:                return;
                    896: 
                    897:        last = &freespace->entries;
                    898: 
                    899:        free = &zone->free_elements;
                    900:        while (((vm_offset_t)elem = *free) != 0) {
                    901:                zone->cur_size -= elem_size;
                    902:                next = *elem;
                    903:                
                    904:                while ((cur = *last) != 0 &&
                    905:                                ((vm_offset_t)cur +
                    906:                                        cur->length) < (vm_offset_t)elem)
                    907:                        last = &cur->next;
                    908:                /*
                    909:                 * Either at end of (maybe empty)
                    910:                 * list, or new entry before current
                    911:                 * entry.
                    912:                 */
                    913:                if (cur == 0 || ((vm_offset_t)elem + elem_size) <
                    914:                                                        (vm_offset_t)cur) {
                    915:                        (vm_offset_t)new = (vm_offset_t)elem;
                    916:                        new->length = elem_size;
                    917:                        if (new->next = cur)
                    918:                                cur->pred = &new->next;
                    919:                        new->pred = last;
                    920:                        *last = new;
                    921:                        freespace->num_entries++;
                    922: 
                    923:                        /*
                    924:                         * Insert this entry into the hint
                    925:                         * table.
                    926:                         */
                    927:                        zone_free_space_hint_insert(freespace, new);
                    928:                }
                    929:                else
                    930:                /*
                    931:                 * Prepend element to current entry
                    932:                 */
                    933:                if (((vm_offset_t)elem + elem_size) == (vm_offset_t)cur) {
                    934:                        vm_size_t               old_length = cur->length;
                    935: 
                    936:                        (vm_offset_t)new = (vm_offset_t)elem;
                    937:                        new->length = cur->length + elem_size;
                    938:                        if (new->next = cur->next)
                    939:                                new->next->pred = &new->next;
                    940:                        new->pred = last;
                    941:                        *last = new;
                    942: 
                    943:                        /*
                    944:                         * Update the hint table.
                    945:                         */
                    946:                        zone_free_space_hint_prepend(freespace,
                    947:                                                        new, old_length, cur);
                    948:                }
                    949:                else
                    950:                /*
                    951:                 * Append element to current entry.
                    952:                 */
                    953:                if (((vm_offset_t)cur + cur->length) == (vm_offset_t)elem) {
                    954:                        vm_size_t               old_length = cur->length;
                    955: 
                    956:                        cur->length += elem_size;
                    957:                        /*
                    958:                         * Coalesce the current entry with the
                    959:                         * following one if we are filling the
                    960:                         * gap between them.
                    961:                         */
                    962:                        if (((vm_offset_t)cur + cur->length) ==
                    963:                                                (vm_offset_t)cur->next) {
                    964: 
                    965:                                /*
                    966:                                 * Delete the obsolete entry
                    967:                                 * from the hint table.
                    968:                                 */
                    969:                                zone_free_space_hint_delete(
                    970:                                                        freespace, cur->next);
                    971: 
                    972:                                cur->length += cur->next->length;
                    973:                                if (cur->next = cur->next->next)
                    974:                                        cur->next->pred = &cur->next;
                    975:                                freespace->num_entries--;
                    976:                        }
                    977: 
                    978:                        /*
                    979:                         * Update the hint table.
                    980:                         */
                    981:                        zone_free_space_hint_append(freespace,
                    982:                                                        cur, old_length);
                    983:                }
                    984:                else
                    985:                /* WTF?? */;
                    986:                
                    987:                *free = next;
                    988:        }
                    989:        
                    990:        zone->last_insert = 0;
                    991: }
                    992: 
                    993: /*
                    994:  * Scan the collectable free space free lists
                    995:  * and gather up pages which can be returned to
                    996:  * the system.  Caller must hold the zget_space_lock.
                    997:  */
                    998: struct zone_free_space_entry *
                    999: zone_free_space_reclaim(void)
                   1000: {
                   1001:        struct zone_free_space_entry    **last, *cur, *pages = 0;
                   1002:        struct zone_free_space          **f = &zone_free_space[0];
                   1003:        int                             i;
                   1004: 
                   1005:        for (i = 1; i < zone_free_space_count; i++) {
                   1006:                last = &(*++f)->entries;
                   1007:                while ((cur = *last) != 0) {
                   1008:                        if (cur->length >= PAGE_SIZE) {
                   1009:                            vm_offset_t         start, end;
                   1010:                    
                   1011:                            start = round_page((vm_offset_t)cur);
                   1012:                            end = trunc_page(
                   1013:                                    (vm_offset_t)cur + cur->length);
                   1014:                            if (start < end &&
                   1015:                                        start >= zone_min &&
                   1016:                                        end <= zone_max) {
                   1017:                                struct zone_free_space_entry    *tmp;
                   1018: 
                   1019:                                /*
                   1020:                                 * Delete this entry from the hint
                   1021:                                 * table.  Space which is leftover
                   1022:                                 * after clipping will be added back
                   1023:                                 * normally after the entries are
                   1024:                                 * created.
                   1025:                                 */ 
                   1026:                                zone_free_space_hint_delete(*f, cur);
                   1027: 
                   1028:                                /*
                   1029:                                 * If the region does not end on a
                   1030:                                 * page boundary, create a new
                   1031:                                 * trailing entry.
                   1032:                                 */
                   1033:                                if (((vm_offset_t)cur + cur->length) != end) {
                   1034:                                        (vm_offset_t)tmp = end;
                   1035:                                        tmp->length = (vm_offset_t)cur +
                   1036:                                                        cur->length - end;
                   1037:                                        if (tmp->next = cur->next)
                   1038:                                                tmp->next->pred = &tmp->next;
                   1039: 
                   1040:                                        /*
                   1041:                                         * Now, if the region does begin
                   1042:                                         * on a page boundary, just remove
                   1043:                                         * the current entry.
                   1044:                                         */
                   1045:                                        if ((vm_offset_t)cur == start) {
                   1046:                                                *last = tmp;
                   1047:                                                tmp->pred = last;
                   1048:                                        }
                   1049:                                        /*
                   1050:                                         * Otherwise, adjust the current
                   1051:                                         * entry, and link it to the new
                   1052:                                         * one.  Do not forget to account
                   1053:                                         * for the new entry.
                   1054:                                         */
                   1055:                                        else {
                   1056:                                                cur->length = start -
                   1057:                                                        (vm_offset_t)cur;
                   1058:                                                cur->next = tmp;
                   1059:                                                tmp->pred = &cur->next;
                   1060:                                                (*f)->num_entries++;
                   1061: 
                   1062:                                                /*
                   1063:                                                 * Reinsert the leading
                   1064:                                                 * entry into the hint
                   1065:                                                 * table.
                   1066:                                                 */
                   1067:                                                zone_free_space_hint_insert(
                   1068:                                                                *f, cur);
                   1069:                                        }
                   1070: 
                   1071:                                        /*
                   1072:                                         * Insert the new trailing entry
                   1073:                                         * into the hint table.
                   1074:                                         */
                   1075:                                        zone_free_space_hint_insert(*f, tmp);
                   1076:                                }
                   1077:                                /*
                   1078:                                 * If the region does not begin on a
                   1079:                                 * page boundary (but the end does),
                   1080:                                 * adjust the current entry.
                   1081:                                 */
                   1082:                                else if ((vm_offset_t)cur != start) {
                   1083:                                        cur->length = start - (vm_offset_t)cur;
                   1084: 
                   1085:                                        /*
                   1086:                                         * Reinsert the entry into
                   1087:                                         * the hint table.
                   1088:                                         */
                   1089:                                        zone_free_space_hint_insert(*f, cur);
                   1090:                                }
                   1091:                                /*
                   1092:                                 * If no clipping is required, just
                   1093:                                 * remove the current entry.
                   1094:                                 */
                   1095:                                else {
                   1096:                                        if (*last = cur->next)
                   1097:                                                cur->next->pred = last;
                   1098:                                        (*f)->num_entries--;
                   1099:                                }
                   1100: 
                   1101:                                /*
                   1102:                                 * Add the new page aligned region
                   1103:                                 * to the list of pages to be freed.
                   1104:                                 * Continue on with the next entry.
                   1105:                                 */
                   1106:                                (vm_offset_t)tmp = start;
                   1107:                                tmp->length = end - start;
                   1108:                                tmp->next = pages;
                   1109:                                pages = tmp;
                   1110:                                continue;
                   1111:                            }
                   1112:                        }
                   1113: 
                   1114:                        /*
                   1115:                         * Skip this entry.
                   1116:                         */
                   1117:                        last = &cur->next;
                   1118:                }
                   1119:        }
                   1120: 
                   1121:        return (pages);
                   1122: }
                   1123: 
                   1124: /*
                   1125:  * Contiguous space allocator for non-paged zones. Allocates "size" amount
                   1126:  * of memory from zone_map.
                   1127:  */
                   1128: 
                   1129: vm_offset_t zget_space(freespace, size, canblock)
                   1130:        struct zone_free_space *freespace;
                   1131:        vm_size_t size;
                   1132:        boolean_t canblock;
                   1133: {
                   1134:        vm_offset_t     new_space = 0;
                   1135:        vm_offset_t     result;
                   1136:        vm_size_t       space_to_add;
                   1137:        struct zone_free_space_entry
                   1138:                        *cur, **last;
                   1139: 
                   1140:        if (freespace == 0)
                   1141:                freespace = zone_default_space;
                   1142: 
                   1143:        /*
                   1144:         * Round up all requests (even 0) to
                   1145:         * our minimum allocation unit.
                   1146:         */
                   1147:        if (size > ZONE_MIN_ALLOC)
                   1148:                size = ((size + (ZONE_MIN_ALLOC - 1)) & ~(ZONE_MIN_ALLOC - 1));
                   1149:        else
                   1150:                size = ZONE_MIN_ALLOC;
                   1151: 
                   1152:        simple_lock(simple_lock_addr(zget_space_lock));
                   1153:        for (;;) {
                   1154:                if ((cur = zone_free_space_lookup(freespace, size)) != 0) {
                   1155:                        last = cur->pred;
                   1156: 
                   1157:                        /*
                   1158:                         * The entry which was found has been
                   1159:                         * removed from the hint table, but
                   1160:                         * remains in the free list.  Trim off
                   1161:                         * the space to be returned.
                   1162:                         */
                   1163:                        if ((cur->length - size) < ZONE_MIN_ALLOC) {
                   1164:                                /*
                   1165:                                 * This is a real lose if it
                   1166:                                 * happens in a collectable
                   1167:                                 * space, since the memory
                   1168:                                 * will be lost, making it
                   1169:                                 * impossible to reclaim the
                   1170:                                 * page later.
                   1171:                                 */
                   1172:                                if (*last = cur->next)
                   1173:                                        cur->next->pred = last;
                   1174:                                freespace->num_entries--;
                   1175:                        }
                   1176:                        else {
                   1177:                                struct zone_free_space_entry    *new;
                   1178: 
                   1179:                                /*
                   1180:                                 * Create a new entry for the
                   1181:                                 * remaining space and position
                   1182:                                 * on the free list.
                   1183:                                 */
                   1184:                                (vm_offset_t)new = (vm_offset_t)cur + size;
                   1185:                                new->length = cur->length - size;
                   1186:                                if (new->next = cur->next)
                   1187:                                        new->next->pred = &new->next;
                   1188:                                new->pred = last;
                   1189:                                *last = new;
                   1190: 
                   1191:                                /*
                   1192:                                 * After trimming the entry, reinsert
                   1193:                                 * it back into the hint table.
                   1194:                                 */
                   1195:                                zone_free_space_hint_insert(freespace, new);
                   1196:                        }
                   1197:                        result = (vm_offset_t)cur;
                   1198:                        break;
                   1199:                }
                   1200:                else if (new_space == 0) {
                   1201:                        /*
                   1202:                         *      Add at least one page to allocation area.
                   1203:                         */
                   1204:        
                   1205:                        space_to_add = round_page(size);
                   1206: 
                   1207:                        if (zdata_size >= space_to_add) {
                   1208:                                zdata_size -= space_to_add;
                   1209:                                result = zone_free_space_add(
                   1210:                                                        freespace,
                   1211:                                                        size,
                   1212:                                                        zdata + zdata_size,
                   1213:                                                        space_to_add);
                   1214:                                break;
                   1215:                        }
                   1216: 
                   1217:                        /*
                   1218:                         *      Memory cannot be wired down while holding
                   1219:                         *      any locks that the pageout daemon might
                   1220:                         *      need to free up pages.  [Making the zget_space
                   1221:                         *      lock a complex lock does not help in this
                   1222:                         *      regard.]
                   1223:                         *
                   1224:                         *      Unlock and allocate memory.  Because several
                   1225:                         *      threads might try to do this at once, don't
                   1226:                         *      use the memory before checking for available
                   1227:                         *      space again.
                   1228:                         */
                   1229: 
                   1230:                        simple_unlock(simple_lock_addr(zget_space_lock));
                   1231:                        {
                   1232:                                kern_return_t   kr;
                   1233: 
                   1234:                                kr = kmem_alloc_zone(zone_map,
                   1235:                                                     &new_space, space_to_add,
                   1236:                                                        canblock);
                   1237:                                if (kr != KERN_SUCCESS) {
                   1238:                                        if (kr == KERN_NO_SPACE)
                   1239:                                                panic("zget_space");
                   1240: 
                   1241:                                        return(0);
                   1242:                                }
                   1243:                        }
                   1244: 
                   1245:                        simple_lock(simple_lock_addr(zget_space_lock));
                   1246:                        continue;
                   1247:                }
                   1248:                else {
                   1249:                        /*
                   1250:                         *      Memory was allocated in a previous iteration.
                   1251:                         */
                   1252: 
                   1253:                        result = zone_free_space_add(
                   1254:                                                freespace,
                   1255:                                                size,
                   1256:                                                new_space,
                   1257:                                                space_to_add);
                   1258:                        new_space = 0;
                   1259:                        break;
                   1260:                }
                   1261:        }
                   1262:        simple_unlock(simple_lock_addr(zget_space_lock));
                   1263: 
                   1264:        if (new_space != 0)
                   1265:                kmem_free(zone_map, new_space, space_to_add);
                   1266: 
                   1267:        return(result);
                   1268: }
                   1269: 
                   1270: static
                   1271: struct zone_free_space *
                   1272: zone_free_space_alloc(alloc_unit, alloc_max)
                   1273:        vm_size_t       alloc_unit;
                   1274:        vm_size_t       alloc_max;
                   1275: {
                   1276:        struct zone_free_space  *freespace, **f;
                   1277:        
                   1278:        if (zone_free_space_count >=
                   1279:                        (sizeof (zone_free_space) / sizeof (freespace)))
                   1280:                return (0);
                   1281:        
                   1282:        f = &zone_free_space[zone_free_space_count++];
                   1283: 
                   1284:        (vm_offset_t)freespace = zget_space(
                   1285:                                        zone_default_space,
                   1286:                                        sizeof (struct zone_free_space), 
                   1287:                                        FALSE);
                   1288:        freespace->alloc_unit = alloc_unit;
                   1289:        freespace->alloc_max = alloc_max;
                   1290: 
                   1291:        freespace->entries = 0;
                   1292:        freespace->num_entries = 0;
                   1293:        
                   1294:        freespace->hash_shift = 0;
                   1295:        while (!(alloc_unit & 01)) {
                   1296:                freespace->hash_shift++; alloc_unit >>= 1;
                   1297:        }
                   1298: 
                   1299:        freespace->num_hints = freespace->alloc_max >> freespace->hash_shift;
                   1300:        (vm_offset_t)freespace->hints =
                   1301:                        zget_space(
                   1302:                                zone_default_space,
                   1303:                                freespace->num_hints *
                   1304:                                        sizeof (struct zone_free_space_hint),
                   1305:                                FALSE);
                   1306:        bzero(freespace->hints, freespace->num_hints *
                   1307:                                        sizeof (struct zone_free_space_hint));
                   1308: 
                   1309:        *f = freespace;
                   1310:        
                   1311:        return (freespace);
                   1312: }
                   1313: 
                   1314: static
                   1315: void
                   1316: zone_free_space_select(zone)
                   1317:        zone_t          zone;
                   1318: {
                   1319:        struct zone_free_space  **f = &zone_free_space[1];
                   1320:        vm_size_t       elem_size;
                   1321:        int             i;
                   1322:        
                   1323:        if (zone->cur_size > 0)
                   1324:                return;
                   1325:        
                   1326:        for (i = 1; i < zone_free_space_count; i++) {
                   1327:                elem_size = ((zone->elem_size + ((*f)->alloc_unit - 1))
                   1328:                                & ~((*f)->alloc_unit - 1));
                   1329:                if (elem_size <= (*f)->alloc_max) {
                   1330:                        zone->elem_size = elem_size;                            
                   1331:                        zone->free_space = *f;
                   1332:                        break;
                   1333:                }
                   1334:                
                   1335:                f++;
                   1336:        }
                   1337: }
                   1338: 
                   1339: /*
                   1340:  *     Initialize the "zone of zones" which uses fixed memory allocated
                   1341:  *     earlier in memory initialization.  zone_bootstrap is called
                   1342:  *     before zone_init.
                   1343:  */
                   1344: void zone_bootstrap(void)
                   1345: {
                   1346:        simple_lock_init(simple_lock_addr(all_zones_lock));
                   1347:        first_zone = ZONE_NULL;
                   1348:        last_zone = &first_zone;
                   1349:        num_zones = 0;
                   1350: 
                   1351:        if (sizeof (struct zone_free_space_entry) > ZONE_MIN_ALLOC)
                   1352:                panic("zone_bootstrap");
                   1353: 
                   1354:        simple_lock_init(simple_lock_addr(zget_space_lock));
                   1355: 
                   1356:        _zone_default_space.hints = &_zone_default_space_hint;
                   1357:        _zone_default_space.num_hints = 1;
                   1358:        
                   1359:        zone_free_space[0] = &_zone_default_space;
                   1360:        zone_free_space_count = 1;
                   1361: 
                   1362:        zone_zone = ZONE_NULL;
                   1363:        zone_zone = zinit(sizeof(struct zone), 128 * sizeof(struct zone),
                   1364:                          sizeof(struct zone), FALSE, "zones");
                   1365: 
                   1366:        zone_free_space_alloc(16,       96);
                   1367:        zone_free_space_alloc(128,      768);
                   1368:        zone_free_space_alloc(1024,     PAGE_SIZE);
                   1369: }
                   1370: 
                   1371: vm_size_t
                   1372: zone_map_sizer(void)
                   1373: {
                   1374: #if defined(__ppc__)
                   1375:        vm_size_t       map_size = mem_size / 4;
                   1376: #else
                   1377:        vm_size_t       map_size = mem_size / 8;
                   1378: #endif
                   1379: 
                   1380:        if (map_size < zone_map_size_min)
                   1381:                map_size = zone_map_size_min;
                   1382:        else
                   1383:        if (map_size > zone_map_size_max)
                   1384:                map_size = zone_map_size_max;
                   1385: 
                   1386:        return (map_size);
                   1387: }
                   1388: 
                   1389: void zone_init(void)
                   1390: {
                   1391:        zone_map_size = zone_map_sizer();
                   1392: 
                   1393:        zone_map = kmem_suballoc(kernel_map, &zone_min, &zone_max,
                   1394:                                 zone_map_size, FALSE);
                   1395: }
                   1396: 
                   1397: 
                   1398: /*
                   1399:  *     zalloc returns an element from the specified zone.
                   1400:  */
                   1401: static
                   1402: vm_offset_t zalloc_canblock(zone, canblock)
                   1403:        register zone_t zone;
                   1404:        boolean_t canblock;
                   1405: {
                   1406:        vm_offset_t     addr;
                   1407: 
                   1408:        if (zone == ZONE_NULL)
                   1409:                panic ("zalloc: null zone");
                   1410: 
                   1411:        lock_zone(zone);
                   1412:        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                   1413:        while (addr == 0) {
                   1414:                /*
                   1415:                 *      If nothing was there, try to get more
                   1416:                 */
                   1417:                if (zone->doing_alloc) {
                   1418:                        /*
                   1419:                         *      Someone is allocating memory for this zone.
                   1420:                         *      Wait for it to show up, then try again.
                   1421:                         */
                   1422:                        if (!canblock) {
                   1423:                                unlock_zone(zone);
                   1424:                                return(0);
                   1425:                        }
                   1426:                        assert_wait((event_t)&zone->doing_alloc, TRUE);
                   1427:                        /* XXX say wakeup needed */
                   1428:                        unlock_zone(zone);
                   1429:                        thread_block_with_continuation((void (*)()) 0);
                   1430:                        lock_zone(zone);
                   1431:                }
                   1432:                else {
                   1433:                        if ((zone->cur_size + (zone->pageable ?
                   1434:                                zone->alloc_size : zone->elem_size)) >
                   1435:                            zone->max_size) {
                   1436:                                if (zone->exhaustible)
                   1437:                                        break;
                   1438: 
                   1439:                                if (zone->expandable) {
                   1440:                                        /*
                   1441:                                         * We're willing to overflow certain
                   1442:                                         * zones, but not without complaining.
                   1443:                                         *
                   1444:                                         * This is best used in conjunction
                   1445:                                         * with the collecatable flag. What we
                   1446:                                         * want is an assurance we can get the
                   1447:                                         * memory back, assuming there's no
                   1448:                                         * leak. 
                   1449:                                         */
                   1450:                                        zone->max_size += (zone->max_size >> 1);
                   1451:                                } else if (!zone_ignore_overflow) {
                   1452:                                        unlock_zone(zone);
                   1453:                                        if (!canblock)
                   1454:                                                return(0);
                   1455:                                        printf("zone \"%s\" empty.\n",
                   1456:                                                zone->zone_name);
                   1457:                                        panic("zalloc");
                   1458:                                }
                   1459:                        }
                   1460: 
                   1461:                        if (zone->pageable)
                   1462:                                zone->doing_alloc = TRUE;
                   1463:                        unlock_zone(zone);
                   1464: 
                   1465:                        if (zone->pageable) {
                   1466:                                if (kmem_alloc_pageable(zone_map, &addr,
                   1467:                                                        zone->alloc_size)
                   1468:                                                        != KERN_SUCCESS)
                   1469:                                        panic("zalloc");
                   1470:                                zcram(zone, addr, zone->alloc_size);
                   1471:                                lock_zone(zone);
                   1472:                                zone->doing_alloc = FALSE; 
                   1473:                                /* XXX check before doing this */
                   1474:                                thread_wakeup((event_t)&zone->doing_alloc);
                   1475: 
                   1476:                                REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                   1477:                        } else {
                   1478:                                addr = zget_space(
                   1479:                                        zone->free_space,
                   1480:                                        zone->elem_size,
                   1481:                                        canblock);
                   1482:                                if (addr == 0) {
                   1483:                                        if (!canblock)
                   1484:                                                return(0);
                   1485:                                        panic("zalloc");
                   1486:                                }
                   1487: 
                   1488:                                lock_zone(zone);
                   1489:                                zone->count++;
                   1490:                                zone->cur_size += zone->elem_size;
                   1491:                                unlock_zone(zone);
                   1492:                                return(addr);
                   1493:                        }
                   1494:                }
                   1495:        }
                   1496: 
                   1497:        unlock_zone(zone);
                   1498:        return(addr);
                   1499: }
                   1500: 
                   1501: vm_offset_t zalloc(zone)
                   1502:        register zone_t zone;
                   1503: {
                   1504:        return (zalloc_canblock(zone, TRUE));
                   1505: }
                   1506: 
                   1507: vm_offset_t zalloc_noblock(zone)
                   1508:        register zone_t zone;
                   1509: {
                   1510:        return (zalloc_canblock(zone, FALSE));
                   1511: }
                   1512: 
                   1513: 
                   1514: /*
                   1515:  *     zget returns an element from the specified zone
                   1516:  *     and immediately returns nothing if there is nothing there.
                   1517:  *
                   1518:  *     This form should be used when you can not block (like when
                   1519:  *     processing an interrupt).
                   1520:  */
                   1521: vm_offset_t zget(zone)
                   1522:        register zone_t zone;
                   1523: {
                   1524:        register vm_offset_t    addr;
                   1525: 
                   1526:        if (zone == ZONE_NULL)
                   1527:                panic ("zalloc: null zone");
                   1528: 
                   1529:        lock_zone(zone);
                   1530:        REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
                   1531:        unlock_zone(zone);
                   1532: 
                   1533:        return(addr);
                   1534: }
                   1535: 
                   1536: boolean_t zone_check = FALSE;
                   1537: 
                   1538: void zfree(zone, elem)
                   1539:        register zone_t zone;
                   1540:        vm_offset_t     elem;
                   1541: {
                   1542:        lock_zone(zone);
                   1543:        if (zone_check) {
                   1544:                vm_offset_t this;
                   1545: 
                   1546:                /* check the zone's consistency */
                   1547: 
                   1548:                for (this = zone->free_elements;
                   1549:                     this != 0;
                   1550:                     this = * (vm_offset_t *) this)
                   1551:                        if (this == elem)
                   1552:                                panic("zfree");
                   1553:        }
                   1554:        ADD_TO_ZONE(zone, elem);
                   1555:        unlock_zone(zone);
                   1556: }
                   1557: 
                   1558: void zcollectable(zone) 
                   1559:        zone_t          zone;
                   1560: {
                   1561:        /* zones are collectable by default
                   1562:         * and cannot later be changed back to collectable */
                   1563: }
                   1564: 
                   1565: void zchange(zone, pageable, sleepable, exhaustible, collectable)
                   1566:        zone_t          zone;
                   1567:        boolean_t       pageable;
                   1568:        boolean_t       sleepable;
                   1569:        boolean_t       exhaustible;
                   1570:        boolean_t       collectable;
                   1571: {
                   1572:        zone->pageable = pageable;
                   1573:        zone->sleepable = sleepable;
                   1574:        zone->exhaustible = exhaustible;
                   1575:        /* zones are collectable by default
                   1576:         * and later can only be changed to non-collectable */
                   1577:        if (!collectable)
                   1578:                zone->free_space = zone_default_space;
                   1579:        lock_zone_init(zone);
                   1580: }
                   1581: 
                   1582: #if    MACH_DEBUG
                   1583: kern_return_t host_zone_info(host, namesp, namesCntp, infop, infoCntp)
                   1584:        host_t          host;
                   1585:        zone_name_array_t *namesp;
                   1586:        unsigned int    *namesCntp;
                   1587:        zone_info_array_t *infop;
                   1588:        unsigned int    *infoCntp;
                   1589: {
                   1590:        zone_name_t     *names;
                   1591:        vm_offset_t     names_addr;
                   1592:        vm_size_t       names_size = 0; /*'=0' to quiet gcc warnings */
                   1593:        zone_info_t     *info;
                   1594:        vm_offset_t     info_addr;
                   1595:        vm_size_t       info_size = 0; /*'=0' to quiet gcc warnings */
                   1596:        unsigned int    max_zones, i;
                   1597:        zone_t          z;
                   1598:        kern_return_t   kr;
                   1599: 
                   1600:        if (host == HOST_NULL)
                   1601:                return KERN_INVALID_HOST;
                   1602: 
                   1603:        /*
                   1604:         *      We assume that zones aren't freed once allocated.
                   1605:         *      We won't pick up any zones that are allocated later.
                   1606:         */
                   1607: 
                   1608:        simple_lock(simple_lock_addr(all_zones_lock));
                   1609:        max_zones = num_zones;
                   1610:        z = first_zone;
                   1611:        simple_unlock(simple_lock_addr(all_zones_lock));
                   1612: 
                   1613:        if (max_zones <= *namesCntp) {
                   1614:                /* use in-line memory */
                   1615: 
                   1616:                names = *namesp;
                   1617:        } else {
                   1618:                names_size = round_page(max_zones * sizeof *names);
                   1619:                kr = kmem_alloc_pageable(ipc_kernel_map,
                   1620:                                         &names_addr, names_size);
                   1621:                if (kr != KERN_SUCCESS)
                   1622:                        return kr;
                   1623: 
                   1624:                names = (zone_name_t *) names_addr;
                   1625:        }
                   1626: 
                   1627:        if (max_zones <= *infoCntp) {
                   1628:                /* use in-line memory */
                   1629: 
                   1630:                info = *infop;
                   1631:        } else {
                   1632:                info_size = round_page(max_zones * sizeof *info);
                   1633:                kr = kmem_alloc_pageable(ipc_kernel_map,
                   1634:                                         &info_addr, info_size);
                   1635:                if (kr != KERN_SUCCESS) {
                   1636:                        if (names != *namesp)
                   1637:                                kmem_free(ipc_kernel_map,
                   1638:                                          names_addr, names_size);
                   1639:                        return kr;
                   1640:                }
                   1641: 
                   1642:                info = (zone_info_t *) info_addr;
                   1643:        }
                   1644: 
                   1645:        for (i = 0; i < max_zones; i++) {
                   1646:                zone_name_t *zn = &names[i];
                   1647:                zone_info_t *zi = &info[i];
                   1648:                struct zone zcopy;
                   1649: 
                   1650:                assert(z != ZONE_NULL);
                   1651: 
                   1652:                lock_zone(z);
                   1653:                zcopy = *z;
                   1654:                unlock_zone(z);
                   1655: 
                   1656:                simple_lock(simple_lock_addr(all_zones_lock));
                   1657:                z = z->next_zone;
                   1658:                simple_unlock(simple_lock_addr(all_zones_lock));
                   1659: 
                   1660:                /* assuming here the name data is static */
                   1661:                (void) strncpy(zn->zn_name, zcopy.zone_name,
                   1662:                               sizeof zn->zn_name);
                   1663: 
                   1664:                zi->zi_count = zcopy.count;
                   1665:                zi->zi_cur_size = zcopy.cur_size;
                   1666:                zi->zi_max_size = zcopy.max_size;
                   1667:                zi->zi_elem_size = zcopy.elem_size;
                   1668:                zi->zi_alloc_size = zcopy.alloc_size;
                   1669:                zi->zi_pageable = zcopy.pageable;
                   1670:                zi->zi_sleepable = zcopy.sleepable;
                   1671:                zi->zi_exhaustible = zcopy.exhaustible;
                   1672:                zi->zi_collectable = zone_collectable(&zcopy);
                   1673:        }
                   1674: 
                   1675:        if (names != *namesp) {
                   1676:                vm_size_t used;
                   1677: #if    MACH_OLD_VM_COPY
                   1678: #else
                   1679:                vm_map_copy_t copy;
                   1680: #endif
                   1681: 
                   1682:                used = max_zones * sizeof *names;
                   1683: 
                   1684:                if (used != names_size)
                   1685:                        bzero((char *) (names_addr + used), names_size - used);
                   1686: 
                   1687: #if    MACH_OLD_VM_COPY
                   1688:                kr = vm_move(
                   1689:                        ipc_kernel_map, names_addr,
                   1690:                        ipc_soft_map, names_size,
                   1691:                        TRUE, &names_addr);
                   1692:                assert(kr == KERN_SUCCESS);
                   1693: 
                   1694:                *namesp = (zone_name_t *) names_addr;
                   1695: #else
                   1696:                kr = vm_map_copyin(ipc_kernel_map, names_addr, names_size,
                   1697:                                   TRUE, &copy);
                   1698:                assert(kr == KERN_SUCCESS);
                   1699: 
                   1700:                *namesp = (zone_name_t *) copy;
                   1701: #endif
                   1702:        }
                   1703:        *namesCntp = max_zones;
                   1704: 
                   1705:        if (info != *infop) {
                   1706:                vm_size_t used;
                   1707: #if    MACH_OLD_VM_COPY
                   1708: #else
                   1709:                vm_map_copy_t copy;
                   1710: #endif
                   1711: 
                   1712:                used = max_zones * sizeof *info;
                   1713: 
                   1714:                if (used != info_size)
                   1715:                        bzero((char *) (info_addr + used), info_size - used);
                   1716: 
                   1717: #if    MACH_OLD_VM_COPY
                   1718:                kr = vm_move(
                   1719:                        ipc_kernel_map, info_addr,
                   1720:                        ipc_soft_map, info_size,
                   1721:                        TRUE, &info_addr);
                   1722:                assert(kr == KERN_SUCCESS);
                   1723: 
                   1724:                *infop = (zone_info_t *) info_addr;
                   1725: #else
                   1726:                kr = vm_map_copyin(ipc_kernel_map, info_addr, info_size,
                   1727:                                   TRUE, &copy);
                   1728:                assert(kr == KERN_SUCCESS);
                   1729: 
                   1730:                *infop = (zone_info_t *) copy;
                   1731: #endif
                   1732:        }
                   1733:        *infoCntp = max_zones;
                   1734: 
                   1735:        return KERN_SUCCESS;
                   1736: }
                   1737: 
                   1738: kern_return_t host_zone_free_space_info(
                   1739:                                host,
                   1740:                                infop, infoCnt,
                   1741:                                chunksp, chunksCnt)
                   1742:        host_t                          host;
                   1743:        zone_free_space_info_array_t    *infop;
                   1744:        mach_msg_type_number_t          *infoCnt;
                   1745:        zone_free_space_chunk_array_t   *chunksp;
                   1746:        mach_msg_type_number_t          *chunksCnt;
                   1747: {
                   1748:        kern_return_t   kr;
                   1749:        vm_size_t       size1, size2;
                   1750:        vm_offset_t     addr1, addr2;
                   1751:        vm_offset_t     memory1, memory2;
                   1752:        mach_msg_type_number_t
                   1753:                        actual1, actual2;
                   1754:        zone_free_space_info_t
                   1755:                        *info;
                   1756:        zone_free_space_chunk_t
                   1757:                        *chunk;
                   1758:        struct zone_free_space_entry
                   1759:                        **last, *cur;
                   1760:        struct zone_free_space
                   1761:                        *freespace;
                   1762:        int             i;
                   1763: 
                   1764:        if (host == HOST_NULL)
                   1765:                return KERN_INVALID_HOST;
                   1766: 
                   1767:        size1 = size2 = 0;
                   1768: 
                   1769:        for (;;) {
                   1770:                vm_size_t       size1_needed, size2_needed;
                   1771: 
                   1772:                size1_needed = size2_needed = 0;
                   1773: 
                   1774:                simple_lock(simple_lock_addr(zget_space_lock));
                   1775: 
                   1776:                actual1 = actual2 = 0;
                   1777:                
                   1778:                for (actual1 = 0; actual1 < zone_free_space_count; actual1++)
                   1779:                        actual2 += zone_free_space[actual1]->num_entries;
                   1780:                
                   1781:                if (actual1 > *infoCnt)
                   1782:                        size1_needed = round_page(
                   1783:                                actual1 * sizeof (**infop));
                   1784:                
                   1785:                if (actual2 > *chunksCnt)
                   1786:                        size2_needed = round_page(
                   1787:                                actual2 * sizeof (**chunksp));
                   1788: 
                   1789:                if (size1_needed <= size1 &&
                   1790:                                size2_needed <= size2)
                   1791:                        break;
                   1792: 
                   1793:                simple_unlock(simple_lock_addr(zget_space_lock));
                   1794: 
                   1795:                if (size1 < size1_needed) {
                   1796:                        if (size1 != 0)
                   1797:                                kmem_free(ipc_kernel_map, addr1, size1);
                   1798:                        size1 = size1_needed;
                   1799: 
                   1800:                        kr = kmem_alloc_pageable(
                   1801:                                                ipc_kernel_map, &addr1, size1);
                   1802:                        if (kr != KERN_SUCCESS) {
                   1803:                                if (size2 != 0)
                   1804:                                        kmem_free(
                   1805:                                                ipc_kernel_map, addr2, size2);
                   1806:                                return KERN_RESOURCE_SHORTAGE;
                   1807:                        }
                   1808: #if    MACH_OLD_VM_COPY
                   1809:                        kr = vm_map_pageable(
                   1810:                                ipc_kernel_map, addr1, addr1 + size1, FALSE);
                   1811:                        assert(kr == KERN_SUCCESS);
                   1812: #else
                   1813:                        kr = vm_map_pageable(
                   1814:                                        ipc_kernel_map, addr1, addr1 + size1,
                   1815:                                                VM_PROT_READ|VM_PROT_WRITE);
                   1816:                        assert(kr == KERN_SUCCESS);
                   1817: #endif
                   1818:                }
                   1819: 
                   1820:                if (size2 < size2_needed) {
                   1821:                        if (size2 != 0)
                   1822:                                kmem_free(ipc_kernel_map, addr2, size2);
                   1823:                        size2 = size2_needed;
                   1824: 
                   1825:                        kr = kmem_alloc_pageable(
                   1826:                                                ipc_kernel_map, &addr2, size2);
                   1827:                        if (kr != KERN_SUCCESS) {
                   1828:                                if (size1 != 0)
                   1829:                                        kmem_free(
                   1830:                                                ipc_kernel_map, addr1, size1);
                   1831:                                return KERN_RESOURCE_SHORTAGE;
                   1832:                        }
                   1833: #if    MACH_OLD_VM_COPY
                   1834:                        kr = vm_map_pageable(
                   1835:                                ipc_kernel_map, addr2, addr2 + size2, FALSE);
                   1836:                        assert(kr == KERN_SUCCESS);
                   1837: #else
                   1838:                        kr = vm_map_pageable(
                   1839:                                        ipc_kernel_map, addr2, addr2 + size2,
                   1840:                                                VM_PROT_READ|VM_PROT_WRITE);
                   1841:                        assert(kr == KERN_SUCCESS);
                   1842: #endif
                   1843:                }
                   1844:        }
                   1845: 
                   1846:        if (size1 != 0)
                   1847:                info = (zone_free_space_info_t *)addr1;
                   1848:        else
                   1849:                info = *infop;
                   1850: 
                   1851:        if (size2 != 0)
                   1852:                chunk = (zone_free_space_chunk_t *)addr2;
                   1853:        else
                   1854:                chunk = *chunksp;
                   1855: 
                   1856:        for (i = 0; i < actual1; i++) {
                   1857:                freespace = zone_free_space[i];
                   1858: 
                   1859:                info->zf_alloc_unit = freespace->alloc_unit;
                   1860:                info->zf_alloc_max = freespace->alloc_max;
                   1861:                info->zf_num_chunks = freespace->num_entries;
                   1862:                info++;
                   1863: 
                   1864:                last = &freespace->entries;
                   1865:                while ((cur = *last) != 0) {
                   1866:                        chunk->zf_address = (vm_offset_t)cur;
                   1867:                        chunk->zf_length = cur->length;
                   1868:                        chunk++;
                   1869:                        
                   1870:                        last = &cur->next;
                   1871:                }
                   1872:        }
                   1873: 
                   1874:        simple_unlock(simple_lock_addr(zget_space_lock));
                   1875: 
                   1876:        if (actual1 != 0 && size1 != 0) {
                   1877:                vm_size_t       size_used;
                   1878:                
                   1879:                size_used = round_page(actual1 * sizeof (**infop));
                   1880: 
                   1881: #if    MACH_OLD_VM_COPY
                   1882:                kr = vm_map_pageable(
                   1883:                        ipc_kernel_map, addr1, addr1 + size_used, TRUE);
                   1884:                assert(kr == KERN_SUCCESS);
                   1885: 
                   1886:                kr = vm_move(
                   1887:                        ipc_kernel_map, addr1,
                   1888:                        ipc_soft_map, size_used,
                   1889:                        TRUE, &memory1);
                   1890:                assert(kr == KERN_SUCCESS);
                   1891: #else
                   1892:                kr = vm_map_pageable(
                   1893:                                ipc_kernel_map,
                   1894:                                addr1, addr1 + size_used, VM_PROT_NONE);
                   1895:                assert(kr == KERN_SUCCESS);
                   1896:        
                   1897:                kr = vm_map_copyin(
                   1898:                                ipc_kernel_map, addr1, size_used,
                   1899:                                TRUE, &memory1);
                   1900:                assert(kr == KERN_SUCCESS);
                   1901: #endif
                   1902:        
                   1903:                if (size_used != size1)
                   1904:                        kmem_free(
                   1905:                                ipc_kernel_map,
                   1906:                                addr1 + size_used, size1 - size_used);
                   1907: 
                   1908:                *infop = (zone_free_space_info_t *)memory1;
                   1909:        }
                   1910:        else if (actual1 == 0) {
                   1911: #if    MACH_OLD_VM_COPY
                   1912:                *infop = (zone_free_space_info_t *)0;
                   1913: #else
                   1914:                *infop = (zone_free_space_info_t *)VM_MAP_COPY_NULL;
                   1915: #endif
                   1916: 
                   1917:                if (size1 != 0)
                   1918:                        kmem_free(ipc_kernel_map, addr1, size1);
                   1919:        }
                   1920:        
                   1921:        *infoCnt = actual1;
                   1922: 
                   1923:        if (actual2 != 0 && size2 != 0) {
                   1924:                vm_size_t       size_used;
                   1925: 
                   1926:                size_used = round_page(actual2 * sizeof (**chunksp));
                   1927: 
                   1928: #if    MACH_OLD_VM_COPY
                   1929:                kr = vm_map_pageable(
                   1930:                        ipc_kernel_map, addr2, addr2 + size_used, TRUE);
                   1931:                assert(kr == KERN_SUCCESS);
                   1932: 
                   1933:                kr = vm_move(
                   1934:                        ipc_kernel_map, addr2,
                   1935:                        ipc_soft_map, size_used,
                   1936:                        TRUE, &memory2);
                   1937:                assert(kr == KERN_SUCCESS);
                   1938: #else
                   1939:                kr = vm_map_pageable(
                   1940:                                ipc_kernel_map,
                   1941:                                addr2, addr2 + size2, VM_PROT_NONE);
                   1942:                assert(kr == KERN_SUCCESS);
                   1943: 
                   1944:                kr = vm_map_copyin(
                   1945:                                ipc_kernel_map, addr2, size_used,
                   1946:                                TRUE, &memory2);
                   1947:                assert(kr == KERN_SUCCESS);
                   1948: #endif
                   1949: 
                   1950:                if (size_used != size2)
                   1951:                        kmem_free(
                   1952:                                ipc_kernel_map,
                   1953:                                addr2 + size_used, size2 - size_used);
                   1954: 
                   1955:                *chunksp = (zone_free_space_chunk_t *)memory2;
                   1956:        }
                   1957:        else if (actual2 == 0) {
                   1958: #if    MACH_OLD_VM_COPY
                   1959:                *chunksp = (zone_free_space_chunk_t *)0;
                   1960: #else
                   1961:                *chunksp = (zone_free_space_chunk_t *)VM_MAP_COPY_NULL;
                   1962: #endif
                   1963: 
                   1964:                if (size2 != 0)
                   1965:                        kmem_free(ipc_kernel_map, addr2, size2);
                   1966:        }
                   1967: 
                   1968:        *chunksCnt = actual2;
                   1969: 
                   1970:        return KERN_SUCCESS;
                   1971: }
                   1972: 
                   1973: kern_return_t host_zone_collect(
                   1974:        host_t          host,
                   1975:        boolean_t       collect_zones,
                   1976:        boolean_t       reclaim_pages)
                   1977: {
                   1978:        struct zone_free_space_entry
                   1979:                        *cur, *pages = 0;
                   1980:        zone_t          z;
                   1981:        int             max_zones, i;
                   1982: 
                   1983:        if (host == HOST_NULL)
                   1984:                return KERN_INVALID_HOST;
                   1985: 
                   1986:        if (!collect_zones)
                   1987:            return KERN_SUCCESS;
                   1988:        
                   1989:        simple_lock(simple_lock_addr(zget_space_lock));
                   1990: 
                   1991:        simple_lock(simple_lock_addr(all_zones_lock));
                   1992:        max_zones = num_zones;
                   1993:        z = first_zone;
                   1994:        simple_unlock(simple_lock_addr(all_zones_lock));
                   1995: 
                   1996:        for (i = 0; i < max_zones; i++) {
                   1997:                assert(z != ZONE_NULL);
                   1998:        /* run this at splhigh so that interupt routines that use zones
                   1999:           can not interupt while their zone is locked */
                   2000:                lock_zone(z);
                   2001: 
                   2002:                if (!z->pageable && zone_collectable(z))
                   2003:                    zone_collect(z);
                   2004: 
                   2005:                unlock_zone(z);         
                   2006:                simple_lock(simple_lock_addr(all_zones_lock));
                   2007:                z = z->next_zone;
                   2008:                simple_unlock(simple_lock_addr(all_zones_lock));
                   2009:        }
                   2010: 
                   2011:        if (reclaim_pages)
                   2012:                pages = zone_free_space_reclaim();
                   2013:        
                   2014:        simple_unlock(simple_lock_addr(zget_space_lock));
                   2015: 
                   2016:        /*
                   2017:         * Return any reclaimed pages to
                   2018:         * the system.
                   2019:         */
                   2020:        while ((cur = pages) != 0) {
                   2021:                pages = cur->next;
                   2022:                kmem_free(zone_map, (vm_offset_t)cur, cur->length);
                   2023:        }
                   2024: 
                   2025:        return KERN_SUCCESS;
                   2026: }
                   2027: #endif MACH_DEBUG

unix.superglobalmegacorp.com

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