Annotation of kernel/ipc/ipc_entry.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
                      7:  * Reserved.  This file contains Original Code and/or Modifications of
                      8:  * Original Code as defined in and that are subject to the Apple Public
                      9:  * Source License Version 1.1 (the "License").  You may not use this file
                     10:  * except in compliance with the License.  Please obtain a copy of the
                     11:  * License at http://www.apple.com/publicsource and read it before using
                     12:  * this file.
                     13:  * 
                     14:  * The Original Code and all software distributed under the License are
                     15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     19:  * License for the specific language governing rights and limitations
                     20:  * under the License.
                     21:  * 
                     22:  * @APPLE_LICENSE_HEADER_END@
                     23:  */
                     24: 
                     25: /*
                     26:  * 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.