Annotation of Gnu-Mach/ipc/ipc_entry.c, revision 1.1.1.4

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