Annotation of XNU/osfmk/ipc/ipc_entry.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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