Annotation of kernel/ipc/ipc_entry.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:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
        !            27:  * Open Software Foundation, Inc. 
        !            28:  *  
        !            29:  * Permission to use, copy, modify, and distribute this software and 
        !            30:  * its documentation for any purpose and without fee is hereby granted, 
        !            31:  * provided that the above copyright notice appears in all copies and 
        !            32:  * that both the copyright notice and this permission notice appear in 
        !            33:  * supporting documentation, and that the name of ("OSF") or Open Software 
        !            34:  * Foundation not be used in advertising or publicity pertaining to 
        !            35:  * distribution of the software without specific, written prior permission. 
        !            36:  *  
        !            37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
        !            38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
        !            39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
        !            40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
        !            41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
        !            42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
        !            43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
        !            44:  */
        !            45: /*
        !            46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
        !            47:  */
        !            48: /* 
        !            49:  * Mach Operating System
        !            50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
        !            51:  * All Rights Reserved.
        !            52:  * 
        !            53:  * Permission to use, copy, modify and distribute this software and its
        !            54:  * documentation is hereby granted, provided that both the copyright
        !            55:  * notice and this permission notice appear in all copies of the
        !            56:  * software, derivative works or modified versions, and any portions
        !            57:  * thereof, and that both notices appear in supporting documentation.
        !            58:  * 
        !            59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            62:  * 
        !            63:  * Carnegie Mellon requests users of this software to return to
        !            64:  * 
        !            65:  *  Software Distribution Coordinator  or  [email protected]
        !            66:  *  School of Computer Science
        !            67:  *  Carnegie Mellon University
        !            68:  *  Pittsburgh PA 15213-3890
        !            69:  * 
        !            70:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            71:  * the rights to redistribute these changes.
        !            72:  */
        !            73: /*
        !            74:  *     File:   ipc/ipc_entry.c
        !            75:  *     Author: Rich Draves
        !            76:  *     Date:   1989
        !            77:  *
        !            78:  *     Primitive functions to manipulate translation entries.
        !            79:  */
        !            80: 
        !            81: #include <mach/kern_return.h>
        !            82: #include <mach/port.h>
        !            83: #include <kern/assert.h>
        !            84: #include <kern/sched_prim.h>
        !            85: #include <kern/zalloc.h>
        !            86: #include <ipc/port.h>
        !            87: #include <ipc/ipc_entry.h>
        !            88: #include <ipc/ipc_space.h>
        !            89: #include <ipc/ipc_splay.h>
        !            90: #include <ipc/ipc_object.h>
        !            91: #include <ipc/ipc_hash.h>
        !            92: #include <ipc/ipc_table.h>
        !            93: #include <ipc/ipc_port.h>
        !            94: 
        !            95: zone_t ipc_tree_entry_zone;
        !            96: 
        !            97: /*
        !            98:  * Forward declarations
        !            99:  */
        !           100: boolean_t ipc_entry_tree_collision(
        !           101:        ipc_space_t     space,
        !           102:        mach_port_t     name);
        !           103: 
        !           104: /*
        !           105:  *     Routine:        ipc_entry_tree_collision
        !           106:  *     Purpose:
        !           107:  *             Checks if "name" collides with an allocated name
        !           108:  *             in the space's tree.  That is, returns TRUE
        !           109:  *             if the splay tree contains a name with the same
        !           110:  *             index as "name".
        !           111:  *     Conditions:
        !           112:  *             The space is locked (read or write) and active.
        !           113:  */
        !           114: 
        !           115: boolean_t
        !           116: ipc_entry_tree_collision(
        !           117:        ipc_space_t     space,
        !           118:        mach_port_t     name)
        !           119: {
        !           120:        mach_port_index_t index;
        !           121:        mach_port_t lower, upper;
        !           122: 
        !           123:        assert(space->is_active);
        !           124: 
        !           125:        /*
        !           126:         *      Check if we collide with the next smaller name
        !           127:         *      or the next larger name.
        !           128:         */
        !           129: 
        !           130:        ipc_splay_tree_bounds(&space->is_tree, name, &lower, &upper);
        !           131: 
        !           132:        index = MACH_PORT_INDEX(name);
        !           133:        return (((lower != ~0) && (MACH_PORT_INDEX(lower) == index)) ||
        !           134:                ((upper != 0) && (MACH_PORT_INDEX(upper) == index)));
        !           135: }
        !           136: 
        !           137: /*
        !           138:  *     Routine:        ipc_entry_lookup
        !           139:  *     Purpose:
        !           140:  *             Searches for an entry, given its name.
        !           141:  *     Conditions:
        !           142:  *             The space must be read or write locked throughout.
        !           143:  *             The space must be active.
        !           144:  */
        !           145: 
        !           146: ipc_entry_t
        !           147: ipc_entry_lookup(
        !           148:        ipc_space_t     space,
        !           149:        mach_port_t     name)
        !           150: {
        !           151:        mach_port_index_t index;
        !           152:        ipc_entry_t entry;
        !           153: 
        !           154:        assert(space->is_active);
        !           155: 
        !           156:        index = MACH_PORT_INDEX(name);
        !           157:        if (index < space->is_table_size) {
        !           158:                entry = &space->is_table[index];
        !           159:                if (IE_BITS_GEN(entry->ie_bits) != MACH_PORT_GEN(name))
        !           160:                        if (entry->ie_bits & IE_BITS_COLLISION) {
        !           161:                                assert(space->is_tree_total > 0);
        !           162:                                goto tree_lookup;
        !           163:                        } else
        !           164:                                entry = IE_NULL;
        !           165:                else if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !           166:                        entry = IE_NULL;
        !           167:        } else if (space->is_tree_total == 0)
        !           168:                entry = IE_NULL;
        !           169:        else
        !           170:            tree_lookup:
        !           171:                entry = (ipc_entry_t)
        !           172:                                ipc_splay_tree_lookup(&space->is_tree, name);
        !           173: 
        !           174:        assert((entry == IE_NULL) || IE_BITS_TYPE(entry->ie_bits));
        !           175:        return entry;
        !           176: }
        !           177: 
        !           178: /*
        !           179:  *     Routine:        ipc_entry_get
        !           180:  *     Purpose:
        !           181:  *             Tries to allocate an entry out of the space.
        !           182:  *     Conditions:
        !           183:  *             The space is write-locked and active throughout.
        !           184:  *             An object may be locked.  Will not allocate memory.
        !           185:  *     Returns:
        !           186:  *             KERN_SUCCESS            A free entry was found.
        !           187:  *             KERN_NO_SPACE           No entry allocated.
        !           188:  */
        !           189: 
        !           190: kern_return_t
        !           191: ipc_entry_get(
        !           192:        ipc_space_t     space,
        !           193:        mach_port_t     *namep,
        !           194:        ipc_entry_t     *entryp)
        !           195: {
        !           196:        ipc_entry_t table;
        !           197:        mach_port_index_t first_free;
        !           198:        ipc_entry_t free_entry;
        !           199: 
        !           200:        assert(space->is_active);
        !           201: 
        !           202:        {
        !           203:                table = space->is_table;
        !           204:                first_free = table->ie_next;
        !           205: 
        !           206:                if (first_free == 0)
        !           207:                        return KERN_NO_SPACE;
        !           208: 
        !           209:                free_entry = &table[first_free];
        !           210:                table->ie_next = free_entry->ie_next;
        !           211:        }
        !           212: 
        !           213:        /*
        !           214:         *      Initialize the new entry.  We need only
        !           215:         *      increment the generation number and clear ie_request.
        !           216:         */
        !           217: 
        !           218:     {
        !           219:        mach_port_t new_name;
        !           220:        mach_port_gen_t gen;
        !           221: 
        !           222:        assert((free_entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
        !           223:        gen = free_entry->ie_bits + IE_BITS_GEN_ONE;
        !           224:        free_entry->ie_bits = gen;
        !           225:        free_entry->ie_request = 0;
        !           226:        /*
        !           227:         *      The new name can't be MACH_PORT_NULL because index
        !           228:         *      is non-zero.  It can't be MACH_PORT_DEAD because
        !           229:         *      the table isn't allowed to grow big enough.
        !           230:         *      (See comment in ipc/ipc_table.h.)
        !           231:         */
        !           232:        new_name = MACH_PORT_MAKE(first_free, gen);
        !           233:        assert(MACH_PORT_VALID(new_name));
        !           234:        *namep = new_name;
        !           235:     }
        !           236: 
        !           237:        assert(free_entry->ie_object == IO_NULL);
        !           238: 
        !           239:        *entryp = free_entry;
        !           240:        return KERN_SUCCESS;
        !           241: }
        !           242: 
        !           243: /*
        !           244:  *     Routine:        ipc_entry_alloc
        !           245:  *     Purpose:
        !           246:  *             Allocate an entry out of the space.
        !           247:  *     Conditions:
        !           248:  *             The space is not locked before, but it is write-locked after
        !           249:  *             if the call is successful.  May allocate memory.
        !           250:  *     Returns:
        !           251:  *             KERN_SUCCESS            An entry was allocated.
        !           252:  *             KERN_INVALID_TASK       The space is dead.
        !           253:  *             KERN_NO_SPACE           No room for an entry in the space.
        !           254:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory for an entry.
        !           255:  */
        !           256: 
        !           257: kern_return_t
        !           258: ipc_entry_alloc(
        !           259:        ipc_space_t     space,
        !           260:        mach_port_t     *namep,
        !           261:        ipc_entry_t     *entryp)
        !           262: {
        !           263:        kern_return_t kr;
        !           264: 
        !           265:        is_write_lock(space);
        !           266: 
        !           267:        for (;;) {
        !           268:                if (!space->is_active) {
        !           269:                        is_write_unlock(space);
        !           270:                        return KERN_INVALID_TASK;
        !           271:                }
        !           272: 
        !           273:                kr = ipc_entry_get(space, namep, entryp);
        !           274:                if (kr == KERN_SUCCESS)
        !           275:                        return kr;
        !           276: 
        !           277:                kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
        !           278:                if (kr != KERN_SUCCESS)
        !           279:                        return kr; /* space is unlocked */
        !           280:        }
        !           281: }
        !           282: 
        !           283: /*
        !           284:  *     Routine:        ipc_entry_alloc_name
        !           285:  *     Purpose:
        !           286:  *             Allocates/finds an entry with a specific name.
        !           287:  *             If an existing entry is returned, its type will be nonzero.
        !           288:  *     Conditions:
        !           289:  *             The space is not locked before, but it is write-locked after
        !           290:  *             if the call is successful.  May allocate memory.
        !           291:  *     Returns:
        !           292:  *             KERN_SUCCESS            Found existing entry with same name.
        !           293:  *             KERN_SUCCESS            Allocated a new entry.
        !           294:  *             KERN_INVALID_TASK       The space is dead.
        !           295:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
        !           296:  */
        !           297: 
        !           298: kern_return_t
        !           299: ipc_entry_alloc_name(
        !           300:        ipc_space_t     space,
        !           301:        mach_port_t     name,
        !           302:        ipc_entry_t     *entryp)
        !           303: {
        !           304:        mach_port_index_t index = MACH_PORT_INDEX(name);
        !           305:        mach_port_gen_t gen = MACH_PORT_GEN(name);
        !           306:        ipc_tree_entry_t tree_entry = ITE_NULL;
        !           307: 
        !           308:        assert(MACH_PORT_VALID(name));
        !           309: 
        !           310:        is_write_lock(space);
        !           311: 
        !           312:        for (;;) {
        !           313:                ipc_entry_t entry;
        !           314:                ipc_tree_entry_t tentry;
        !           315:                ipc_table_size_t its;
        !           316: 
        !           317:                if (!space->is_active) {
        !           318:                        is_write_unlock(space);
        !           319:                        if (tree_entry) ite_free(tree_entry);
        !           320:                        return KERN_INVALID_TASK;
        !           321:                }
        !           322: 
        !           323:                /*
        !           324:                 *      If we are under the table cutoff,
        !           325:                 *      there are three cases:
        !           326:                 *              1) The entry is inuse, for the same name
        !           327:                 *              2) The entry is inuse, for a different name
        !           328:                 *              3) The entry is free
        !           329:                 */
        !           330: 
        !           331:                if ((0 < index) && (index < space->is_table_size)) {
        !           332:                        ipc_entry_t table = space->is_table;
        !           333: 
        !           334:                        entry = &table[index];
        !           335: 
        !           336:                        if (IE_BITS_TYPE(entry->ie_bits)) {
        !           337:                                if (IE_BITS_GEN(entry->ie_bits) == gen) {
        !           338:                                        *entryp = entry;
        !           339:                                        if (tree_entry) ite_free(tree_entry);
        !           340:                                        return KERN_SUCCESS;
        !           341:                                }
        !           342:                        } else {
        !           343:                                mach_port_index_t free_index, next_index;
        !           344: 
        !           345:                                /*
        !           346:                                 *      Rip the entry out of the free list.
        !           347:                                 */
        !           348: 
        !           349:                                for (free_index = 0;
        !           350:                                     (next_index = table[free_index].ie_next)
        !           351:                                                        != index;
        !           352:                                     free_index = next_index)
        !           353:                                        continue;
        !           354: 
        !           355:                                table[free_index].ie_next =
        !           356:                                        table[next_index].ie_next;
        !           357: 
        !           358:                                entry->ie_bits = gen;
        !           359:                                assert(entry->ie_object == IO_NULL);
        !           360:                                entry->ie_request = 0;
        !           361: 
        !           362:                                *entryp = entry;
        !           363:                                if (tree_entry) ite_free(tree_entry);
        !           364:                                return KERN_SUCCESS;
        !           365:                        }
        !           366:                }
        !           367: 
        !           368:                /*
        !           369:                 *      Before trying to allocate any memory,
        !           370:                 *      check if the entry already exists in the tree.
        !           371:                 *      This avoids spurious resource errors.
        !           372:                 *      The splay tree makes a subsequent lookup/insert
        !           373:                 *      of the same name cheap, so this costs little.
        !           374:                 */
        !           375: 
        !           376:                if ((space->is_tree_total > 0) &&
        !           377:                    ((tentry = ipc_splay_tree_lookup(&space->is_tree, name))
        !           378:                                                        != ITE_NULL)) {
        !           379:                        assert(tentry->ite_space == space);
        !           380:                        assert(IE_BITS_TYPE(tentry->ite_bits));
        !           381: 
        !           382:                        *entryp = &tentry->ite_entry;
        !           383:                        if (tree_entry) ite_free(tree_entry);
        !           384:                        return KERN_SUCCESS;
        !           385:                }
        !           386: 
        !           387:                its = space->is_table_next;
        !           388: 
        !           389:                /*
        !           390:                 *      Check if the table should be grown.
        !           391:                 *
        !           392:                 *      Note that if space->is_table_size == its->its_size,
        !           393:                 *      then we won't ever try to grow the table.
        !           394:                 *
        !           395:                 *      Note that we are optimistically assuming that name
        !           396:                 *      doesn't collide with any existing names.  (So if
        !           397:                 *      it were entered into the tree, is_tree_small would
        !           398:                 *      be incremented.)  This is OK, because even in that
        !           399:                 *      case, we don't lose memory by growing the table.
        !           400:                 */
        !           401: 
        !           402:                if ((space->is_table_size <= index) &&
        !           403:                    (index < its->its_size) &&
        !           404:                    (((its->its_size - space->is_table_size) *
        !           405:                      sizeof(struct ipc_entry)) <
        !           406:                     ((space->is_tree_small + 1) *
        !           407:                      sizeof(struct ipc_tree_entry)))) {
        !           408:                        kern_return_t kr;
        !           409: 
        !           410:                        /*
        !           411:                         *      Can save space by growing the table.
        !           412:                         *      Because the space will be unlocked,
        !           413:                         *      we must restart.
        !           414:                         */
        !           415: 
        !           416:                        kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
        !           417:                        assert(kr != KERN_NO_SPACE);
        !           418:                        if (kr != KERN_SUCCESS) {
        !           419:                                /* space is unlocked */
        !           420:                                if (tree_entry) ite_free(tree_entry);
        !           421:                                return kr;
        !           422:                        }
        !           423: 
        !           424:                        continue;
        !           425:                }
        !           426: 
        !           427:                /*
        !           428:                 *      If a splay-tree entry was allocated previously,
        !           429:                 *      go ahead and insert it into the tree.
        !           430:                 */
        !           431: 
        !           432:                if (tree_entry != ITE_NULL) {
        !           433:                        space->is_tree_total++;
        !           434: 
        !           435:                        if (index < space->is_table_size)
        !           436:                                space->is_table[index].ie_bits |=
        !           437:                                        IE_BITS_COLLISION;
        !           438:                        else if ((index < its->its_size) &&
        !           439:                                 !ipc_entry_tree_collision(space, name))
        !           440:                                space->is_tree_small++;
        !           441: 
        !           442:                        ipc_splay_tree_insert(&space->is_tree,
        !           443:                                              name, tree_entry);
        !           444: 
        !           445:                        tree_entry->ite_bits = 0;
        !           446:                        tree_entry->ite_object = IO_NULL;
        !           447:                        tree_entry->ite_request = 0;
        !           448:                        tree_entry->ite_space = space;
        !           449:                        *entryp = &tree_entry->ite_entry;
        !           450:                        return KERN_SUCCESS;
        !           451:                }
        !           452: 
        !           453:                /*
        !           454:                 *      Allocate a tree entry and try again.
        !           455:                 */
        !           456: 
        !           457:                is_write_unlock(space);
        !           458:                tree_entry = ite_alloc();
        !           459:                if (tree_entry == ITE_NULL)
        !           460:                        return KERN_RESOURCE_SHORTAGE;
        !           461:                is_write_lock(space);
        !           462:        }
        !           463: }
        !           464: 
        !           465: /*
        !           466:  *     Routine:        ipc_entry_dealloc
        !           467:  *     Purpose:
        !           468:  *             Deallocates an entry from a space.
        !           469:  *     Conditions:
        !           470:  *             The space must be write-locked throughout.
        !           471:  *             The space must be active.
        !           472:  */
        !           473: 
        !           474: void
        !           475: ipc_entry_dealloc(
        !           476:        ipc_space_t     space,
        !           477:        mach_port_t     name,
        !           478:        ipc_entry_t     entry)
        !           479: {
        !           480:        ipc_entry_t table;
        !           481:        ipc_entry_num_t size;
        !           482:        mach_port_index_t index;
        !           483: 
        !           484:        assert(space->is_active);
        !           485:        assert(entry->ie_object == IO_NULL);
        !           486:        assert(entry->ie_request == 0);
        !           487: 
        !           488:        index = MACH_PORT_INDEX(name);
        !           489:        table = space->is_table;
        !           490:        size = space->is_table_size;
        !           491: 
        !           492:        if ((index < size) && (entry == &table[index])) {
        !           493:                assert(IE_BITS_GEN(entry->ie_bits) == MACH_PORT_GEN(name));
        !           494: 
        !           495:                if (entry->ie_bits & IE_BITS_COLLISION) {
        !           496:                        struct ipc_splay_tree small, collisions;
        !           497:                        ipc_tree_entry_t tentry;
        !           498:                        mach_port_t tname;
        !           499:                        boolean_t pick;
        !           500:                        ipc_entry_bits_t bits;
        !           501:                        ipc_object_t obj;
        !           502: 
        !           503:                        /* must move an entry from tree to table */
        !           504: 
        !           505:                        ipc_splay_tree_split(&space->is_tree,
        !           506:                                             MACH_PORT_MAKE(index+1, 0),
        !           507:                                             &collisions);
        !           508:                        ipc_splay_tree_split(&collisions,
        !           509:                                             MACH_PORT_MAKE(index, 0),
        !           510:                                             &small);
        !           511: 
        !           512:                        pick = ipc_splay_tree_pick(&collisions,
        !           513:                                                   &tname, &tentry);
        !           514:                        assert(pick);
        !           515:                        assert(MACH_PORT_INDEX(tname) == index);
        !           516: 
        !           517:                        bits = tentry->ite_bits;
        !           518:                        entry->ie_bits = bits | MACH_PORT_GEN(tname);
        !           519:                        entry->ie_object = obj = tentry->ite_object;
        !           520:                        entry->ie_request = tentry->ite_request;
        !           521:                        assert(tentry->ite_space == space);
        !           522: 
        !           523:                        if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND) {
        !           524:                                ipc_hash_global_delete(space, obj,
        !           525:                                                       tname, tentry);
        !           526:                                ipc_hash_local_insert(space, obj,
        !           527:                                                      index, entry);
        !           528:                        }
        !           529: 
        !           530:                        ipc_splay_tree_delete(&collisions, tname, tentry);
        !           531: 
        !           532:                        assert(space->is_tree_total > 0);
        !           533:                        space->is_tree_total--;
        !           534: 
        !           535:                        /* check if collision bit should still be on */
        !           536: 
        !           537:                        pick = ipc_splay_tree_pick(&collisions,
        !           538:                                                   &tname, &tentry);
        !           539:                        if (pick) {
        !           540:                                entry->ie_bits |= IE_BITS_COLLISION;
        !           541:                                ipc_splay_tree_join(&space->is_tree,
        !           542:                                                    &collisions);
        !           543:                        }
        !           544: 
        !           545:                        ipc_splay_tree_join(&space->is_tree, &small);
        !           546:                } else {
        !           547:                        entry->ie_bits &= IE_BITS_GEN_MASK;
        !           548:                        entry->ie_next = table->ie_next;
        !           549:                        table->ie_next = index;
        !           550:                }
        !           551:        } else {
        !           552:                ipc_tree_entry_t tentry = (ipc_tree_entry_t) entry;
        !           553: 
        !           554:                assert(tentry->ite_space == space);
        !           555: 
        !           556:                ipc_splay_tree_delete(&space->is_tree, name, tentry);
        !           557: 
        !           558:                assert(space->is_tree_total > 0);
        !           559:                space->is_tree_total--;
        !           560: 
        !           561:                if (index < size) {
        !           562:                        ipc_entry_t ientry = &table[index];
        !           563: 
        !           564:                        assert(ientry->ie_bits & IE_BITS_COLLISION);
        !           565: 
        !           566:                        if (!ipc_entry_tree_collision(space, name))
        !           567:                                ientry->ie_bits &= ~IE_BITS_COLLISION;
        !           568:                } else if ((index < space->is_table_next->its_size) &&
        !           569:                           !ipc_entry_tree_collision(space, name)) {
        !           570:                        assert(space->is_tree_small > 0);
        !           571:                        space->is_tree_small--;
        !           572:                }
        !           573:        }
        !           574: }
        !           575: 
        !           576: /*
        !           577:  *     Routine:        ipc_entry_grow_table
        !           578:  *     Purpose:
        !           579:  *             Grows the table in a space.
        !           580:  *     Conditions:
        !           581:  *             The space must be write-locked and active before.
        !           582:  *             If successful, it is also returned locked.
        !           583:  *             Allocates memory.
        !           584:  *     Returns:
        !           585:  *             KERN_SUCCESS            Grew the table.
        !           586:  *             KERN_SUCCESS            Somebody else grew the table.
        !           587:  *             KERN_SUCCESS            The space died.
        !           588:  *             KERN_NO_SPACE           Table has maximum size already.
        !           589:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate a new table.
        !           590:  */
        !           591: 
        !           592: kern_return_t
        !           593: ipc_entry_grow_table(
        !           594:        ipc_space_t     space,
        !           595:        int             target_size)
        !           596: {
        !           597:        ipc_entry_num_t osize, size, nsize, psize;
        !           598: 
        !           599:        do {
        !           600:                ipc_entry_t otable, table;
        !           601:                ipc_table_size_t oits, its, nits;
        !           602:                mach_port_index_t i, free_index;
        !           603: 
        !           604:                assert(space->is_active);
        !           605: 
        !           606:                if (space->is_growing) {
        !           607:                        /*
        !           608:                         *      Somebody else is growing the table.
        !           609:                         *      We just wait for them to finish.
        !           610:                         */
        !           611: 
        !           612:                        assert_wait((event_t) space, FALSE);
        !           613:                        is_write_unlock(space);
        !           614:                        thread_block_with_continuation((void (*)()) 0);
        !           615:                        is_write_lock(space);
        !           616:                        return KERN_SUCCESS;
        !           617:                }
        !           618: 
        !           619:                otable = space->is_table;
        !           620:                
        !           621:                its = space->is_table_next;
        !           622:                size = its->its_size;
        !           623:                
        !           624:                /*
        !           625:                 * Since is_table_next points to the next natural size
        !           626:                 * we can identify the current size entry.
        !           627:                 */
        !           628:                oits = its - 1;
        !           629:                osize = oits->its_size;
        !           630:                
        !           631:                /*
        !           632:                 * If there is no target size, then the new size is simply
        !           633:                 * specified by is_table_next.  If there is a target
        !           634:                 * size, then search for the next entry.
        !           635:                 */
        !           636:                if (target_size != ITS_SIZE_NONE) {
        !           637:                        if (target_size <= osize) {
        !           638:                                is_write_unlock(space);
        !           639:                                return KERN_SUCCESS;
        !           640:                        }
        !           641: 
        !           642:                        psize = osize;
        !           643:                        while ((psize != size) && (target_size > size)) {
        !           644:                                psize = size;
        !           645:                                its++;
        !           646:                                size = its->its_size;
        !           647:                        }
        !           648:                        if (psize == size) {
        !           649:                                is_write_unlock(space);
        !           650:                                return KERN_NO_SPACE;
        !           651:                        }
        !           652:                }
        !           653:                nits = its + 1;
        !           654:                nsize = nits->its_size;
        !           655: 
        !           656:                if (osize == size) {
        !           657:                        is_write_unlock(space);
        !           658:                        return KERN_NO_SPACE;
        !           659:                }
        !           660: 
        !           661:                assert((osize < size) && (size <= nsize));
        !           662: 
        !           663:                /*
        !           664:                 *      OK, we'll attempt to grow the table.
        !           665:                 *      The realloc requires that the old table
        !           666:                 *      remain in existence.
        !           667:                 */
        !           668: 
        !           669:                space->is_growing = TRUE;
        !           670:                is_write_unlock(space);
        !           671:                if (it_entries_reallocable(oits))
        !           672:                        table = it_entries_realloc(oits, otable, its);
        !           673:                else
        !           674:                        table = it_entries_alloc(its);
        !           675:                is_write_lock(space);
        !           676:                space->is_growing = FALSE;
        !           677: 
        !           678:                /*
        !           679:                 *      We need to do a wakeup on the space,
        !           680:                 *      to rouse waiting threads.  We defer
        !           681:                 *      this until the space is unlocked,
        !           682:                 *      because we don't want them to spin.
        !           683:                 */
        !           684: 
        !           685:                if (table == IE_NULL) {
        !           686:                        is_write_unlock(space);
        !           687:                        thread_wakeup((event_t) space);
        !           688:                        return KERN_RESOURCE_SHORTAGE;
        !           689:                }
        !           690: 
        !           691:                if (!space->is_active) {
        !           692:                        /*
        !           693:                         *      The space died while it was unlocked.
        !           694:                         */
        !           695: 
        !           696:                        is_write_unlock(space);
        !           697:                        thread_wakeup((event_t) space);
        !           698:                        it_entries_free(its, table);
        !           699:                        is_write_lock(space);
        !           700:                        return KERN_SUCCESS;
        !           701:                }
        !           702: 
        !           703:                assert(space->is_table == otable);
        !           704:                assert((space->is_table_next == its) ||
        !           705:                       (target_size != ITS_SIZE_NONE));
        !           706:                assert(space->is_table_size == osize);
        !           707: 
        !           708:                space->is_table = table;
        !           709:                space->is_table_size = size;
        !           710:                space->is_table_next = nits;
        !           711: 
        !           712:                /*
        !           713:                 *      If we did a realloc, it remapped the data.
        !           714:                 *      Otherwise we copy by hand first.  Then we have
        !           715:                 *      to clear the index fields in the old part and
        !           716:                 *      zero the new part.
        !           717:                 */
        !           718: 
        !           719:                if (!it_entries_reallocable(oits))
        !           720:                        bcopy((char *) otable, (char *) table,
        !           721:                              osize * sizeof(struct ipc_entry));
        !           722: 
        !           723:                for (i = 0; i < osize; i++)
        !           724:                        table[i].ie_index = 0;
        !           725: 
        !           726:                bzero((char *) (table + osize),
        !           727:                      (size - osize) * sizeof(struct ipc_entry));
        !           728: 
        !           729:                /*
        !           730:                 *      Put old entries into the reverse hash table.
        !           731:                 */
        !           732: 
        !           733:                for (i = 0; i < osize; i++) {
        !           734:                        ipc_entry_t entry = &table[i];
        !           735: 
        !           736:                        if (IE_BITS_TYPE(entry->ie_bits) ==
        !           737:                                                MACH_PORT_TYPE_SEND)
        !           738:                                ipc_hash_local_insert(space, entry->ie_object,
        !           739:                                                      i, entry);
        !           740:                }
        !           741: 
        !           742:                /*
        !           743:                 *      If there are entries in the splay tree,
        !           744:                 *      then we have work to do:
        !           745:                 *              1) transfer entries to the table
        !           746:                 *              2) update is_tree_small
        !           747:                 */
        !           748: 
        !           749:                if (space->is_tree_total > 0) {
        !           750:                        mach_port_index_t index;
        !           751:                        boolean_t delete;
        !           752:                        struct ipc_splay_tree ignore;
        !           753:                        struct ipc_splay_tree move;
        !           754:                        struct ipc_splay_tree small;
        !           755:                        ipc_entry_num_t nosmall;
        !           756:                        ipc_tree_entry_t tentry;
        !           757: 
        !           758:                        /*
        !           759:                         *      The splay tree divides into four regions,
        !           760:                         *      based on the index of the entries:
        !           761:                         *              1) 0 <= index < osize
        !           762:                         *              2) osize <= index < size
        !           763:                         *              3) size <= index < nsize
        !           764:                         *              4) nsize <= index
        !           765:                         *
        !           766:                         *      Entries in the first part are ignored.
        !           767:                         *      Entries in the second part, that don't
        !           768:                         *      collide, are moved into the table.
        !           769:                         *      Entries in the third part, that don't
        !           770:                         *      collide, are counted for is_tree_small.
        !           771:                         *      Entries in the fourth part are ignored.
        !           772:                         */
        !           773: 
        !           774:                        ipc_splay_tree_split(&space->is_tree,
        !           775:                                             MACH_PORT_MAKE(nsize, 0),
        !           776:                                             &small);
        !           777:                        ipc_splay_tree_split(&small,
        !           778:                                             MACH_PORT_MAKE(size, 0),
        !           779:                                             &move);
        !           780:                        ipc_splay_tree_split(&move,
        !           781:                                             MACH_PORT_MAKE(osize, 0),
        !           782:                                             &ignore);
        !           783: 
        !           784:                        /* move entries into the table */
        !           785: 
        !           786:                        for (tentry = ipc_splay_traverse_start(&move);
        !           787:                             tentry != ITE_NULL;
        !           788:                             tentry = ipc_splay_traverse_next(&move, delete)) {
        !           789:                                mach_port_t name;
        !           790:                                mach_port_gen_t gen;
        !           791:                                mach_port_type_t type;
        !           792:                                ipc_entry_bits_t bits;
        !           793:                                ipc_object_t obj;
        !           794:                                ipc_entry_t entry;
        !           795: 
        !           796:                                name = tentry->ite_name;
        !           797:                                gen = MACH_PORT_GEN(name);
        !           798:                                index = MACH_PORT_INDEX(name);
        !           799: 
        !           800:                                assert(tentry->ite_space == space);
        !           801:                                assert((osize <= index) && (index < size));
        !           802: 
        !           803:                                entry = &table[index];
        !           804: 
        !           805:                                /* collision with previously moved entry? */
        !           806: 
        !           807:                                bits = entry->ie_bits;
        !           808:                                if (bits != 0) {
        !           809:                                        assert(IE_BITS_TYPE(bits));
        !           810:                                        assert(IE_BITS_GEN(bits) != gen);
        !           811: 
        !           812:                                        entry->ie_bits =
        !           813:                                                bits | IE_BITS_COLLISION;
        !           814:                                        delete = FALSE;
        !           815:                                        continue;
        !           816:                                }
        !           817: 
        !           818:                                bits = tentry->ite_bits;
        !           819:                                type = IE_BITS_TYPE(bits);
        !           820:                                assert(type != MACH_PORT_TYPE_NONE);
        !           821: 
        !           822:                                entry->ie_bits = bits | gen;
        !           823:                                entry->ie_object = obj = tentry->ite_object;
        !           824:                                entry->ie_request = tentry->ite_request;
        !           825: 
        !           826:                                if (type == MACH_PORT_TYPE_SEND) {
        !           827:                                        ipc_hash_global_delete(space, obj,
        !           828:                                                               name, tentry);
        !           829:                                        ipc_hash_local_insert(space, obj,
        !           830:                                                              index, entry);
        !           831:                                }
        !           832: 
        !           833:                                space->is_tree_total--;
        !           834:                                delete = TRUE;
        !           835:                        }
        !           836:                        ipc_splay_traverse_finish(&move);
        !           837: 
        !           838:                        /* count entries for is_tree_small */
        !           839: 
        !           840:                        nosmall = 0; index = 0;
        !           841:                        for (tentry = ipc_splay_traverse_start(&small);
        !           842:                             tentry != ITE_NULL;
        !           843:                             tentry = ipc_splay_traverse_next(&small, FALSE)) {
        !           844:                                mach_port_index_t nindex;
        !           845: 
        !           846:                                nindex = MACH_PORT_INDEX(tentry->ite_name);
        !           847: 
        !           848:                                if (nindex != index) {
        !           849:                                        nosmall++;
        !           850:                                        index = nindex;
        !           851:                                }
        !           852:                        }
        !           853:                        ipc_splay_traverse_finish(&small);
        !           854: 
        !           855:                        assert(nosmall <= (nsize - size));
        !           856:                        assert(nosmall <= space->is_tree_total);
        !           857:                        space->is_tree_small = nosmall;
        !           858: 
        !           859:                        /* put the splay tree back together */
        !           860: 
        !           861:                        ipc_splay_tree_join(&space->is_tree, &small);
        !           862:                        ipc_splay_tree_join(&space->is_tree, &move);
        !           863:                        ipc_splay_tree_join(&space->is_tree, &ignore);
        !           864:                }
        !           865: 
        !           866:                /*
        !           867:                 *      Add entries in the new part which still aren't used
        !           868:                 *      to the free list.  Add them in reverse order,
        !           869:                 *      and set the generation number to -1, so that
        !           870:                 *      early allocations produce "natural" names.
        !           871:                 */
        !           872: 
        !           873:                free_index = table[0].ie_next;
        !           874:                for (i = size-1; i >= osize; --i) {
        !           875:                        ipc_entry_t entry = &table[i];
        !           876: 
        !           877:                        if (entry->ie_bits == 0) {
        !           878:                                entry->ie_bits = IE_BITS_GEN_MASK;
        !           879:                                entry->ie_next = free_index;
        !           880:                                free_index = i;
        !           881:                        }
        !           882:                }
        !           883:                table[0].ie_next = free_index;
        !           884: 
        !           885:                /*
        !           886:                 *      Now we need to free the old table.
        !           887:                 *      If the space dies or grows while unlocked,
        !           888:                 *      then we can quit here.
        !           889:                 */
        !           890: 
        !           891:                is_write_unlock(space);
        !           892:                thread_wakeup((event_t) space);
        !           893:                it_entries_free(oits, otable);
        !           894:                is_write_lock(space);
        !           895:                if (!space->is_active || (space->is_table_next != nits))
        !           896:                        return KERN_SUCCESS;
        !           897: 
        !           898:                /*
        !           899:                 *      We might have moved enough entries from
        !           900:                 *      the splay tree into the table that
        !           901:                 *      the table can be profitably grown again.
        !           902:                 *
        !           903:                 *      Note that if size == nsize, then
        !           904:                 *      space->is_tree_small == 0.
        !           905:                 */
        !           906:        } while ((space->is_tree_small > 0) &&
        !           907:                 (((nsize - size) * sizeof(struct ipc_entry)) <
        !           908:                  (space->is_tree_small * sizeof(struct ipc_tree_entry))));
        !           909: 
        !           910:        return KERN_SUCCESS;
        !           911: }

unix.superglobalmegacorp.com

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