Annotation of OSKit-Mach/ipc/ipc_entry.c, revision 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.