Annotation of XNU/osfmk/ipc/ipc_port.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_FREE_COPYRIGHT@
        !            24:  */
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
        !            28:  * All Rights Reserved.
        !            29:  * 
        !            30:  * Permission to use, copy, modify and distribute this software and its
        !            31:  * documentation is hereby granted, provided that both the copyright
        !            32:  * notice and this permission notice appear in all copies of the
        !            33:  * software, derivative works or modified versions, and any portions
        !            34:  * thereof, and that both notices appear in supporting documentation.
        !            35:  * 
        !            36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            39:  * 
        !            40:  * Carnegie Mellon requests users of this software to return to
        !            41:  * 
        !            42:  *  Software Distribution Coordinator  or  [email protected]
        !            43:  *  School of Computer Science
        !            44:  *  Carnegie Mellon University
        !            45:  *  Pittsburgh PA 15213-3890
        !            46:  * 
        !            47:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            48:  * the rights to redistribute these changes.
        !            49:  */
        !            50: /*
        !            51:  */
        !            52: /*
        !            53:  *     File:   ipc/ipc_port.c
        !            54:  *     Author: Rich Draves
        !            55:  *     Date:   1989
        !            56:  *
        !            57:  *     Functions to manipulate IPC ports.
        !            58:  */
        !            59: 
        !            60: #include <dipc.h>
        !            61: #include <norma_vm.h>
        !            62: #include <mach_kdb.h>
        !            63: #include <zone_debug.h>
        !            64: #include <mach_assert.h>
        !            65: 
        !            66: #include <mach/port.h>
        !            67: #include <mach/kern_return.h>
        !            68: #include <kern/lock.h>
        !            69: #include <kern/ipc_kobject.h>
        !            70: #include <kern/ipc_subsystem.h>
        !            71: #include <kern/thread.h>
        !            72: #include <kern/thread_pool.h>
        !            73: #include <kern/misc_protos.h>
        !            74: #include <kern/wait_queue.h>
        !            75: #include <ipc/ipc_entry.h>
        !            76: #include <ipc/ipc_space.h>
        !            77: #include <ipc/ipc_object.h>
        !            78: #include <ipc/ipc_port.h>
        !            79: #include <ipc/ipc_pset.h>
        !            80: #include <ipc/ipc_mqueue.h>
        !            81: #include <ipc/ipc_notify.h>
        !            82: #include <ipc/ipc_print.h>
        !            83: #include <ipc/ipc_table.h>
        !            84: 
        !            85: #if    MACH_KDB
        !            86: #include <machine/db_machdep.h>
        !            87: #include <ddb/db_command.h>
        !            88: #include <ddb/db_expr.h>
        !            89: #endif /* MACH_KDB */
        !            90: 
        !            91: #include <string.h>
        !            92: 
        !            93: decl_mutex_data(,      ipc_port_multiple_lock_data)
        !            94: decl_mutex_data(,      ipc_port_timestamp_lock_data)
        !            95: ipc_port_timestamp_t   ipc_port_timestamp_data;
        !            96: 
        !            97: #if    MACH_ASSERT
        !            98: void   ipc_port_init_debug(
        !            99:                ipc_port_t      port);
        !           100: #endif /* MACH_ASSERT */
        !           101: 
        !           102: #if    MACH_KDB && ZONE_DEBUG
        !           103: /* Forwards */
        !           104: void   print_type_ports(unsigned, unsigned);
        !           105: void   print_ports(void);
        !           106: #endif /* MACH_KDB && ZONE_DEBUG */
        !           107: 
        !           108: /*
        !           109:  *     Routine:        ipc_port_timestamp
        !           110:  *     Purpose:
        !           111:  *             Retrieve a timestamp value.
        !           112:  */
        !           113: 
        !           114: ipc_port_timestamp_t
        !           115: ipc_port_timestamp(void)
        !           116: {
        !           117:        ipc_port_timestamp_t timestamp;
        !           118: 
        !           119:        ipc_port_timestamp_lock();
        !           120:        timestamp = ipc_port_timestamp_data++;
        !           121:        ipc_port_timestamp_unlock();
        !           122: 
        !           123:        return timestamp;
        !           124: }
        !           125: 
        !           126: /*
        !           127:  *     Routine:        ipc_port_dnrequest
        !           128:  *     Purpose:
        !           129:  *             Try to allocate a dead-name request slot.
        !           130:  *             If successful, returns the request index.
        !           131:  *             Otherwise returns zero.
        !           132:  *     Conditions:
        !           133:  *             The port is locked and active.
        !           134:  *     Returns:
        !           135:  *             KERN_SUCCESS            A request index was found.
        !           136:  *             KERN_NO_SPACE           No index allocated.
        !           137:  */
        !           138: 
        !           139: kern_return_t
        !           140: ipc_port_dnrequest(
        !           141:        ipc_port_t                      port,
        !           142:        mach_port_name_t                name,
        !           143:        ipc_port_t                      soright,
        !           144:        ipc_port_request_index_t        *indexp)
        !           145: {
        !           146:        ipc_port_request_t ipr, table;
        !           147:        ipc_port_request_index_t index;
        !           148: 
        !           149:        assert(ip_active(port));
        !           150:        assert(name != MACH_PORT_NULL);
        !           151:        assert(soright != IP_NULL);
        !           152: 
        !           153:        table = port->ip_dnrequests;
        !           154:        if (table == IPR_NULL)
        !           155:                return KERN_NO_SPACE;
        !           156: 
        !           157:        index = table->ipr_next;
        !           158:        if (index == 0)
        !           159:                return KERN_NO_SPACE;
        !           160: 
        !           161:        ipr = &table[index];
        !           162:        assert(ipr->ipr_name == MACH_PORT_NULL);
        !           163: 
        !           164:        table->ipr_next = ipr->ipr_next;
        !           165:        ipr->ipr_name = name;
        !           166:        ipr->ipr_soright = soright;
        !           167: 
        !           168:        *indexp = index;
        !           169:        return KERN_SUCCESS;
        !           170: }
        !           171: 
        !           172: /*
        !           173:  *     Routine:        ipc_port_dngrow
        !           174:  *     Purpose:
        !           175:  *             Grow a port's table of dead-name requests.
        !           176:  *     Conditions:
        !           177:  *             The port must be locked and active.
        !           178:  *             Nothing else locked; will allocate memory.
        !           179:  *             Upon return the port is unlocked.
        !           180:  *     Returns:
        !           181:  *             KERN_SUCCESS            Grew the table.
        !           182:  *             KERN_SUCCESS            Somebody else grew the table.
        !           183:  *             KERN_SUCCESS            The port died.
        !           184:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate new table.
        !           185:  *             KERN_NO_SPACE           Couldn't grow to desired size
        !           186:  */
        !           187: 
        !           188: kern_return_t
        !           189: ipc_port_dngrow(
        !           190:        ipc_port_t      port,
        !           191:        int             target_size)
        !           192: {
        !           193:        ipc_table_size_t its;
        !           194:        ipc_port_request_t otable, ntable;
        !           195: 
        !           196:        assert(ip_active(port));
        !           197: 
        !           198:        otable = port->ip_dnrequests;
        !           199:        if (otable == IPR_NULL)
        !           200:                its = &ipc_table_dnrequests[0];
        !           201:        else
        !           202:                its = otable->ipr_size + 1;
        !           203: 
        !           204:        if (target_size != ITS_SIZE_NONE) {
        !           205:                if ((otable != IPR_NULL) &&
        !           206:                    (target_size <= otable->ipr_size->its_size)) {
        !           207:                        ip_unlock(port);
        !           208:                        return KERN_SUCCESS;
        !           209:                }
        !           210:                while ((its->its_size) && (its->its_size < target_size)) {
        !           211:                        its++;
        !           212:                }
        !           213:                if (its->its_size == 0) {
        !           214:                        ip_unlock(port);
        !           215:                        return KERN_NO_SPACE;
        !           216:                }
        !           217:        }
        !           218: 
        !           219:        ip_reference(port);
        !           220:        ip_unlock(port);
        !           221: 
        !           222:        if ((its->its_size == 0) ||
        !           223:            ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
        !           224:                ipc_port_release(port);
        !           225:                return KERN_RESOURCE_SHORTAGE;
        !           226:        }
        !           227: 
        !           228:        ip_lock(port);
        !           229:        ip_release(port);
        !           230: 
        !           231:        /*
        !           232:         *      Check that port is still active and that nobody else
        !           233:         *      has slipped in and grown the table on us.  Note that
        !           234:         *      just checking port->ip_dnrequests == otable isn't
        !           235:         *      sufficient; must check ipr_size.
        !           236:         */
        !           237: 
        !           238:        if (ip_active(port) &&
        !           239:            (port->ip_dnrequests == otable) &&
        !           240:            ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
        !           241:                ipc_table_size_t oits;
        !           242:                ipc_table_elems_t osize, nsize;
        !           243:                ipc_port_request_index_t free, i;
        !           244: 
        !           245:                /* copy old table to new table */
        !           246: 
        !           247:                if (otable != IPR_NULL) {
        !           248:                        oits = otable->ipr_size;
        !           249:                        osize = oits->its_size;
        !           250:                        free = otable->ipr_next;
        !           251: 
        !           252:                        (void) memcpy((void *)(ntable + 1),
        !           253:                              (const void *)(otable + 1),
        !           254:                              (osize - 1) * sizeof(struct ipc_port_request));
        !           255:                } else {
        !           256:                        osize = 1;
        !           257:                        free = 0;
        !           258:                }
        !           259: 
        !           260:                nsize = its->its_size;
        !           261:                assert(nsize > osize);
        !           262: 
        !           263:                /* add new elements to the new table's free list */
        !           264: 
        !           265:                for (i = osize; i < nsize; i++) {
        !           266:                        ipc_port_request_t ipr = &ntable[i];
        !           267: 
        !           268:                        ipr->ipr_name = MACH_PORT_NULL;
        !           269:                        ipr->ipr_next = free;
        !           270:                        free = i;
        !           271:                }
        !           272: 
        !           273:                ntable->ipr_next = free;
        !           274:                ntable->ipr_size = its;
        !           275:                port->ip_dnrequests = ntable;
        !           276:                ip_unlock(port);
        !           277: 
        !           278:                if (otable != IPR_NULL) {
        !           279:                        it_dnrequests_free(oits, otable);
        !           280:                }
        !           281:        } else {
        !           282:                ip_check_unlock(port);
        !           283:                it_dnrequests_free(its, ntable);
        !           284:        }
        !           285: 
        !           286:        return KERN_SUCCESS;
        !           287: }
        !           288:  
        !           289: /*
        !           290:  *     Routine:        ipc_port_dncancel
        !           291:  *     Purpose:
        !           292:  *             Cancel a dead-name request and return the send-once right.
        !           293:  *     Conditions:
        !           294:  *             The port must locked and active.
        !           295:  */
        !           296: 
        !           297: ipc_port_t
        !           298: ipc_port_dncancel(
        !           299:        ipc_port_t                      port,
        !           300:        mach_port_name_t                name,
        !           301:        ipc_port_request_index_t        index)
        !           302: {
        !           303:        ipc_port_request_t ipr, table;
        !           304:        ipc_port_t dnrequest;
        !           305: 
        !           306:        assert(ip_active(port));
        !           307:        assert(name != MACH_PORT_NULL);
        !           308:        assert(index != 0);
        !           309: 
        !           310:        table = port->ip_dnrequests;
        !           311:        assert(table != IPR_NULL);
        !           312: 
        !           313:        ipr = &table[index];
        !           314:        dnrequest = ipr->ipr_soright;
        !           315:        assert(ipr->ipr_name == name);
        !           316: 
        !           317:        /* return ipr to the free list inside the table */
        !           318: 
        !           319:        ipr->ipr_name = MACH_PORT_NULL;
        !           320:        ipr->ipr_next = table->ipr_next;
        !           321:        table->ipr_next = index;
        !           322: 
        !           323:        return dnrequest;
        !           324: }
        !           325: 
        !           326: /*
        !           327:  *     Routine:        ipc_port_pdrequest
        !           328:  *     Purpose:
        !           329:  *             Make a port-deleted request, returning the
        !           330:  *             previously registered send-once right.
        !           331:  *             Just cancels the previous request if notify is IP_NULL.
        !           332:  *     Conditions:
        !           333:  *             The port is locked and active.  It is unlocked.
        !           334:  *             Consumes a ref for notify (if non-null), and
        !           335:  *             returns previous with a ref (if non-null).
        !           336:  */
        !           337: 
        !           338: void
        !           339: ipc_port_pdrequest(
        !           340:        ipc_port_t      port,
        !           341:        ipc_port_t      notify,
        !           342:        ipc_port_t      *previousp)
        !           343: {
        !           344:        ipc_port_t previous;
        !           345: 
        !           346:        assert(ip_active(port));
        !           347: 
        !           348:        previous = port->ip_pdrequest;
        !           349:        port->ip_pdrequest = notify;
        !           350:        ip_unlock(port);
        !           351: 
        !           352:        *previousp = previous;
        !           353: }
        !           354: 
        !           355: /*
        !           356:  *     Routine:        ipc_port_nsrequest
        !           357:  *     Purpose:
        !           358:  *             Make a no-senders request, returning the
        !           359:  *             previously registered send-once right.
        !           360:  *             Just cancels the previous request if notify is IP_NULL.
        !           361:  *     Conditions:
        !           362:  *             The port is locked and active.  It is unlocked.
        !           363:  *             Consumes a ref for notify (if non-null), and
        !           364:  *             returns previous with a ref (if non-null).
        !           365:  */
        !           366: 
        !           367: void
        !           368: ipc_port_nsrequest(
        !           369:        ipc_port_t              port,
        !           370:        mach_port_mscount_t     sync,
        !           371:        ipc_port_t              notify,
        !           372:        ipc_port_t              *previousp)
        !           373: {
        !           374:        ipc_port_t previous;
        !           375:        mach_port_mscount_t mscount;
        !           376: 
        !           377:        assert(ip_active(port));
        !           378: 
        !           379:        previous = port->ip_nsrequest;
        !           380:        mscount = port->ip_mscount;
        !           381: 
        !           382:        if ((port->ip_srights == 0) && (sync <= mscount) &&
        !           383:            (notify != IP_NULL)) {
        !           384:                port->ip_nsrequest = IP_NULL;
        !           385:                ip_unlock(port);
        !           386:                ipc_notify_no_senders(notify, mscount);
        !           387:        } else {
        !           388:                port->ip_nsrequest = notify;
        !           389:                ip_unlock(port);
        !           390:        }
        !           391: 
        !           392:        *previousp = previous;
        !           393: }
        !           394: 
        !           395: 
        !           396: /*
        !           397:  *     Routine:        ipc_port_clear_receiver
        !           398:  *     Purpose:
        !           399:  *             Prepares a receive right for transmission/destruction.
        !           400:  *     Conditions:
        !           401:  *             The port is locked and active.
        !           402:  */
        !           403: 
        !           404: void
        !           405: ipc_port_clear_receiver(
        !           406:        ipc_port_t      port)
        !           407: {
        !           408:        assert(ip_active(port));
        !           409: 
        !           410:        /*
        !           411:         * pull ourselves from any sets.
        !           412:         */
        !           413:        if (port->ip_pset_count != 0) {
        !           414:                ipc_pset_remove_all(port);
        !           415:                port->ip_pset_count = 0;
        !           416:        }
        !           417: 
        !           418:        /*
        !           419:         * Send anyone waiting on the port's queue directly away.
        !           420:         * Also clear the mscount and seqno.
        !           421:         */
        !           422:        imq_lock(&port->ip_messages);
        !           423:        ipc_mqueue_changed(&port->ip_messages);
        !           424:        ipc_port_set_mscount(port, 0);
        !           425:        port->ip_messages.imq_seqno = 0;
        !           426:        imq_unlock(&port->ip_messages);
        !           427: }
        !           428: 
        !           429: /*
        !           430:  *     Routine:        ipc_port_init
        !           431:  *     Purpose:
        !           432:  *             Initializes a newly-allocated port.
        !           433:  *             Doesn't touch the ip_object fields.
        !           434:  */
        !           435: 
        !           436: void
        !           437: ipc_port_init(
        !           438:        ipc_port_t              port,
        !           439:        ipc_space_t             space,
        !           440:        mach_port_name_t        name)
        !           441: {
        !           442:        /* port->ip_kobject doesn't have to be initialized */
        !           443: 
        !           444:        port->ip_receiver = space;
        !           445:        port->ip_receiver_name = name;
        !           446: 
        !           447:        port->ip_mscount = 0;
        !           448:        port->ip_srights = 0;
        !           449:        port->ip_sorights = 0;
        !           450: 
        !           451:        port->ip_nsrequest = IP_NULL;
        !           452:        port->ip_pdrequest = IP_NULL;
        !           453:        port->ip_dnrequests = IPR_NULL;
        !           454: 
        !           455:        port->ip_pset_count = 0;
        !           456: 
        !           457:        thread_pool_init(&port->ip_thread_pool);
        !           458: 
        !           459:        port->ip_subsystem = RPC_SUBSYSTEM_NULL;
        !           460:        
        !           461:        port->ip_flags = 0;
        !           462: 
        !           463:        /*
        !           464:         *      Turn no more senders detection on
        !           465:         *      for all ports.  Eventually, this
        !           466:         *      default will go away, and nms
        !           467:         *      detection will be enabled depending
        !           468:         *      on how the port is allocated. XXX
        !           469:         */
        !           470:        IP_SET_NMS(port);
        !           471: 
        !           472: #if    MACH_ASSERT
        !           473:        ipc_port_init_debug(port);
        !           474: #endif /* MACH_ASSERT */
        !           475: 
        !           476:        ipc_mqueue_init(&port->ip_messages, FALSE /* set */);
        !           477: }
        !           478: 
        !           479: /*
        !           480:  *     Routine:        ipc_port_alloc
        !           481:  *     Purpose:
        !           482:  *             Allocate a port.
        !           483:  *     Conditions:
        !           484:  *             Nothing locked.  If successful, the port is returned
        !           485:  *             locked.  (The caller doesn't have a reference.)
        !           486:  *     Returns:
        !           487:  *             KERN_SUCCESS            The port is allocated.
        !           488:  *             KERN_INVALID_TASK       The space is dead.
        !           489:  *             KERN_NO_SPACE           No room for an entry in the space.
        !           490:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
        !           491:  */
        !           492: 
        !           493: kern_return_t
        !           494: ipc_port_alloc(
        !           495:        ipc_space_t             space,
        !           496:        mach_port_name_t        *namep,
        !           497:        ipc_port_t              *portp)
        !           498: {
        !           499:        ipc_port_t port;
        !           500:        mach_port_name_t name;
        !           501:        kern_return_t kr;
        !           502: 
        !           503:        kr = ipc_object_alloc(space, IOT_PORT,
        !           504:                              MACH_PORT_TYPE_RECEIVE, 0,
        !           505:                              &name, (ipc_object_t *) &port);
        !           506:        if (kr != KERN_SUCCESS)
        !           507:                return kr;
        !           508: 
        !           509:        /* port is locked */
        !           510: 
        !           511:        ipc_port_init(port, space, name);
        !           512: 
        !           513:        *namep = name;
        !           514:        *portp = port;
        !           515: 
        !           516:        return KERN_SUCCESS;
        !           517: }
        !           518: 
        !           519: /*
        !           520:  *     Routine:        ipc_port_alloc_name
        !           521:  *     Purpose:
        !           522:  *             Allocate a port, with a specific name.
        !           523:  *     Conditions:
        !           524:  *             Nothing locked.  If successful, the port is returned
        !           525:  *             locked.  (The caller doesn't have a reference.)
        !           526:  *     Returns:
        !           527:  *             KERN_SUCCESS            The port is allocated.
        !           528:  *             KERN_INVALID_TASK       The space is dead.
        !           529:  *             KERN_NAME_EXISTS        The name already denotes a right.
        !           530:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
        !           531:  */
        !           532: 
        !           533: kern_return_t
        !           534: ipc_port_alloc_name(
        !           535:        ipc_space_t             space,
        !           536:        mach_port_name_t        name,
        !           537:        ipc_port_t              *portp)
        !           538: {
        !           539:        ipc_port_t port;
        !           540:        kern_return_t kr;
        !           541: 
        !           542:        kr = ipc_object_alloc_name(space, IOT_PORT,
        !           543:                                   MACH_PORT_TYPE_RECEIVE, 0,
        !           544:                                   name, (ipc_object_t *) &port);
        !           545:        if (kr != KERN_SUCCESS)
        !           546:                return kr;
        !           547: 
        !           548:        /* port is locked */
        !           549: 
        !           550:        ipc_port_init(port, space, name);
        !           551: 
        !           552:        *portp = port;
        !           553: 
        !           554:        return KERN_SUCCESS;
        !           555: }
        !           556: 
        !           557: /*
        !           558:  * Generate dead name notifications.  Called from ipc_port_destroy.
        !           559:  * Port is unlocked but still has reference(s);
        !           560:  * dnrequests was taken from port while the port
        !           561:  * was locked but the port now has port->ip_dnrequests set to IPR_NULL.
        !           562:  */
        !           563: void
        !           564: ipc_port_dnnotify(
        !           565:        ipc_port_t              port,
        !           566:        ipc_port_request_t      dnrequests)
        !           567: {
        !           568:        ipc_table_size_t        its = dnrequests->ipr_size;
        !           569:        ipc_table_elems_t       size = its->its_size;
        !           570:        ipc_port_request_index_t index;
        !           571: 
        !           572:        for (index = 1; index < size; index++) {
        !           573:                ipc_port_request_t      ipr = &dnrequests[index];
        !           574:                mach_port_name_t                name = ipr->ipr_name;
        !           575:                ipc_port_t              soright;
        !           576: 
        !           577:                if (name == MACH_PORT_NULL)
        !           578:                        continue;
        !           579: 
        !           580:                soright = ipr->ipr_soright;
        !           581:                assert(soright != IP_NULL);
        !           582: 
        !           583:                ipc_notify_dead_name(soright, name);
        !           584:        }
        !           585: 
        !           586:        it_dnrequests_free(its, dnrequests);
        !           587: }
        !           588: 
        !           589: /*
        !           590:  *     Routine:        ipc_port_destroy
        !           591:  *     Purpose:
        !           592:  *             Destroys a port.  Cleans up queued messages.
        !           593:  *
        !           594:  *             If the port has a backup, it doesn't get destroyed,
        !           595:  *             but is sent in a port-destroyed notification to the backup.
        !           596:  *     Conditions:
        !           597:  *             The port is locked and alive; nothing else locked.
        !           598:  *             The caller has a reference, which is consumed.
        !           599:  *             Afterwards, the port is unlocked and dead.
        !           600:  */
        !           601: 
        !           602: void
        !           603: ipc_port_destroy(
        !           604:        ipc_port_t      port)
        !           605: {
        !           606:        ipc_port_t pdrequest, nsrequest;
        !           607:        ipc_mqueue_t mqueue;
        !           608:        ipc_kmsg_queue_t kmqueue;
        !           609:        ipc_kmsg_t kmsg;
        !           610:        ipc_port_request_t dnrequests;
        !           611:        thread_pool_t thread_pool;
        !           612: 
        !           613:        assert(ip_active(port));
        !           614:        /* port->ip_receiver_name is garbage */
        !           615:        /* port->ip_receiver/port->ip_destination is garbage */
        !           616:        assert(port->ip_pset_count == 0);
        !           617:        assert(port->ip_mscount == 0);
        !           618: 
        !           619:        /* first check for a backup port */
        !           620: 
        !           621:        pdrequest = port->ip_pdrequest;
        !           622:        if (pdrequest != IP_NULL) {
        !           623:                /* we assume the ref for pdrequest */
        !           624:                port->ip_pdrequest = IP_NULL;
        !           625: 
        !           626:                /* make port be in limbo */
        !           627:                port->ip_receiver_name = MACH_PORT_NULL;
        !           628:                port->ip_destination = IP_NULL;
        !           629:                ip_unlock(port);
        !           630: 
        !           631:                if (!ipc_port_check_circularity(port, pdrequest)) {
        !           632:                        /* consumes our refs for port and pdrequest */
        !           633:                        ipc_notify_port_destroyed(pdrequest, port);
        !           634:                        return;
        !           635:                } else {
        !           636:                        /* consume pdrequest and destroy port */
        !           637:                        ipc_port_release_sonce(pdrequest);
        !           638:                }
        !           639: 
        !           640:                ip_lock(port);
        !           641:                assert(ip_active(port));
        !           642:                assert(port->ip_pset_count == 0);
        !           643:                assert(port->ip_mscount == 0);
        !           644:                assert(port->ip_pdrequest == IP_NULL);
        !           645:                assert(port->ip_receiver_name == MACH_PORT_NULL);
        !           646:                assert(port->ip_destination == IP_NULL);
        !           647: 
        !           648:                /* fall through and destroy the port */
        !           649:        }
        !           650: 
        !           651:        /* once port is dead, we don't need to keep it locked */
        !           652: 
        !           653:        port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
        !           654:        port->ip_timestamp = ipc_port_timestamp();
        !           655: 
        !           656:        /* save for later */
        !           657:        dnrequests = port->ip_dnrequests;
        !           658:        port->ip_dnrequests = IPR_NULL;
        !           659:        ip_unlock(port);
        !           660: 
        !           661:        /* wakeup any threads waiting on this pool port for an activation */
        !           662:        if ((thread_pool = &port->ip_thread_pool) != THREAD_POOL_NULL)
        !           663:                thread_pool_wakeup(thread_pool);
        !           664: 
        !           665:        /* throw away no-senders request */
        !           666: 
        !           667:        nsrequest = port->ip_nsrequest;
        !           668:        if (nsrequest != IP_NULL)
        !           669:                ipc_notify_send_once(nsrequest); /* consumes ref */
        !           670: 
        !           671:        /* destroy any queued messages */
        !           672:        mqueue = &port->ip_messages;
        !           673:        ipc_mqueue_destroy(mqueue);
        !           674: 
        !           675:        /* generate dead-name notifications */
        !           676:        if (dnrequests != IPR_NULL) {
        !           677:                ipc_port_dnnotify(port, dnrequests);
        !           678:        }
        !           679: 
        !           680:        ipc_kobject_destroy(port);
        !           681: 
        !           682:        if (port->ip_subsystem != RPC_SUBSYSTEM_NULL) {
        !           683:                subsystem_deallocate((subsystem_t) port->ip_kobject);
        !           684:        }
        !           685: 
        !           686:        /* XXXX Perhaps should verify that ip_thread_pool is empty! */
        !           687: 
        !           688:        ipc_port_release(port); /* consume caller's ref */
        !           689: }
        !           690: 
        !           691: /*
        !           692:  *     Routine:        ipc_port_check_circularity
        !           693:  *     Purpose:
        !           694:  *             Check if queueing "port" in a message for "dest"
        !           695:  *             would create a circular group of ports and messages.
        !           696:  *
        !           697:  *             If no circularity (FALSE returned), then "port"
        !           698:  *             is changed from "in limbo" to "in transit".
        !           699:  *
        !           700:  *             That is, we want to set port->ip_destination == dest,
        !           701:  *             but guaranteeing that this doesn't create a circle
        !           702:  *             port->ip_destination->ip_destination->... == port
        !           703:  *     Conditions:
        !           704:  *             No ports locked.  References held for "port" and "dest".
        !           705:  */
        !           706: 
        !           707: boolean_t
        !           708: ipc_port_check_circularity(
        !           709:        ipc_port_t      port,
        !           710:        ipc_port_t      dest)
        !           711: {
        !           712:        ipc_port_t base;
        !           713: 
        !           714:        assert(port != IP_NULL);
        !           715:        assert(dest != IP_NULL);
        !           716: 
        !           717:        if (port == dest)
        !           718:                return TRUE;
        !           719:        base = dest;
        !           720: 
        !           721:        /*
        !           722:         *      First try a quick check that can run in parallel.
        !           723:         *      No circularity if dest is not in transit.
        !           724:         */
        !           725: 
        !           726:        ip_lock(port);
        !           727:        if (ip_lock_try(dest)) {
        !           728:                if (!ip_active(dest) ||
        !           729:                    (dest->ip_receiver_name != MACH_PORT_NULL) ||
        !           730:                    (dest->ip_destination == IP_NULL))
        !           731:                        goto not_circular;
        !           732: 
        !           733:                /* dest is in transit; further checking necessary */
        !           734: 
        !           735:                ip_unlock(dest);
        !           736:        }
        !           737:        ip_unlock(port);
        !           738: 
        !           739:        ipc_port_multiple_lock(); /* massive serialization */
        !           740: 
        !           741:        /*
        !           742:         *      Search for the end of the chain (a port not in transit),
        !           743:         *      acquiring locks along the way.
        !           744:         */
        !           745: 
        !           746:        for (;;) {
        !           747:                ip_lock(base);
        !           748: 
        !           749:                if (!ip_active(base) ||
        !           750:                    (base->ip_receiver_name != MACH_PORT_NULL) ||
        !           751:                    (base->ip_destination == IP_NULL))
        !           752:                        break;
        !           753: 
        !           754:                base = base->ip_destination;
        !           755:        }
        !           756: 
        !           757:        /* all ports in chain from dest to base, inclusive, are locked */
        !           758: 
        !           759:        if (port == base) {
        !           760:                /* circularity detected! */
        !           761: 
        !           762:                ipc_port_multiple_unlock();
        !           763: 
        !           764:                /* port (== base) is in limbo */
        !           765: 
        !           766:                assert(ip_active(port));
        !           767:                assert(port->ip_receiver_name == MACH_PORT_NULL);
        !           768:                assert(port->ip_destination == IP_NULL);
        !           769: 
        !           770:                while (dest != IP_NULL) {
        !           771:                        ipc_port_t next;
        !           772: 
        !           773:                        /* dest is in transit or in limbo */
        !           774: 
        !           775:                        assert(ip_active(dest));
        !           776:                        assert(dest->ip_receiver_name == MACH_PORT_NULL);
        !           777: 
        !           778:                        next = dest->ip_destination;
        !           779:                        ip_unlock(dest);
        !           780:                        dest = next;
        !           781:                }
        !           782: 
        !           783:                return TRUE;
        !           784:        }
        !           785: 
        !           786:        /*
        !           787:         *      The guarantee:  lock port while the entire chain is locked.
        !           788:         *      Once port is locked, we can take a reference to dest,
        !           789:         *      add port to the chain, and unlock everything.
        !           790:         */
        !           791: 
        !           792:        ip_lock(port);
        !           793:        ipc_port_multiple_unlock();
        !           794: 
        !           795:     not_circular:
        !           796: 
        !           797:        /* port is in limbo */
        !           798: 
        !           799:        assert(ip_active(port));
        !           800:        assert(port->ip_receiver_name == MACH_PORT_NULL);
        !           801:        assert(port->ip_destination == IP_NULL);
        !           802: 
        !           803:        ip_reference(dest);
        !           804:        port->ip_destination = dest;
        !           805: 
        !           806:        /* now unlock chain */
        !           807: 
        !           808:        while (port != base) {
        !           809:                ipc_port_t next;
        !           810: 
        !           811:                /* port is in transit */
        !           812: 
        !           813:                assert(ip_active(port));
        !           814:                assert(port->ip_receiver_name == MACH_PORT_NULL);
        !           815:                assert(port->ip_destination != IP_NULL);
        !           816: 
        !           817:                next = port->ip_destination;
        !           818:                ip_unlock(port);
        !           819:                port = next;
        !           820:        }
        !           821: 
        !           822:        /* base is not in transit */
        !           823: 
        !           824:        assert(!ip_active(base) ||
        !           825:               (base->ip_receiver_name != MACH_PORT_NULL) ||
        !           826:               (base->ip_destination == IP_NULL));
        !           827:        ip_unlock(base);
        !           828: 
        !           829:        return FALSE;
        !           830: }
        !           831: 
        !           832: /*
        !           833:  *     Routine:        ipc_port_lookup_notify
        !           834:  *     Purpose:
        !           835:  *             Make a send-once notify port from a receive right.
        !           836:  *             Returns IP_NULL if name doesn't denote a receive right.
        !           837:  *     Conditions:
        !           838:  *             The space must be locked (read or write) and active.
        !           839:  *             Being the active space, we can rely on thread server_id
        !           840:  *             context to give us the proper server level sub-order
        !           841:  *             within the space.
        !           842:  */
        !           843: 
        !           844: ipc_port_t
        !           845: ipc_port_lookup_notify(
        !           846:        ipc_space_t             space,
        !           847:        mach_port_name_t        name)
        !           848: {
        !           849:        ipc_port_t port;
        !           850:        ipc_entry_t entry;
        !           851: 
        !           852:        assert(space->is_active);
        !           853: 
        !           854:        entry = ipc_entry_lookup(space, name);
        !           855:        if (entry == IE_NULL)
        !           856:                return IP_NULL;
        !           857:        if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
        !           858:                return IP_NULL;
        !           859: 
        !           860:        port = (ipc_port_t) entry->ie_object;
        !           861:        assert(port != IP_NULL);
        !           862: 
        !           863:        ip_lock(port);
        !           864:        assert(ip_active(port));
        !           865:        assert(port->ip_receiver_name == name);
        !           866:        assert(port->ip_receiver == space);
        !           867: 
        !           868:        ip_reference(port);
        !           869:        port->ip_sorights++;
        !           870:        ip_unlock(port);
        !           871: 
        !           872:        return port;
        !           873: }
        !           874: 
        !           875: /*
        !           876:  *     Routine:        ipc_port_make_send
        !           877:  *     Purpose:
        !           878:  *             Make a naked send right from a receive right.
        !           879:  *     Conditions:
        !           880:  *             The port is not locked but it is active.
        !           881:  */
        !           882: 
        !           883: ipc_port_t
        !           884: ipc_port_make_send(
        !           885:        ipc_port_t      port)
        !           886: {
        !           887:        assert(IP_VALID(port));
        !           888: 
        !           889:        ip_lock(port);
        !           890:        assert(ip_active(port));
        !           891:        port->ip_mscount++;
        !           892:        port->ip_srights++;
        !           893:        ip_reference(port);
        !           894:        ip_unlock(port);
        !           895: 
        !           896:        return port;
        !           897: }
        !           898: 
        !           899: /*
        !           900:  *     Routine:        ipc_port_copy_send
        !           901:  *     Purpose:
        !           902:  *             Make a naked send right from another naked send right.
        !           903:  *                     IP_NULL         -> IP_NULL
        !           904:  *                     IP_DEAD         -> IP_DEAD
        !           905:  *                     dead port       -> IP_DEAD
        !           906:  *                     live port       -> port + ref
        !           907:  *     Conditions:
        !           908:  *             Nothing locked except possibly a space.
        !           909:  */
        !           910: 
        !           911: ipc_port_t
        !           912: ipc_port_copy_send(
        !           913:        ipc_port_t      port)
        !           914: {
        !           915:        ipc_port_t sright;
        !           916: 
        !           917:        if (!IP_VALID(port))
        !           918:                return port;
        !           919: 
        !           920:        ip_lock(port);
        !           921:        if (ip_active(port)) {
        !           922:                assert(port->ip_srights > 0);
        !           923: 
        !           924:                ip_reference(port);
        !           925:                port->ip_srights++;
        !           926:                sright = port;
        !           927:        } else
        !           928:                sright = IP_DEAD;
        !           929:        ip_unlock(port);
        !           930: 
        !           931:        return sright;
        !           932: }
        !           933: 
        !           934: /*
        !           935:  *     Routine:        ipc_port_copyout_send
        !           936:  *     Purpose:
        !           937:  *             Copyout a naked send right (possibly null/dead),
        !           938:  *             or if that fails, destroy the right.
        !           939:  *     Conditions:
        !           940:  *             Nothing locked.
        !           941:  */
        !           942: 
        !           943: mach_port_name_t
        !           944: ipc_port_copyout_send(
        !           945:        ipc_port_t      sright,
        !           946:        ipc_space_t     space)
        !           947: {
        !           948:        mach_port_name_t name;
        !           949: 
        !           950:        if (IP_VALID(sright)) {
        !           951:                kern_return_t kr;
        !           952: 
        !           953:                kr = ipc_object_copyout(space, (ipc_object_t) sright,
        !           954:                                        MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
        !           955:                if (kr != KERN_SUCCESS) {
        !           956:                        ipc_port_release_send(sright);
        !           957: 
        !           958:                        if (kr == KERN_INVALID_CAPABILITY)
        !           959:                                name = MACH_PORT_DEAD;
        !           960:                        else
        !           961:                                name = MACH_PORT_NULL;
        !           962:                }
        !           963:        } else
        !           964:                name = (mach_port_name_t) sright;
        !           965: 
        !           966:        return name;
        !           967: }
        !           968: 
        !           969: /*
        !           970:  *     Routine:        ipc_port_release_send
        !           971:  *     Purpose:
        !           972:  *             Release a (valid) naked send right.
        !           973:  *             Consumes a ref for the port.
        !           974:  *     Conditions:
        !           975:  *             Nothing locked.
        !           976:  */
        !           977: 
        !           978: void
        !           979: ipc_port_release_send(
        !           980:        ipc_port_t      port)
        !           981: {
        !           982:        ipc_port_t nsrequest = IP_NULL;
        !           983:        mach_port_mscount_t mscount;
        !           984: 
        !           985:        assert(IP_VALID(port));
        !           986: 
        !           987:        ip_lock(port);
        !           988:        ip_release(port);
        !           989: 
        !           990:        if (!ip_active(port)) {
        !           991:                ip_check_unlock(port);
        !           992:                return;
        !           993:        }
        !           994: 
        !           995:        assert(port->ip_srights > 0);
        !           996: 
        !           997:        if (--port->ip_srights == 0 &&
        !           998:            port->ip_nsrequest != IP_NULL) {
        !           999:                nsrequest = port->ip_nsrequest;
        !          1000:                port->ip_nsrequest = IP_NULL;
        !          1001:                mscount = port->ip_mscount;
        !          1002:                ip_unlock(port);
        !          1003:                ipc_notify_no_senders(nsrequest, mscount);
        !          1004:                /*
        !          1005:                 * Check that there are no other locks taken, because
        !          1006:                 * [norma_]ipc_notify_no_senders routines may block.
        !          1007:                 */
        !          1008:                check_simple_locks();
        !          1009:        } else
        !          1010:                ip_unlock(port);
        !          1011: }
        !          1012: 
        !          1013: /*
        !          1014:  *     Routine:        ipc_port_make_sonce
        !          1015:  *     Purpose:
        !          1016:  *             Make a naked send-once right from a receive right.
        !          1017:  *     Conditions:
        !          1018:  *             The port is not locked but it is active.
        !          1019:  */
        !          1020: 
        !          1021: ipc_port_t
        !          1022: ipc_port_make_sonce(
        !          1023:        ipc_port_t      port)
        !          1024: {
        !          1025:        assert(IP_VALID(port));
        !          1026: 
        !          1027:        ip_lock(port);
        !          1028:        assert(ip_active(port));
        !          1029:        port->ip_sorights++;
        !          1030:        ip_reference(port);
        !          1031:        ip_unlock(port);
        !          1032: 
        !          1033:        return port;
        !          1034: }
        !          1035: 
        !          1036: /*
        !          1037:  *     Routine:        ipc_port_release_sonce
        !          1038:  *     Purpose:
        !          1039:  *             Release a naked send-once right.
        !          1040:  *             Consumes a ref for the port.
        !          1041:  *
        !          1042:  *             In normal situations, this is never used.
        !          1043:  *             Send-once rights are only consumed when
        !          1044:  *             a message (possibly a send-once notification)
        !          1045:  *             is sent to them.
        !          1046:  *     Conditions:
        !          1047:  *             Nothing locked except possibly a space.
        !          1048:  */
        !          1049: 
        !          1050: void
        !          1051: ipc_port_release_sonce(
        !          1052:        ipc_port_t      port)
        !          1053: {
        !          1054:        assert(IP_VALID(port));
        !          1055: 
        !          1056:        ip_lock(port);
        !          1057: 
        !          1058:        assert(port->ip_sorights > 0);
        !          1059: 
        !          1060:        port->ip_sorights--;
        !          1061: 
        !          1062:        ip_release(port);
        !          1063: 
        !          1064:        if (!ip_active(port)) {
        !          1065:                ip_check_unlock(port);
        !          1066:                return;
        !          1067:        }
        !          1068: 
        !          1069:        ip_unlock(port);
        !          1070: }
        !          1071: 
        !          1072: /*
        !          1073:  *     Routine:        ipc_port_release_receive
        !          1074:  *     Purpose:
        !          1075:  *             Release a naked (in limbo or in transit) receive right.
        !          1076:  *             Consumes a ref for the port; destroys the port.
        !          1077:  *     Conditions:
        !          1078:  *             Nothing locked.
        !          1079:  */
        !          1080: 
        !          1081: void
        !          1082: ipc_port_release_receive(
        !          1083:        ipc_port_t      port)
        !          1084: {
        !          1085:        ipc_port_t dest;
        !          1086: 
        !          1087:        assert(IP_VALID(port));
        !          1088: 
        !          1089:        ip_lock(port);
        !          1090:        assert(ip_active(port));
        !          1091:        assert(port->ip_receiver_name == MACH_PORT_NULL);
        !          1092:        dest = port->ip_destination;
        !          1093: 
        !          1094:        ipc_port_destroy(port); /* consumes ref, unlocks */
        !          1095: 
        !          1096:        if (dest != IP_NULL)
        !          1097:                ipc_port_release(dest);
        !          1098: }
        !          1099: 
        !          1100: /*
        !          1101:  *     Routine:        ipc_port_alloc_special
        !          1102:  *     Purpose:
        !          1103:  *             Allocate a port in a special space.
        !          1104:  *             The new port is returned with one ref.
        !          1105:  *             If unsuccessful, IP_NULL is returned.
        !          1106:  *     Conditions:
        !          1107:  *             Nothing locked.
        !          1108:  */
        !          1109: 
        !          1110: ipc_port_t
        !          1111: ipc_port_alloc_special(
        !          1112:        ipc_space_t     space)
        !          1113: {
        !          1114:        ipc_port_t port;
        !          1115: 
        !          1116:        port = (ipc_port_t) io_alloc(IOT_PORT);
        !          1117:        if (port == IP_NULL)
        !          1118:                return IP_NULL;
        !          1119: 
        !          1120:        bzero((char *)port, sizeof(*port));
        !          1121:        io_lock_init(&port->ip_object);
        !          1122:        port->ip_references = 1;
        !          1123:        port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
        !          1124: 
        !          1125:        ipc_port_init(port, space, 1);
        !          1126: 
        !          1127:        return port;
        !          1128: }
        !          1129: 
        !          1130: /*
        !          1131:  *     Routine:        ipc_port_dealloc_special
        !          1132:  *     Purpose:
        !          1133:  *             Deallocate a port in a special space.
        !          1134:  *             Consumes one ref for the port.
        !          1135:  *     Conditions:
        !          1136:  *             Nothing locked.
        !          1137:  */
        !          1138: 
        !          1139: void
        !          1140: ipc_port_dealloc_special(
        !          1141:        ipc_port_t      port,
        !          1142:        ipc_space_t     space)
        !          1143: {
        !          1144:        ip_lock(port);
        !          1145:        assert(ip_active(port));
        !          1146:        assert(port->ip_receiver_name != MACH_PORT_NULL);
        !          1147:        assert(port->ip_receiver == space);
        !          1148: 
        !          1149:        /*
        !          1150:         *      We clear ip_receiver_name and ip_receiver to simplify
        !          1151:         *      the ipc_space_kernel check in ipc_mqueue_send.
        !          1152:         */
        !          1153: 
        !          1154:        port->ip_receiver_name = MACH_PORT_NULL;
        !          1155:        port->ip_receiver = IS_NULL;
        !          1156: 
        !          1157:        /* relevant part of ipc_port_clear_receiver */
        !          1158:        ipc_port_set_mscount(port, 0);
        !          1159:        port->ip_messages.imq_seqno = 0;
        !          1160: 
        !          1161:        ipc_port_destroy(port);
        !          1162: }
        !          1163: 
        !          1164: 
        !          1165: #if    MACH_ASSERT
        !          1166: /*
        !          1167:  *     Keep a list of all allocated ports.
        !          1168:  *     Allocation is intercepted via ipc_port_init;
        !          1169:  *     deallocation is intercepted via io_free.
        !          1170:  */
        !          1171: queue_head_t   port_alloc_queue;
        !          1172: decl_mutex_data(,port_alloc_queue_lock)
        !          1173: 
        !          1174: unsigned long  port_count = 0;
        !          1175: unsigned long  port_count_warning = 20000;
        !          1176: unsigned long  port_timestamp = 0;
        !          1177: 
        !          1178: void           db_port_stack_trace(
        !          1179:                        ipc_port_t      port);
        !          1180: void           db_ref(
        !          1181:                        int             refs);
        !          1182: int            db_port_walk(
        !          1183:                        unsigned int    verbose,
        !          1184:                        unsigned int    display,
        !          1185:                        unsigned int    ref_search,
        !          1186:                        unsigned int    ref_target);
        !          1187: 
        !          1188: /*
        !          1189:  *     Initialize global state needed for run-time
        !          1190:  *     port debugging.
        !          1191:  */
        !          1192: void
        !          1193: ipc_port_debug_init(void)
        !          1194: {
        !          1195:        queue_init(&port_alloc_queue);
        !          1196:        mutex_init(&port_alloc_queue_lock, ETAP_IPC_PORT_ALLOCQ);
        !          1197: }
        !          1198: 
        !          1199: 
        !          1200: /*
        !          1201:  *     Initialize all of the debugging state in a port.
        !          1202:  *     Insert the port into a global list of all allocated ports.
        !          1203:  */
        !          1204: void
        !          1205: ipc_port_init_debug(
        !          1206:        ipc_port_t      port)
        !          1207: {
        !          1208:        unsigned int    i;
        !          1209: 
        !          1210:        port->ip_thread = (unsigned long) current_thread();
        !          1211:        port->ip_timetrack = port_timestamp++;
        !          1212:        for (i = 0; i < IP_CALLSTACK_MAX; ++i)
        !          1213:                port->ip_callstack[i] = 0;
        !          1214:        for (i = 0; i < IP_NSPARES; ++i)
        !          1215:                port->ip_spares[i] = 0;
        !          1216: 
        !          1217:        /*
        !          1218:         *      Machine-dependent routine to fill in an
        !          1219:         *      array with up to IP_CALLSTACK_MAX levels
        !          1220:         *      of return pc information.
        !          1221:         */
        !          1222:        machine_callstack(&port->ip_callstack[0], IP_CALLSTACK_MAX);
        !          1223: 
        !          1224: #if 0
        !          1225:        mutex_lock(&port_alloc_queue_lock);
        !          1226:        ++port_count;
        !          1227:        if (port_count_warning > 0 && port_count >= port_count_warning)
        !          1228:                assert(port_count < port_count_warning);
        !          1229:        queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links);
        !          1230:        mutex_unlock(&port_alloc_queue_lock);
        !          1231: #endif
        !          1232: }
        !          1233: 
        !          1234: 
        !          1235: /*
        !          1236:  *     Remove a port from the queue of allocated ports.
        !          1237:  *     This routine should be invoked JUST prior to
        !          1238:  *     deallocating the actual memory occupied by the port.
        !          1239:  */
        !          1240: void
        !          1241: ipc_port_track_dealloc(
        !          1242:        ipc_port_t      port)
        !          1243: {
        !          1244: #if 0
        !          1245:        mutex_lock(&port_alloc_queue_lock);
        !          1246:        assert(port_count > 0);
        !          1247:        --port_count;
        !          1248:        queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links);
        !          1249:        mutex_unlock(&port_alloc_queue_lock);
        !          1250: #endif
        !          1251: }
        !          1252: 
        !          1253: #endif /* MACH_ASSERT */
        !          1254: 
        !          1255: 
        !          1256: #if    MACH_KDB
        !          1257: 
        !          1258: #include <ddb/db_output.h>
        !          1259: #include <ddb/db_print.h>
        !          1260: 
        !          1261: #define        printf  kdbprintf
        !          1262: extern int db_indent;
        !          1263: 
        !          1264: int
        !          1265: db_port_queue_print(
        !          1266:        ipc_port_t      port);
        !          1267: 
        !          1268: /*
        !          1269:  * ipc_entry_print - pretty-print an ipc_entry
        !          1270:  */
        !          1271: static void ipc_entry_print(struct ipc_entry *, char *); /* forward */
        !          1272: 
        !          1273: static void ipc_entry_print(struct ipc_entry *iep, char *tag)
        !          1274: {
        !          1275:        ipc_entry_bits_t bits = iep->ie_bits;
        !          1276: 
        !          1277:        iprintf("%s @", tag);
        !          1278:        printf(" 0x%x, bits=%x object=%x\n", iep, bits, iep->ie_object);
        !          1279:        db_indent += 2;
        !          1280:        iprintf("urefs=%x ", IE_BITS_UREFS(bits));
        !          1281:        printf("type=%x gen=%x\n", IE_BITS_TYPE(bits), IE_BITS_GEN(bits));
        !          1282:        db_indent -= 2;
        !          1283: }
        !          1284: 
        !          1285: /*
        !          1286:  *     Routine:        ipc_port_print
        !          1287:  *     Purpose:
        !          1288:  *             Pretty-print a port for kdb.
        !          1289:  */
        !          1290: int    ipc_port_print_long = 0;        /* set for more detail */
        !          1291: 
        !          1292: void
        !          1293: ipc_port_print(
        !          1294:        ipc_port_t      port,
        !          1295:        boolean_t       have_addr,
        !          1296:        db_expr_t       count,
        !          1297:        char            *modif)
        !          1298: {
        !          1299:        extern int      db_indent;
        !          1300:        db_addr_t       task;
        !          1301:        int             task_id;
        !          1302:        int             nmsgs;
        !          1303:        int             verbose = 0;
        !          1304: #if    MACH_ASSERT
        !          1305:        int             i, needs_db_indent, items_printed;
        !          1306: #endif /* MACH_ASSERT */
        !          1307:        
        !          1308:        if (db_option(modif, 'l') || db_option(modif, 'v'))
        !          1309:                ++verbose;
        !          1310: 
        !          1311:        printf("port 0x%x\n", port);
        !          1312: 
        !          1313:        db_indent += 2;
        !          1314: 
        !          1315:        ipc_object_print(&port->ip_object);
        !          1316: 
        !          1317:        if (ipc_port_print_long) {
        !          1318:                iprintf("pool=0x%x", port->ip_thread_pool);
        !          1319:                printf("\n");
        !          1320:        }
        !          1321: 
        !          1322:        if (!ip_active(port)) {
        !          1323:                iprintf("timestamp=0x%x", port->ip_timestamp);
        !          1324:        } else if (port->ip_receiver_name == MACH_PORT_NULL) {
        !          1325:                iprintf("destination=0x%x (", port->ip_destination);
        !          1326:                if (port->ip_destination != MACH_PORT_NULL &&
        !          1327:                    (task = db_task_from_space(port->ip_destination->
        !          1328:                                               ip_receiver, &task_id)))
        !          1329:                        printf("task%d at 0x%x", task_id, task);
        !          1330:                else
        !          1331:                        printf("unknown");
        !          1332:                printf(")");
        !          1333:        } else {
        !          1334:                iprintf("receiver=0x%x (", port->ip_receiver);
        !          1335:                if (port->ip_receiver == ipc_space_kernel)
        !          1336:                        printf("kernel");
        !          1337:                else if (port->ip_receiver == ipc_space_reply)
        !          1338:                        printf("reply");
        !          1339:                else if (port->ip_receiver == default_pager_space)
        !          1340:                        printf("default_pager");
        !          1341:                else if (task = db_task_from_space(port->ip_receiver, &task_id))
        !          1342:                        printf("task%d at 0x%x", task_id, task);
        !          1343:                else
        !          1344:                        printf("unknown");
        !          1345:                printf(")");
        !          1346:        }
        !          1347:        printf(", receiver_name=0x%x", port->ip_receiver_name);
        !          1348:        printf("%s\n", IP_NMS(port) ? ", NMS tracking" : "");
        !          1349: 
        !          1350:        iprintf("mscount=%d", port->ip_mscount);
        !          1351:        printf(", srights=%d", port->ip_srights);
        !          1352:        printf(", sorights=%d\n", port->ip_sorights);
        !          1353: 
        !          1354:        iprintf("nsrequest=0x%x", port->ip_nsrequest);
        !          1355:        printf(", pdrequest=0x%x", port->ip_pdrequest);
        !          1356:        printf(", dnrequests=0x%x\n", port->ip_dnrequests);
        !          1357: 
        !          1358:        iprintf("pset_count=0x%x", port->ip_pset_count);
        !          1359:        printf(", seqno=%d", port->ip_messages.imq_seqno);
        !          1360:        printf(", msgcount=%d", port->ip_messages.imq_msgcount);
        !          1361:        printf(", qlimit=%d\n", port->ip_messages.imq_qlimit);
        !          1362: 
        !          1363:        iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
        !          1364:        printf(", rcvrs queue=0x%x", port->ip_messages.imq_wait_queue);
        !          1365:        printf(", kobj=0x%x\n", port->ip_kobject);
        !          1366: 
        !          1367:        iprintf("flags=0x%x", port->ip_flags);
        !          1368:        
        !          1369: #if    MACH_ASSERT
        !          1370:        /* don't bother printing callstack or queue links */
        !          1371:        iprintf("ip_thread=0x%x, ip_timetrack=0x%x\n",
        !          1372:                port->ip_thread, port->ip_timetrack);
        !          1373:        items_printed = 0;
        !          1374:        needs_db_indent = 1;
        !          1375:        for (i = 0; i < IP_NSPARES; ++i) {
        !          1376:                if (port->ip_spares[i] != 0) {
        !          1377:                        if (needs_db_indent) {
        !          1378:                                iprintf("");
        !          1379:                                needs_db_indent = 0;
        !          1380:                        }
        !          1381:                        printf("%sip_spares[%d] = %d",
        !          1382:                               items_printed ? ", " : "", i, 
        !          1383:                               port->ip_spares[i]);
        !          1384:                        if (++items_printed >= 4) {
        !          1385:                                needs_db_indent = 1;
        !          1386:                                printf("\n");
        !          1387:                                items_printed = 0;
        !          1388:                        }
        !          1389:                }
        !          1390:        }
        !          1391: #endif /* MACH_ASSERT */
        !          1392: 
        !          1393:        if (verbose) {
        !          1394:                iprintf("kmsg queue contents:\n");
        !          1395:                db_indent += 2;
        !          1396:                nmsgs = db_port_queue_print(port);
        !          1397:                db_indent -= 2;
        !          1398:                iprintf("...total kmsgs:  %d\n", nmsgs);
        !          1399:        }
        !          1400: 
        !          1401:        db_indent -=2;
        !          1402: }
        !          1403: 
        !          1404: ipc_port_t
        !          1405: ipc_name_to_data(
        !          1406:        task_t                  task,
        !          1407:        mach_port_name_t        name)
        !          1408: {
        !          1409:        ipc_space_t     space;
        !          1410:        ipc_entry_t     entry;
        !          1411: 
        !          1412:        if (task == TASK_NULL) {
        !          1413:                db_printf("port_name_to_data: task is null\n");
        !          1414:                return (0);
        !          1415:        }
        !          1416:        if ((space = task->itk_space) == 0) {
        !          1417:                db_printf("port_name_to_data: task->itk_space is null\n");
        !          1418:                return (0);
        !          1419:        }
        !          1420:        if (!space->is_active) {
        !          1421:                db_printf("port_name_to_data: task->itk_space not active\n");
        !          1422:                return (0);
        !          1423:        }
        !          1424:        if ((entry = ipc_entry_lookup(space, name)) == 0) {
        !          1425:                db_printf("port_name_to_data: lookup yields zero\n");
        !          1426:                return (0);
        !          1427:        }
        !          1428:        return ((ipc_port_t)entry->ie_object);
        !          1429: }
        !          1430: 
        !          1431: #if    ZONE_DEBUG
        !          1432: void
        !          1433: print_type_ports(type, dead)
        !          1434:        unsigned type;
        !          1435:        unsigned dead;
        !          1436: {
        !          1437:        ipc_port_t port;
        !          1438:        int n;
        !          1439: 
        !          1440:        n = 0;
        !          1441:        for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
        !          1442:             port;
        !          1443:             port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT], 
        !          1444:                                             (vm_offset_t)port))
        !          1445:                if (ip_kotype(port) == type &&
        !          1446:                    (!dead || !ip_active(port))) {
        !          1447:                        if (++n % 5)
        !          1448:                                printf("0x%x\t", port);
        !          1449:                        else
        !          1450:                                printf("0x%x\n", port);
        !          1451:                }
        !          1452:        if (n % 5)
        !          1453:                printf("\n");
        !          1454: }
        !          1455: 
        !          1456: void
        !          1457: print_ports(void)
        !          1458: {
        !          1459:        ipc_port_t port;
        !          1460:        int total_port_count;
        !          1461:        int space_null_count;
        !          1462:        int space_kernel_count;
        !          1463:        int space_reply_count;
        !          1464:        int space_pager_count;
        !          1465:        int space_other_count;
        !          1466: 
        !          1467:        struct {
        !          1468:                int total_count;
        !          1469:                int dead_count;
        !          1470:        } port_types[IKOT_MAX_TYPE];
        !          1471: 
        !          1472:        total_port_count = 0;
        !          1473: 
        !          1474:        bzero((char *)&port_types[0], sizeof(port_types));
        !          1475:        space_null_count = 0;
        !          1476:        space_kernel_count = 0;
        !          1477:        space_reply_count = 0;
        !          1478:        space_pager_count = 0;
        !          1479:        space_other_count = 0;
        !          1480: 
        !          1481:        for (port = (ipc_port_t)first_element(ipc_object_zones[IOT_PORT]);
        !          1482:             port;
        !          1483:             port = (ipc_port_t)next_element(ipc_object_zones[IOT_PORT], 
        !          1484:                                             (vm_offset_t)port)) {
        !          1485:                total_port_count++;
        !          1486:                if (ip_kotype(port) >= IKOT_MAX_TYPE) {
        !          1487:                        port_types[IKOT_UNKNOWN].total_count++;
        !          1488:                        if (!io_active(&port->ip_object))
        !          1489:                                port_types[IKOT_UNKNOWN].dead_count++;
        !          1490:                } else {
        !          1491:                        port_types[ip_kotype(port)].total_count++;
        !          1492:                        if (!io_active(&port->ip_object))
        !          1493:                                port_types[ip_kotype(port)].dead_count++;
        !          1494:                }
        !          1495: 
        !          1496:                if (!port->ip_receiver)
        !          1497:                        space_null_count++;
        !          1498:                else if (port->ip_receiver == ipc_space_kernel)
        !          1499:                        space_kernel_count++;
        !          1500:                else if (port->ip_receiver == ipc_space_reply)
        !          1501:                        space_reply_count++;
        !          1502:                else if (port->ip_receiver == default_pager_space)
        !          1503:                        space_pager_count++;
        !          1504:                else
        !          1505:                        space_other_count++;
        !          1506:        }
        !          1507:        printf("\n%7d   total ports\n\n", total_port_count);
        !          1508: 
        !          1509: #define PRINT_ONE_PORT_TYPE(name) \
        !          1510:        printf("%7d     %s", port_types[IKOT_##name].total_count, # name); \
        !          1511:        if (port_types[IKOT_##name].dead_count) \
        !          1512:             printf(" (%d dead ports)", port_types[IKOT_##name].dead_count);\
        !          1513:        printf("\n");
        !          1514: 
        !          1515:        PRINT_ONE_PORT_TYPE(NONE);
        !          1516:        PRINT_ONE_PORT_TYPE(THREAD);
        !          1517:        PRINT_ONE_PORT_TYPE(TASK);
        !          1518:        PRINT_ONE_PORT_TYPE(HOST);
        !          1519:        PRINT_ONE_PORT_TYPE(HOST_PRIV);
        !          1520:        PRINT_ONE_PORT_TYPE(PROCESSOR);
        !          1521:        PRINT_ONE_PORT_TYPE(PSET);
        !          1522:        PRINT_ONE_PORT_TYPE(PSET_NAME);
        !          1523:        PRINT_ONE_PORT_TYPE(PAGING_REQUEST);
        !          1524:        PRINT_ONE_PORT_TYPE(XMM_OBJECT);
        !          1525:        PRINT_ONE_PORT_TYPE(DEVICE);
        !          1526:        PRINT_ONE_PORT_TYPE(XMM_PAGER);
        !          1527:        PRINT_ONE_PORT_TYPE(XMM_KERNEL);
        !          1528:        PRINT_ONE_PORT_TYPE(XMM_REPLY);
        !          1529:        PRINT_ONE_PORT_TYPE(CLOCK);
        !          1530:        PRINT_ONE_PORT_TYPE(CLOCK_CTRL);
        !          1531:        PRINT_ONE_PORT_TYPE(MASTER_DEVICE);
        !          1532:        PRINT_ONE_PORT_TYPE(UNKNOWN);
        !          1533:        printf("\nipc_space:\n\n");
        !          1534:        printf("NULL    KERNEL  REPLY   PAGER   OTHER\n");
        !          1535:        printf("%d      %d      %d      %d      %d\n",
        !          1536:               space_null_count,
        !          1537:               space_kernel_count,
        !          1538:               space_reply_count,
        !          1539:               space_pager_count,
        !          1540:               space_other_count
        !          1541:        );
        !          1542: }
        !          1543: 
        !          1544: #endif /* ZONE_DEBUG */
        !          1545: 
        !          1546: 
        !          1547: /*
        !          1548:  *     Print out all the kmsgs in a queue.  Aggregate kmsgs with
        !          1549:  *     identical message ids into a single entry.  Count up the
        !          1550:  *     amount of inline and out-of-line data consumed by each
        !          1551:  *     and every kmsg.
        !          1552:  *
        !          1553:  */
        !          1554: 
        !          1555: #define        KMSG_MATCH_FIELD(kmsg)  ((unsigned int) kmsg->ikm_header.msgh_id)
        !          1556: #define        DKQP_LONG(kmsg) FALSE
        !          1557: char   *dkqp_long_format = "(%3d) <%10d> 0x%x   %10d %10d\n";
        !          1558: char   *dkqp_format = "(%3d) <%10d> 0x%x   %10d %10d\n";
        !          1559: 
        !          1560: int
        !          1561: db_kmsg_queue_print(
        !          1562:        ipc_kmsg_t      kmsg);
        !          1563: int
        !          1564: db_kmsg_queue_print(
        !          1565:        ipc_kmsg_t      kmsg)
        !          1566: {
        !          1567:        ipc_kmsg_t      ikmsg, first_kmsg;
        !          1568:        register int    icount;
        !          1569:        mach_msg_id_t   cur_id;
        !          1570:        unsigned int    inline_total, ool_total;
        !          1571:        int             nmsgs;
        !          1572: 
        !          1573:        iprintf("Count      msgh_id  kmsg addr inline bytes   ool bytes\n");
        !          1574:        inline_total = ool_total = (vm_size_t) 0;
        !          1575:        cur_id = KMSG_MATCH_FIELD(kmsg);
        !          1576:        for (icount = 0, nmsgs = 0, first_kmsg = ikmsg = kmsg;
        !          1577:             kmsg != IKM_NULL && (kmsg != first_kmsg || nmsgs == 0);
        !          1578:             kmsg = kmsg->ikm_next) {
        !          1579:                ++nmsgs;
        !          1580:                if (!(KMSG_MATCH_FIELD(kmsg) == cur_id)) {
        !          1581:                        iprintf(DKQP_LONG(kmsg) ? dkqp_long_format:dkqp_format,
        !          1582:                                icount, cur_id, ikmsg, inline_total,ool_total);
        !          1583:                        cur_id = KMSG_MATCH_FIELD(kmsg);
        !          1584:                        icount = 1;
        !          1585:                        ikmsg = kmsg;
        !          1586:                        inline_total = ool_total = 0;
        !          1587:                } else {
        !          1588:                        icount++;
        !          1589:                }
        !          1590:                if (DKQP_LONG(kmsg))
        !          1591:                        inline_total += kmsg->ikm_size;
        !          1592:                else
        !          1593:                        inline_total += kmsg->ikm_header.msgh_size;
        !          1594:        }
        !          1595:        iprintf(DKQP_LONG(kmsg) ? dkqp_long_format : dkqp_format,
        !          1596:                icount, cur_id, ikmsg, inline_total, ool_total);
        !          1597:        return nmsgs;
        !          1598: }
        !          1599: 
        !          1600: 
        !          1601: /*
        !          1602:  *     Process all of the messages on a port - prints out the
        !          1603:  *     number of occurences of each message type, and the first
        !          1604:  *     kmsg with a particular msgh_id.
        !          1605:  */
        !          1606: int
        !          1607: db_port_queue_print(
        !          1608:        ipc_port_t      port)
        !          1609: {
        !          1610:        ipc_kmsg_t      kmsg;
        !          1611: 
        !          1612:        if (ipc_kmsg_queue_empty(&port->ip_messages.imq_messages))
        !          1613:                return 0;
        !          1614:        kmsg = ipc_kmsg_queue_first(&port->ip_messages.imq_messages);
        !          1615:        return db_kmsg_queue_print(kmsg);
        !          1616: }
        !          1617: 
        !          1618: 
        !          1619: #if    MACH_ASSERT
        !          1620: #include <ddb/db_sym.h>
        !          1621: #include <ddb/db_access.h>
        !          1622: 
        !          1623: #define        FUNC_NULL       ((void (*)) 0)
        !          1624: #define        MAX_REFS        5               /* bins for tracking ref counts */
        !          1625: 
        !          1626: /*
        !          1627:  *     Translate port's cache of call stack pointers
        !          1628:  *     into symbolic names.
        !          1629:  */
        !          1630: void
        !          1631: db_port_stack_trace(
        !          1632:        ipc_port_t      port)
        !          1633: {
        !          1634:        unsigned int    i;
        !          1635: 
        !          1636:        for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
        !          1637:                iprintf("[%d] 0x%x\t", i, port->ip_callstack[i]);
        !          1638:                if (port->ip_callstack[i] != 0 &&
        !          1639:                    DB_VALID_KERN_ADDR(port->ip_callstack[i]))
        !          1640:                        db_printsym(port->ip_callstack[i], DB_STGY_PROC);
        !          1641:                printf("\n");
        !          1642:        }
        !          1643: }
        !          1644: 
        !          1645: 
        !          1646: typedef struct port_item {
        !          1647:        unsigned long   item;
        !          1648:        unsigned long   count;
        !          1649: } port_item;
        !          1650: 
        !          1651: 
        !          1652: #define        ITEM_MAX        400
        !          1653: typedef struct port_track {
        !          1654:        char            *name;
        !          1655:        unsigned long   max;
        !          1656:        unsigned long   warning;
        !          1657:        port_item       items[ITEM_MAX];
        !          1658: } port_track;
        !          1659: 
        !          1660: port_track     port_callers;           /* match against calling addresses */
        !          1661: port_track     port_threads;           /* match against allocating threads */
        !          1662: port_track     port_spaces;            /* match against ipc spaces */
        !          1663: 
        !          1664: void           port_track_init(
        !          1665:                        port_track      *trackp,
        !          1666:                        char            *name);
        !          1667: void           port_item_add(
        !          1668:                        port_track      *trackp,
        !          1669:                        unsigned long   item);
        !          1670: void           port_track_sort(
        !          1671:                        port_track      *trackp);
        !          1672: void           port_track_print(
        !          1673:                        port_track      *trackp,
        !          1674:                        void            (*func)(port_item *));
        !          1675: void           port_callers_print(
        !          1676:                        port_item       *p);
        !          1677: 
        !          1678: void
        !          1679: port_track_init(
        !          1680:        port_track      *trackp,
        !          1681:        char            *name)
        !          1682: {
        !          1683:        port_item       *i;
        !          1684: 
        !          1685:        trackp->max = trackp->warning = 0;
        !          1686:        trackp->name = name;
        !          1687:        for (i = trackp->items; i < trackp->items + ITEM_MAX; ++i)
        !          1688:                i->item = i->count = 0;
        !          1689: }
        !          1690: 
        !          1691: 
        !          1692: void
        !          1693: port_item_add(
        !          1694:        port_track      *trackp,
        !          1695:        unsigned long   item)
        !          1696: {
        !          1697:        port_item       *limit, *i;
        !          1698: 
        !          1699:        limit = trackp->items + trackp->max;
        !          1700:        for (i = trackp->items; i < limit; ++i)
        !          1701:                if (i->item == item) {
        !          1702:                        i->count++;
        !          1703:                        return;
        !          1704:                }
        !          1705:        if (trackp->max >= ITEM_MAX) {
        !          1706:                if (trackp->warning++ == 0)
        !          1707:                        iprintf("%s:  no room\n", trackp->name);
        !          1708:                return;
        !          1709:        }
        !          1710:        i->item = item;
        !          1711:        i->count = 1;
        !          1712:        trackp->max++;
        !          1713: }
        !          1714: 
        !          1715: 
        !          1716: /*
        !          1717:  *     Simple (and slow) bubble sort.
        !          1718:  */
        !          1719: void
        !          1720: port_track_sort(
        !          1721:        port_track      *trackp)
        !          1722: {
        !          1723:        port_item       *limit, *p;
        !          1724:        port_item       temp;
        !          1725:        boolean_t       unsorted;
        !          1726: 
        !          1727:        limit = trackp->items + trackp->max - 1;
        !          1728:        do {
        !          1729:                unsorted = FALSE;
        !          1730:                for (p = trackp->items; p < limit - 1; ++p) {
        !          1731:                        if (p->count < (p+1)->count) {
        !          1732:                                temp = *p;
        !          1733:                                *p = *(p+1);
        !          1734:                                *(p+1) = temp;
        !          1735:                                unsorted = TRUE;
        !          1736:                        }
        !          1737:                }
        !          1738:        } while (unsorted == TRUE);
        !          1739: }
        !          1740: 
        !          1741: 
        !          1742: void
        !          1743: port_track_print(
        !          1744:        port_track      *trackp,
        !          1745:        void            (*func)(port_item *))
        !          1746: {
        !          1747:        port_item       *limit, *p;
        !          1748: 
        !          1749:        limit = trackp->items + trackp->max;
        !          1750:        iprintf("%s:\n", trackp->name);
        !          1751:        for (p = trackp->items; p < limit; ++p) {
        !          1752:                if (func != FUNC_NULL)
        !          1753:                        (*func)(p);
        !          1754:                else
        !          1755:                        iprintf("0x%x\t%8d\n", p->item, p->count);
        !          1756:        }
        !          1757: }
        !          1758: 
        !          1759: 
        !          1760: void
        !          1761: port_callers_print(
        !          1762:        port_item       *p)
        !          1763: {
        !          1764:        iprintf("0x%x\t%8d\t", p->item, p->count);
        !          1765:        db_printsym(p->item, DB_STGY_PROC);
        !          1766:        printf("\n");
        !          1767: }
        !          1768: 
        !          1769: 
        !          1770: /*
        !          1771:  *     Show all ports with a given reference count.
        !          1772:  */
        !          1773: void
        !          1774: db_ref(
        !          1775:        int             refs)
        !          1776: {
        !          1777:        db_port_walk(1, 1, 1, refs);
        !          1778: }
        !          1779: 
        !          1780: 
        !          1781: /*
        !          1782:  *     Examine all currently allocated ports.
        !          1783:  *     Options:
        !          1784:  *             verbose         display suspicious ports
        !          1785:  *             display         print out each port encountered
        !          1786:  *             ref_search      restrict examination to ports with
        !          1787:  *                             a specified reference count
        !          1788:  *             ref_target      reference count for ref_search
        !          1789:  */
        !          1790: int
        !          1791: db_port_walk(
        !          1792:        unsigned int    verbose,
        !          1793:        unsigned int    display,
        !          1794:        unsigned int    ref_search,
        !          1795:        unsigned int    ref_target)
        !          1796: {
        !          1797:        ipc_port_t      port;
        !          1798:        unsigned int    ref_overflow, refs, i, ref_inactive_overflow;
        !          1799:        unsigned int    no_receiver, no_match;
        !          1800:        unsigned int    ref_counts[MAX_REFS];
        !          1801:        unsigned int    inactive[MAX_REFS];
        !          1802:        unsigned int    ipc_ports = 0;
        !          1803:        unsigned int    proxies = 0, principals = 0;
        !          1804: 
        !          1805:        iprintf("Allocated port count is %d\n", port_count);
        !          1806:        no_receiver = no_match = ref_overflow = 0;
        !          1807:        ref_inactive_overflow = 0;
        !          1808:        for (i = 0; i < MAX_REFS; ++i) {
        !          1809:                ref_counts[i] = 0;
        !          1810:                inactive[i] = 0;
        !          1811:        }
        !          1812:        port_track_init(&port_callers, "port callers");
        !          1813:        port_track_init(&port_threads, "port threads");
        !          1814:        port_track_init(&port_spaces, "port spaces");
        !          1815:        if (ref_search)
        !          1816:                iprintf("Walking ports of ref_count=%d.\n", ref_target);
        !          1817:        else
        !          1818:                iprintf("Walking all ports.\n");
        !          1819: 
        !          1820:        queue_iterate(&port_alloc_queue, port, ipc_port_t, ip_port_links) {
        !          1821:                char    *port_type;
        !          1822: 
        !          1823:                port_type = " IPC port";
        !          1824:                if (ip_active(port))
        !          1825:                  ipc_ports++;
        !          1826: 
        !          1827:                refs = port->ip_references;
        !          1828:                if (ref_search && refs != ref_target)
        !          1829:                        continue;
        !          1830: 
        !          1831:                if (refs >= MAX_REFS) {
        !          1832:                        if (ip_active(port))
        !          1833:                                ++ref_overflow;
        !          1834:                        else
        !          1835:                                ++ref_inactive_overflow;
        !          1836:                } else {
        !          1837:                        if (refs == 0 && verbose)
        !          1838:                                iprintf("%s 0x%x has ref count of zero!\n",
        !          1839:                                        port_type, port);
        !          1840:                        if (ip_active(port))
        !          1841:                                ref_counts[refs]++;
        !          1842:                        else
        !          1843:                                inactive[refs]++;
        !          1844:                }
        !          1845:                port_item_add(&port_threads, (unsigned long) port->ip_thread);
        !          1846:                for (i = 0; i < IP_CALLSTACK_MAX; ++i) {
        !          1847:                        if (port->ip_callstack[i] != 0 &&
        !          1848:                            DB_VALID_KERN_ADDR(port->ip_callstack[i]))
        !          1849:                                port_item_add(&port_callers,
        !          1850:                                              port->ip_callstack[i]);
        !          1851:                }
        !          1852:                if (!ip_active(port)) {
        !          1853:                        if (verbose)
        !          1854:                                iprintf("%s 0x%x, inactive, refcnt %d\n",
        !          1855:                                        port_type, port, refs);
        !          1856:                        continue;
        !          1857:                }
        !          1858: 
        !          1859:                if (port->ip_receiver_name == MACH_PORT_NULL) {
        !          1860:                        iprintf("%s  0x%x, no receiver, refcnt %d\n",
        !          1861:                                port, refs);
        !          1862:                        ++no_receiver;
        !          1863:                        continue;
        !          1864:                }
        !          1865:                if (port->ip_receiver == ipc_space_kernel ||
        !          1866:                    port->ip_receiver == ipc_space_reply ||
        !          1867:                    ipc_entry_lookup(port->ip_receiver,
        !          1868:                                        port->ip_receiver_name) 
        !          1869:                                        != IE_NULL) {
        !          1870:                        port_item_add(&port_spaces,
        !          1871:                                      (unsigned long)port->ip_receiver);
        !          1872:                        if (display) {
        !          1873:                                iprintf( "%s 0x%x time 0x%x ref_cnt %d\n",
        !          1874:                                                port_type, port,
        !          1875:                                                port->ip_timetrack, refs);
        !          1876:                        }
        !          1877:                        continue;
        !          1878:                }
        !          1879:                iprintf("%s 0x%x, rcvr 0x%x, name 0x%x, ref %d, no match\n",
        !          1880:                                port_type, port, port->ip_receiver,
        !          1881:                                port->ip_receiver_name, refs);
        !          1882:                ++no_match;
        !          1883:        }
        !          1884:        iprintf("Active port type summary:\n");
        !          1885:        iprintf("\tlocal  IPC %6d\n", ipc_ports);
        !          1886:        iprintf("summary:\tcallers %d threads %d spaces %d\n",
        !          1887:                port_callers.max, port_threads.max, port_spaces.max);
        !          1888: 
        !          1889:        iprintf("\tref_counts:\n");
        !          1890:        for (i = 0; i < MAX_REFS; ++i)
        !          1891:                iprintf("\t  ref_counts[%d] = %d\n", i, ref_counts[i]);
        !          1892: 
        !          1893:        iprintf("\t%d ports w/o receivers, %d w/o matches\n",
        !          1894:                no_receiver, no_match);
        !          1895: 
        !          1896:        iprintf("\tinactives:");
        !          1897:        if ( ref_inactive_overflow || inactive[0] || inactive[1] ||
        !          1898:             inactive[2] || inactive[3] || inactive[4] )
        !          1899:                printf(" [0]=%d [1]=%d [2]=%d [3]=%d [4]=%d [5+]=%d\n",
        !          1900:                        inactive[0], inactive[1], inactive[2],
        !          1901:                        inactive[3], inactive[4], ref_inactive_overflow);
        !          1902:        else
        !          1903:                printf(" No inactive ports.\n");
        !          1904: 
        !          1905:        port_track_sort(&port_spaces);
        !          1906:        port_track_print(&port_spaces, FUNC_NULL);
        !          1907:        port_track_sort(&port_threads);
        !          1908:        port_track_print(&port_threads, FUNC_NULL);
        !          1909:        port_track_sort(&port_callers);
        !          1910:        port_track_print(&port_callers, port_callers_print);
        !          1911:        return 0;
        !          1912: }
        !          1913: 
        !          1914: 
        !          1915: #endif /* MACH_ASSERT */
        !          1916: 
        !          1917: #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.