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

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_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.