Annotation of OSKit-Mach/ipc/ipc_entry.c, revision 1.1.1.1

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