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

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