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

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

unix.superglobalmegacorp.com

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