Annotation of Gnu-Mach/ipc/ipc_port.c, revision 1.1.1.2

1.1       root        1: /*
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
                      4:  * Copyright (c) 1993,1994 The University of Utah and
                      5:  * the Computer Systems Laboratory (CSL).
                      6:  * All rights reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
                     15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
                     16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
                     17:  * THIS SOFTWARE.
                     18:  *
                     19:  * Carnegie Mellon requests users of this software to return to
                     20:  *
                     21:  *  Software Distribution Coordinator  or  [email protected]
                     22:  *  School of Computer Science
                     23:  *  Carnegie Mellon University
                     24:  *  Pittsburgh PA 15213-3890
                     25:  *
                     26:  * any improvements or extensions that they make and grant Carnegie Mellon
                     27:  * the rights to redistribute these changes.
                     28:  */
                     29: /*
                     30:  *     File:   ipc/ipc_port.c
                     31:  *     Author: Rich Draves
                     32:  *     Date:   1989
                     33:  *
                     34:  *     Functions to manipulate IPC ports.
                     35:  */
                     36: 
                     37: #include <mach_ipc_compat.h>
                     38: 
                     39: #include <mach/port.h>
                     40: #include <mach/kern_return.h>
                     41: #include <kern/lock.h>
                     42: #include <kern/ipc_sched.h>
                     43: #include <kern/ipc_kobject.h>
                     44: #include <ipc/ipc_entry.h>
                     45: #include <ipc/ipc_space.h>
                     46: #include <ipc/ipc_object.h>
                     47: #include <ipc/ipc_port.h>
                     48: #include <ipc/ipc_pset.h>
                     49: #include <ipc/ipc_thread.h>
                     50: #include <ipc/ipc_mqueue.h>
                     51: #include <ipc/ipc_notify.h>
                     52: #if    NORMA_IPC
                     53: #include <norma/ipc_node.h>
1.1.1.2 ! root       54: #endif /* NORMA_IPC */
1.1       root       55: 
                     56: 
                     57: 
                     58: decl_simple_lock_data(, ipc_port_multiple_lock_data)
                     59: 
                     60: decl_simple_lock_data(, ipc_port_timestamp_lock_data)
                     61: ipc_port_timestamp_t ipc_port_timestamp_data;
                     62: 
                     63: /*
                     64:  *     Routine:        ipc_port_timestamp
                     65:  *     Purpose:
                     66:  *             Retrieve a timestamp value.
                     67:  */
                     68: 
                     69: ipc_port_timestamp_t
                     70: ipc_port_timestamp(void)
                     71: {
                     72:        ipc_port_timestamp_t timestamp;
                     73: 
                     74:        ipc_port_timestamp_lock();
                     75:        timestamp = ipc_port_timestamp_data++;
                     76:        ipc_port_timestamp_unlock();
                     77: 
                     78:        return timestamp;
                     79: }
                     80: 
                     81: /*
                     82:  *     Routine:        ipc_port_dnrequest
                     83:  *     Purpose:
                     84:  *             Try to allocate a dead-name request slot.
                     85:  *             If successful, returns the request index.
                     86:  *             Otherwise returns zero.
                     87:  *     Conditions:
                     88:  *             The port is locked and active.
                     89:  *     Returns:
                     90:  *             KERN_SUCCESS            A request index was found.
                     91:  *             KERN_NO_SPACE           No index allocated.
                     92:  */
                     93: 
                     94: kern_return_t
                     95: ipc_port_dnrequest(port, name, soright, indexp)
                     96:        ipc_port_t port;
                     97:        mach_port_t name;
                     98:        ipc_port_t soright;
                     99:        ipc_port_request_index_t *indexp;
                    100: {
                    101:        ipc_port_request_t ipr, table;
                    102:        ipc_port_request_index_t index;
                    103: 
                    104:        assert(ip_active(port));
                    105:        assert(name != MACH_PORT_NULL);
                    106:        assert(soright != IP_NULL);
                    107: 
                    108:        table = port->ip_dnrequests;
                    109:        if (table == IPR_NULL)
                    110:                return KERN_NO_SPACE;
                    111: 
                    112:        index = table->ipr_next;
                    113:        if (index == 0)
                    114:                return KERN_NO_SPACE;
                    115: 
                    116:        ipr = &table[index];
                    117:        assert(ipr->ipr_name == MACH_PORT_NULL);
                    118: 
                    119:        table->ipr_next = ipr->ipr_next;
                    120:        ipr->ipr_name = name;
                    121:        ipr->ipr_soright = soright;
                    122: 
                    123:        *indexp = index;
                    124:        return KERN_SUCCESS;
                    125: }
                    126: 
                    127: /*
                    128:  *     Routine:        ipc_port_dngrow
                    129:  *     Purpose:
                    130:  *             Grow a port's table of dead-name requests.
                    131:  *     Conditions:
                    132:  *             The port must be locked and active.
                    133:  *             Nothing else locked; will allocate memory.
                    134:  *             Upon return the port is unlocked.
                    135:  *     Returns:
                    136:  *             KERN_SUCCESS            Grew the table.
                    137:  *             KERN_SUCCESS            Somebody else grew the table.
                    138:  *             KERN_SUCCESS            The port died.
                    139:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate new table.
                    140:  */
                    141: 
                    142: kern_return_t
                    143: ipc_port_dngrow(port)
                    144:        ipc_port_t port;
                    145: {
                    146:        ipc_table_size_t its;
                    147:        ipc_port_request_t otable, ntable;
                    148: 
                    149:        assert(ip_active(port));
                    150: 
                    151:        otable = port->ip_dnrequests;
                    152:        if (otable == IPR_NULL)
                    153:                its = &ipc_table_dnrequests[0];
                    154:        else
                    155:                its = otable->ipr_size + 1;
                    156: 
                    157:        ip_reference(port);
                    158:        ip_unlock(port);
                    159: 
                    160:        if ((its->its_size == 0) ||
                    161:            ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
                    162:                ipc_port_release(port);
                    163:                return KERN_RESOURCE_SHORTAGE;
                    164:        }
                    165: 
                    166:        ip_lock(port);
                    167:        ip_release(port);
                    168: 
                    169:        /*
                    170:         *      Check that port is still active and that nobody else
                    171:         *      has slipped in and grown the table on us.  Note that
                    172:         *      just checking port->ip_dnrequests == otable isn't
                    173:         *      sufficient; must check ipr_size.
                    174:         */
                    175: 
                    176:        if (ip_active(port) &&
                    177:            (port->ip_dnrequests == otable) &&
                    178:            ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
                    179:                ipc_table_size_t oits = 0; /* '=0' to shut up lint */
                    180:                ipc_table_elems_t osize, nsize;
                    181:                ipc_port_request_index_t free, i;
                    182: 
                    183:                /* copy old table to new table */
                    184: 
                    185:                if (otable != IPR_NULL) {
                    186:                        oits = otable->ipr_size;
                    187:                        osize = oits->its_size;
                    188:                        free = otable->ipr_next;
                    189: 
                    190:                        bcopy((char *)(otable + 1), (char *)(ntable + 1),
                    191:                              (osize - 1) * sizeof(struct ipc_port_request));
                    192:                } else {
                    193:                        osize = 1;
                    194:                        free = 0;
                    195:                }
                    196: 
                    197:                nsize = its->its_size;
                    198:                assert(nsize > osize);
                    199: 
                    200:                /* add new elements to the new table's free list */
                    201: 
                    202:                for (i = osize; i < nsize; i++) {
                    203:                        ipc_port_request_t ipr = &ntable[i];
                    204: 
                    205:                        ipr->ipr_name = MACH_PORT_NULL;
                    206:                        ipr->ipr_next = free;
                    207:                        free = i;
                    208:                }
                    209: 
                    210:                ntable->ipr_next = free;
                    211:                ntable->ipr_size = its;
                    212:                port->ip_dnrequests = ntable;
                    213:                ip_unlock(port);
                    214: 
                    215:                if (otable != IPR_NULL)
                    216:                        it_dnrequests_free(oits, otable);
                    217:        } else {
                    218:                ip_check_unlock(port);
                    219:                it_dnrequests_free(its, ntable);
                    220:        }
                    221: 
                    222:        return KERN_SUCCESS;
                    223: }
1.1.1.2 ! root      224: 
1.1       root      225: /*
                    226:  *     Routine:        ipc_port_dncancel
                    227:  *     Purpose:
                    228:  *             Cancel a dead-name request and return the send-once right.
                    229:  *     Conditions:
                    230:  *             The port must locked and active.
                    231:  */
                    232: 
                    233: ipc_port_t
                    234: ipc_port_dncancel(
                    235:        ipc_port_t                      port,
                    236:        mach_port_t                     name,
                    237:        ipc_port_request_index_t        index)
                    238: {
                    239:        ipc_port_request_t ipr, table;
                    240:        ipc_port_t dnrequest;
                    241: 
                    242:        assert(ip_active(port));
                    243:        assert(name != MACH_PORT_NULL);
                    244:        assert(index != 0);
                    245: 
                    246:        table = port->ip_dnrequests;
                    247:        assert(table != IPR_NULL);
                    248: 
                    249:        ipr = &table[index];
                    250:        dnrequest = ipr->ipr_soright;
                    251:        assert(ipr->ipr_name == name);
                    252: 
                    253:        /* return ipr to the free list inside the table */
                    254: 
                    255:        ipr->ipr_name = MACH_PORT_NULL;
                    256:        ipr->ipr_next = table->ipr_next;
                    257:        table->ipr_next = index;
                    258: 
                    259:        return dnrequest;
                    260: }
                    261: 
                    262: /*
                    263:  *     Routine:        ipc_port_pdrequest
                    264:  *     Purpose:
                    265:  *             Make a port-deleted request, returning the
                    266:  *             previously registered send-once right.
                    267:  *             Just cancels the previous request if notify is IP_NULL.
                    268:  *     Conditions:
                    269:  *             The port is locked and active.  It is unlocked.
                    270:  *             Consumes a ref for notify (if non-null), and
                    271:  *             returns previous with a ref (if non-null).
                    272:  */
                    273: 
                    274: void
                    275: ipc_port_pdrequest(
                    276:        ipc_port_t      port,
                    277:        ipc_port_t      notify,
                    278:        ipc_port_t      *previousp)
                    279: {
                    280:        ipc_port_t previous;
                    281: 
                    282:        assert(ip_active(port));
                    283: 
                    284:        previous = port->ip_pdrequest;
                    285:        port->ip_pdrequest = notify;
                    286:        ip_unlock(port);
                    287: 
                    288:        *previousp = previous;
                    289: }
                    290: 
                    291: /*
                    292:  *     Routine:        ipc_port_nsrequest
                    293:  *     Purpose:
                    294:  *             Make a no-senders request, returning the
                    295:  *             previously registered send-once right.
                    296:  *             Just cancels the previous request if notify is IP_NULL.
                    297:  *     Conditions:
                    298:  *             The port is locked and active.  It is unlocked.
                    299:  *             Consumes a ref for notify (if non-null), and
                    300:  *             returns previous with a ref (if non-null).
                    301:  */
                    302: 
                    303: void
                    304: ipc_port_nsrequest(
                    305:        ipc_port_t              port,
                    306:        mach_port_mscount_t     sync,
                    307:        ipc_port_t              notify,
                    308:        ipc_port_t              *previousp)
                    309: {
                    310:        ipc_port_t previous;
                    311:        mach_port_mscount_t mscount;
                    312: 
                    313:        assert(ip_active(port));
                    314: 
                    315:        previous = port->ip_nsrequest;
                    316:        mscount = port->ip_mscount;
                    317: 
                    318:        if ((port->ip_srights == 0) &&
                    319:            (sync <= mscount) &&
                    320:            (notify != IP_NULL)) {
                    321:                port->ip_nsrequest = IP_NULL;
                    322:                ip_unlock(port);
                    323:                ipc_notify_no_senders(notify, mscount);
                    324:        } else {
                    325:                port->ip_nsrequest = notify;
                    326:                ip_unlock(port);
                    327:        }
                    328: 
                    329:        *previousp = previous;
                    330: }
                    331: 
                    332: /*
                    333:  *     Routine:        ipc_port_set_qlimit
                    334:  *     Purpose:
                    335:  *             Changes a port's queue limit; the maximum number
                    336:  *             of messages which may be queued to the port.
                    337:  *     Conditions:
                    338:  *             The port is locked and active.
                    339:  */
                    340: 
                    341: void
                    342: ipc_port_set_qlimit(
                    343:        ipc_port_t              port,
                    344:        mach_port_msgcount_t    qlimit)
                    345: {
                    346:        assert(ip_active(port));
                    347: 
                    348:        /* wake up senders allowed by the new qlimit */
                    349: 
                    350:        if (qlimit > port->ip_qlimit) {
                    351:                mach_port_msgcount_t i, wakeup;
                    352: 
                    353:                /* caution: wakeup, qlimit are unsigned */
                    354: 
                    355:                wakeup = qlimit - port->ip_qlimit;
                    356: 
                    357:                for (i = 0; i < wakeup; i++) {
                    358:                        ipc_thread_t th;
                    359: 
                    360:                        th = ipc_thread_dequeue(&port->ip_blocked);
                    361:                        if (th == ITH_NULL)
                    362:                                break;
                    363: 
                    364:                        th->ith_state = MACH_MSG_SUCCESS;
                    365:                        thread_go(th);
                    366:                }
                    367:        }
                    368: 
                    369:        port->ip_qlimit = qlimit;
                    370: }
                    371: 
                    372: /*
                    373:  *     Routine:        ipc_port_lock_mqueue
                    374:  *     Purpose:
                    375:  *             Locks and returns the message queue that the port is using.
                    376:  *             The message queue may be in the port or in its port set.
                    377:  *     Conditions:
                    378:  *             The port is locked and active.
                    379:  *             Port set, message queue locks may be taken.
                    380:  */
                    381: 
                    382: ipc_mqueue_t
                    383: ipc_port_lock_mqueue(port)
                    384:        ipc_port_t port;
                    385: {
                    386:        if (port->ip_pset != IPS_NULL) {
                    387:                ipc_pset_t pset = port->ip_pset;
                    388: 
                    389:                ips_lock(pset);
                    390:                if (ips_active(pset)) {
                    391:                        imq_lock(&pset->ips_messages);
                    392:                        ips_unlock(pset);
                    393:                        return &pset->ips_messages;
                    394:                }
                    395: 
                    396:                ipc_pset_remove(pset, port);
                    397:                ips_check_unlock(pset);
                    398:        }
                    399: 
                    400:        imq_lock(&port->ip_messages);
                    401:        return &port->ip_messages;
                    402: }
                    403: 
                    404: /*
                    405:  *     Routine:        ipc_port_set_seqno
                    406:  *     Purpose:
                    407:  *             Changes a port's sequence number.
                    408:  *     Conditions:
                    409:  *             The port is locked and active.
                    410:  *             Port set, message queue locks may be taken.
                    411:  */
                    412: 
                    413: void
                    414: ipc_port_set_seqno(port, seqno)
                    415:        ipc_port_t port;
                    416:        mach_port_seqno_t seqno;
                    417: {
                    418:        ipc_mqueue_t mqueue;
                    419: 
                    420:        mqueue = ipc_port_lock_mqueue(port);
                    421:        port->ip_seqno = seqno;
                    422:        imq_unlock(mqueue);
                    423: }
                    424: 
                    425: /*
                    426:  *     Routine:        ipc_port_clear_receiver
                    427:  *     Purpose:
                    428:  *             Prepares a receive right for transmission/destruction.
                    429:  *     Conditions:
                    430:  *             The port is locked and active.
                    431:  */
                    432: 
                    433: void
                    434: ipc_port_clear_receiver(
                    435:        ipc_port_t      port)
                    436: {
                    437:        ipc_pset_t pset;
                    438: 
                    439:        assert(ip_active(port));
                    440: 
                    441:        pset = port->ip_pset;
                    442:        if (pset != IPS_NULL) {
                    443:                /* No threads receiving from port, but must remove from set. */
                    444: 
                    445:                ips_lock(pset);
                    446:                ipc_pset_remove(pset, port);
                    447:                ips_check_unlock(pset);
                    448:        } else {
                    449:                /* Else, wake up all receivers, indicating why. */
                    450: 
                    451:                imq_lock(&port->ip_messages);
                    452:                ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED);
                    453:                imq_unlock(&port->ip_messages);
                    454:        }
                    455: 
                    456:        ipc_port_set_mscount(port, 0);
                    457:        imq_lock(&port->ip_messages);
                    458:        port->ip_seqno = 0;
                    459:        imq_unlock(&port->ip_messages);
                    460: }
                    461: 
                    462: /*
                    463:  *     Routine:        ipc_port_init
                    464:  *     Purpose:
                    465:  *             Initializes a newly-allocated port.
                    466:  *             Doesn't touch the ip_object fields.
                    467:  */
                    468: 
                    469: void
                    470: ipc_port_init(
                    471:        ipc_port_t      port,
                    472:        ipc_space_t     space,
                    473:        mach_port_t     name)
                    474: {
                    475:        /* port->ip_kobject doesn't have to be initialized */
                    476: 
                    477:        ipc_target_init(&port->ip_target, name);
                    478: 
                    479:        port->ip_receiver = space;
                    480: 
                    481:        port->ip_mscount = 0;
                    482:        port->ip_srights = 0;
                    483:        port->ip_sorights = 0;
                    484: 
                    485:        port->ip_nsrequest = IP_NULL;
                    486:        port->ip_pdrequest = IP_NULL;
                    487:        port->ip_dnrequests = IPR_NULL;
                    488: 
                    489:        port->ip_pset = IPS_NULL;
                    490:        port->ip_cur_target = &port->ip_target;
                    491:        port->ip_seqno = 0;
                    492:        port->ip_msgcount = 0;
                    493:        port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
                    494: 
                    495: #if    NORMA_IPC
                    496:        port->ip_norma_uid = 0;
                    497:        port->ip_norma_dest_node = 0;
                    498:        port->ip_norma_stransit = 0;
                    499:        port->ip_norma_sotransit = 0;
                    500:        port->ip_norma_xmm_object_refs = 0;
                    501:        port->ip_norma_is_proxy = FALSE;
                    502:        port->ip_norma_is_special = FALSE;
                    503:        port->ip_norma_atrium = IP_NULL;
                    504:        port->ip_norma_queue_next = port;
                    505:        port->ip_norma_xmm_object = IP_NULL;
                    506:        port->ip_norma_next = port;
                    507:        port->ip_norma_spare1 = 0L;
                    508:        port->ip_norma_spare2 = 0L;
                    509:        port->ip_norma_spare3 = 0L;
                    510:        port->ip_norma_spare4 = 0L;
1.1.1.2 ! root      511: #endif /* NORMA_IPC */
1.1       root      512: 
                    513:        ipc_mqueue_init(&port->ip_messages);
                    514:        ipc_thread_queue_init(&port->ip_blocked);
                    515: }
                    516: 
                    517: /*
                    518:  *     Routine:        ipc_port_alloc
                    519:  *     Purpose:
                    520:  *             Allocate a port.
                    521:  *     Conditions:
                    522:  *             Nothing locked.  If successful, the port is returned
                    523:  *             locked.  (The caller doesn't have a reference.)
                    524:  *     Returns:
                    525:  *             KERN_SUCCESS            The port is allocated.
                    526:  *             KERN_INVALID_TASK       The space is dead.
                    527:  *             KERN_NO_SPACE           No room for an entry in the space.
                    528:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    529:  */
                    530: 
                    531: kern_return_t
                    532: ipc_port_alloc(
                    533:        ipc_space_t     space,
                    534:        mach_port_t     *namep,
                    535:        ipc_port_t      *portp)
                    536: {
                    537:        ipc_port_t port;
                    538:        mach_port_t name;
                    539:        kern_return_t kr;
                    540: 
                    541:        kr = ipc_object_alloc(space, IOT_PORT,
                    542:                              MACH_PORT_TYPE_RECEIVE, 0,
                    543:                              &name, (ipc_object_t *) &port);
                    544:        if (kr != KERN_SUCCESS)
                    545:                return kr;
                    546: 
                    547:        /* port is locked */
                    548: 
                    549:        ipc_port_init(port, space, name);
                    550: 
                    551:        *namep = name;
                    552:        *portp = port;
                    553: 
                    554:        return KERN_SUCCESS;
                    555: }
                    556: 
                    557: /*
                    558:  *     Routine:        ipc_port_alloc_name
                    559:  *     Purpose:
                    560:  *             Allocate a port, with a specific name.
                    561:  *     Conditions:
                    562:  *             Nothing locked.  If successful, the port is returned
                    563:  *             locked.  (The caller doesn't have a reference.)
                    564:  *     Returns:
                    565:  *             KERN_SUCCESS            The port is allocated.
                    566:  *             KERN_INVALID_TASK       The space is dead.
                    567:  *             KERN_NAME_EXISTS        The name already denotes a right.
                    568:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    569:  */
                    570: 
                    571: kern_return_t
                    572: ipc_port_alloc_name(
                    573:        ipc_space_t     space,
                    574:        mach_port_t     name,
                    575:        ipc_port_t      *portp)
                    576: {
                    577:        ipc_port_t port;
                    578:        kern_return_t kr;
                    579: 
                    580:        kr = ipc_object_alloc_name(space, IOT_PORT,
                    581:                                   MACH_PORT_TYPE_RECEIVE, 0,
                    582:                                   name, (ipc_object_t *) &port);
                    583:        if (kr != KERN_SUCCESS)
                    584:                return kr;
                    585:        /* port is locked */
                    586: 
                    587:        ipc_port_init(port, space, name);
                    588: 
                    589:        *portp = port;
                    590:        return KERN_SUCCESS;
                    591: }
                    592: 
                    593: #if    MACH_IPC_COMPAT
                    594: /*
                    595:  *     Routine:        ipc_port_delete_compat
                    596:  *     Purpose:
                    597:  *             Find and destroy a compat entry for a dead port.
                    598:  *             If successful, generate a port-deleted notification.
                    599:  *     Conditions:
                    600:  *             Nothing locked; the port is dead.
                    601:  *             Frees a ref for the space.
                    602:  */
                    603: 
                    604: void
                    605: ipc_port_delete_compat(port, space, name)
                    606:        ipc_port_t port;
                    607:        ipc_space_t space;
                    608:        mach_port_t name;
                    609: {
                    610:        ipc_entry_t entry;
                    611:        kern_return_t kr;
                    612: 
                    613:        assert(!ip_active(port));
                    614: 
                    615:        kr = ipc_right_lookup_write(space, name, &entry);
                    616:        if (kr == KERN_SUCCESS) {
                    617:                ipc_port_t sright;
                    618: 
                    619:                /* space is write-locked and active */
                    620: 
                    621:                if ((ipc_port_t) entry->ie_object == port) {
                    622:                        assert(entry->ie_bits & IE_BITS_COMPAT);
                    623: 
                    624:                        sright = ipc_space_make_notify(space);
                    625: 
                    626:                        kr = ipc_right_destroy(space, name, entry);
                    627:                        /* space is unlocked */
                    628:                        assert(kr == KERN_INVALID_NAME);
                    629:                } else {
                    630:                        is_write_unlock(space);
                    631:                        sright = IP_NULL;
                    632:                }
                    633: 
                    634:                if (IP_VALID(sright))
                    635:                        ipc_notify_port_deleted_compat(sright, name);
                    636:        }
                    637: 
                    638:        is_release(space);
                    639: }
1.1.1.2 ! root      640: #endif /* MACH_IPC_COMPAT */
1.1       root      641: 
                    642: /*
                    643:  *     Routine:        ipc_port_destroy
                    644:  *     Purpose:
                    645:  *             Destroys a port.  Cleans up queued messages.
                    646:  *
                    647:  *             If the port has a backup, it doesn't get destroyed,
                    648:  *             but is sent in a port-destroyed notification to the backup.
                    649:  *     Conditions:
                    650:  *             The port is locked and alive; nothing else locked.
                    651:  *             The caller has a reference, which is consumed.
                    652:  *             Afterwards, the port is unlocked and dead.
                    653:  */
                    654: 
                    655: void
                    656: ipc_port_destroy(
                    657:        ipc_port_t      port)
                    658: {
                    659:        ipc_port_t pdrequest, nsrequest;
                    660:        ipc_mqueue_t mqueue;
                    661:        ipc_kmsg_queue_t kmqueue;
                    662:        ipc_kmsg_t kmsg;
                    663:        ipc_thread_t sender;
                    664:        ipc_port_request_t dnrequests;
                    665: 
                    666:        assert(ip_active(port));
                    667:        /* port->ip_receiver_name is garbage */
                    668:        /* port->ip_receiver/port->ip_destination is garbage */
                    669:        assert(port->ip_pset == IPS_NULL);
                    670:        assert(port->ip_mscount == 0);
                    671:        assert(port->ip_seqno == 0);
                    672: 
                    673:        /* first check for a backup port */
                    674: 
                    675:        pdrequest = port->ip_pdrequest;
                    676:        if (pdrequest != IP_NULL) {
                    677:                /* we assume the ref for pdrequest */
                    678:                port->ip_pdrequest = IP_NULL;
                    679: 
                    680:                /* make port be in limbo */
                    681:                port->ip_receiver_name = MACH_PORT_NULL;
                    682:                port->ip_destination = IP_NULL;
                    683:                ip_unlock(port);
                    684: 
                    685: #if    MACH_IPC_COMPAT
                    686:                /*
                    687:                 *      pdrequest might actually be a send right instead
                    688:                 *      of a send-once right, indicated by the low bit
                    689:                 *      of the pointer value.  If this is the case,
                    690:                 *      we must use ipc_notify_port_destroyed_compat.
                    691:                 */
                    692: 
                    693:                if (ip_pdsendp(pdrequest)) {
                    694:                        ipc_port_t sright = ip_pdsend(pdrequest);
                    695: 
                    696:                        if (!ipc_port_check_circularity(port, sright)) {
                    697:                                /* consumes our refs for port and sright */
                    698:                                ipc_notify_port_destroyed_compat(sright, port);
                    699:                                return;
                    700:                        } else {
                    701:                                /* consume sright and destroy port */
                    702:                                ipc_port_release_send(sright);
                    703:                        }
                    704:                } else
1.1.1.2 ! root      705: #endif /* MACH_IPC_COMPAT */
1.1       root      706: 
                    707:                if (!ipc_port_check_circularity(port, pdrequest)) {
                    708:                        /* consumes our refs for port and pdrequest */
                    709:                        ipc_notify_port_destroyed(pdrequest, port);
                    710:                        return;
                    711:                } else {
                    712:                        /* consume pdrequest and destroy port */
                    713:                        ipc_port_release_sonce(pdrequest);
                    714:                }
                    715: 
                    716:                ip_lock(port);
                    717:                assert(ip_active(port));
                    718:                assert(port->ip_pset == IPS_NULL);
                    719:                assert(port->ip_mscount == 0);
                    720:                assert(port->ip_seqno == 0);
                    721:                assert(port->ip_pdrequest == IP_NULL);
                    722:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                    723:                assert(port->ip_destination == IP_NULL);
                    724: 
                    725:                /* fall through and destroy the port */
                    726:        }
                    727: 
                    728: #if    NORMA_IPC
                    729:        /*
                    730:         *      destroy any NORMA_IPC state associated with port
                    731:         */
                    732:        norma_ipc_port_destroy(port);
1.1.1.2 ! root      733: #endif /* NORMA_IPC */
1.1       root      734: 
                    735:        /*
                    736:         *      rouse all blocked senders
                    737:         *
                    738:         *      This must be done with the port locked, because
                    739:         *      ipc_mqueue_send can play with the ip_blocked queue
                    740:         *      of a dead port.
                    741:         */
                    742: 
                    743:        while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) {
                    744:                sender->ith_state = MACH_MSG_SUCCESS;
                    745:                thread_go(sender);
                    746:        }
                    747: 
                    748:        /* once port is dead, we don't need to keep it locked */
                    749: 
                    750:        port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
                    751:        port->ip_timestamp = ipc_port_timestamp();
                    752:        ip_unlock(port);
                    753: 
                    754:        /* throw away no-senders request */
                    755: 
                    756:        nsrequest = port->ip_nsrequest;
                    757:        if (nsrequest != IP_NULL)
                    758:                ipc_notify_send_once(nsrequest); /* consumes ref */
                    759: 
                    760:        /* destroy any queued messages */
                    761: 
                    762:        mqueue = &port->ip_messages;
                    763:        imq_lock(mqueue);
                    764:        assert(ipc_thread_queue_empty(&mqueue->imq_threads));
                    765:        kmqueue = &mqueue->imq_messages;
                    766: 
                    767:        while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
                    768:                imq_unlock(mqueue);
                    769: 
                    770:                assert(kmsg->ikm_header.msgh_remote_port ==
                    771:                                                (mach_port_t) port);
                    772: 
                    773:                ipc_port_release(port);
                    774:                kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    775:                ipc_kmsg_destroy(kmsg);
                    776: 
                    777:                imq_lock(mqueue);
                    778:        }
                    779: 
                    780:        imq_unlock(mqueue);
                    781: 
                    782:        /* generate dead-name notifications */
                    783: 
                    784:        dnrequests = port->ip_dnrequests;
                    785:        if (dnrequests != IPR_NULL) {
                    786:                ipc_table_size_t its = dnrequests->ipr_size;
                    787:                ipc_table_elems_t size = its->its_size;
                    788:                ipc_port_request_index_t index;
                    789: 
                    790:                for (index = 1; index < size; index++) {
                    791:                        ipc_port_request_t ipr = &dnrequests[index];
                    792:                        mach_port_t name = ipr->ipr_name;
                    793:                        ipc_port_t soright;
                    794: 
                    795:                        if (name == MACH_PORT_NULL)
                    796:                                continue;
                    797: 
                    798:                        soright = ipr->ipr_soright;
                    799:                        assert(soright != IP_NULL);
                    800: 
                    801: #if    MACH_IPC_COMPAT
                    802:                        if (ipr_spacep(soright)) {
                    803:                                ipc_port_delete_compat(port,
                    804:                                                ipr_space(soright), name);
                    805:                                continue;
                    806:                        }
1.1.1.2 ! root      807: #endif /* MACH_IPC_COMPAT */
1.1       root      808: 
                    809:                        ipc_notify_dead_name(soright, name);
                    810:                }
                    811: 
                    812:                it_dnrequests_free(its, dnrequests);
                    813:        }
                    814: 
                    815:        if (ip_kotype(port) != IKOT_NONE)
                    816:                ipc_kobject_destroy(port);
                    817: 
                    818:        /* Common destruction for the IPC target.  */
                    819:        ipc_target_terminate(&port->ip_target);
                    820: 
                    821:        ipc_port_release(port); /* consume caller's ref */
                    822: }
                    823: 
                    824: /*
                    825:  *     Routine:        ipc_port_check_circularity
                    826:  *     Purpose:
                    827:  *             Check if queueing "port" in a message for "dest"
                    828:  *             would create a circular group of ports and messages.
                    829:  *
                    830:  *             If no circularity (FALSE returned), then "port"
                    831:  *             is changed from "in limbo" to "in transit".
                    832:  *
                    833:  *             That is, we want to set port->ip_destination == dest,
                    834:  *             but guaranteeing that this doesn't create a circle
                    835:  *             port->ip_destination->ip_destination->... == port
                    836:  *     Conditions:
                    837:  *             No ports locked.  References held for "port" and "dest".
                    838:  */
                    839: 
                    840: boolean_t
                    841: ipc_port_check_circularity(
                    842:        ipc_port_t      port,
                    843:        ipc_port_t      dest)
                    844: {
                    845:        ipc_port_t base;
                    846: 
                    847:        assert(port != IP_NULL);
                    848:        assert(dest != IP_NULL);
                    849: 
                    850:        if (port == dest)
                    851:                return TRUE;
                    852:        base = dest;
                    853: 
                    854:        /*
                    855:         *      First try a quick check that can run in parallel.
                    856:         *      No circularity if dest is not in transit.
                    857:         */
                    858: 
                    859:        ip_lock(port);
                    860:        if (ip_lock_try(dest)) {
                    861:                if (!ip_active(dest) ||
                    862:                    (dest->ip_receiver_name != MACH_PORT_NULL) ||
                    863:                    (dest->ip_destination == IP_NULL))
                    864:                        goto not_circular;
                    865: 
                    866:                /* dest is in transit; further checking necessary */
                    867: 
                    868:                ip_unlock(dest);
                    869:        }
                    870:        ip_unlock(port);
                    871: 
                    872:        ipc_port_multiple_lock(); /* massive serialization */
                    873: 
                    874:        /*
                    875:         *      Search for the end of the chain (a port not in transit),
                    876:         *      acquiring locks along the way.
                    877:         */
                    878: 
                    879:        for (;;) {
                    880:                ip_lock(base);
                    881: 
                    882:                if (!ip_active(base) ||
                    883:                    (base->ip_receiver_name != MACH_PORT_NULL) ||
                    884:                    (base->ip_destination == IP_NULL))
                    885:                        break;
                    886: 
                    887:                base = base->ip_destination;
                    888:        }
                    889: 
                    890:        /* all ports in chain from dest to base, inclusive, are locked */
                    891: 
                    892:        if (port == base) {
                    893:                /* circularity detected! */
                    894: 
                    895:                ipc_port_multiple_unlock();
                    896: 
                    897:                /* port (== base) is in limbo */
                    898: 
                    899:                assert(ip_active(port));
                    900:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                    901:                assert(port->ip_destination == IP_NULL);
                    902: 
                    903:                while (dest != IP_NULL) {
                    904:                        ipc_port_t next;
                    905: 
                    906:                        /* dest is in transit or in limbo */
                    907: 
                    908:                        assert(ip_active(dest));
                    909:                        assert(dest->ip_receiver_name == MACH_PORT_NULL);
                    910: 
                    911:                        next = dest->ip_destination;
                    912:                        ip_unlock(dest);
                    913:                        dest = next;
                    914:                }
                    915: 
                    916:                return TRUE;
                    917:        }
                    918: 
                    919:        /*
                    920:         *      The guarantee:  lock port while the entire chain is locked.
                    921:         *      Once port is locked, we can take a reference to dest,
                    922:         *      add port to the chain, and unlock everything.
                    923:         */
                    924: 
                    925:        ip_lock(port);
                    926:        ipc_port_multiple_unlock();
                    927: 
                    928:     not_circular:
                    929: 
                    930:        /* port is in limbo */
                    931: 
                    932:        assert(ip_active(port));
                    933:        assert(port->ip_receiver_name == MACH_PORT_NULL);
                    934:        assert(port->ip_destination == IP_NULL);
                    935: 
                    936:        ip_reference(dest);
                    937:        port->ip_destination = dest;
                    938: 
                    939:        /* now unlock chain */
                    940: 
                    941:        while (port != base) {
                    942:                ipc_port_t next;
                    943: 
                    944:                /* port is in transit */
                    945: 
                    946:                assert(ip_active(port));
                    947:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                    948:                assert(port->ip_destination != IP_NULL);
                    949: 
                    950:                next = port->ip_destination;
                    951:                ip_unlock(port);
                    952:                port = next;
                    953:        }
                    954: 
                    955:        /* base is not in transit */
                    956: 
                    957:        assert(!ip_active(base) ||
                    958:               (base->ip_receiver_name != MACH_PORT_NULL) ||
                    959:               (base->ip_destination == IP_NULL));
                    960:        ip_unlock(base);
                    961: 
                    962:        return FALSE;
                    963: }
                    964: 
                    965: /*
                    966:  *     Routine:        ipc_port_lookup_notify
                    967:  *     Purpose:
                    968:  *             Make a send-once notify port from a receive right.
                    969:  *             Returns IP_NULL if name doesn't denote a receive right.
                    970:  *     Conditions:
                    971:  *             The space must be locked (read or write) and active.
                    972:  */
                    973: 
                    974: ipc_port_t
                    975: ipc_port_lookup_notify(
                    976:        ipc_space_t     space,
                    977:        mach_port_t     name)
                    978: {
                    979:        ipc_port_t port;
                    980:        ipc_entry_t entry;
                    981: 
                    982:        assert(space->is_active);
                    983: 
                    984:        entry = ipc_entry_lookup(space, name);
                    985:        if (entry == IE_NULL)
                    986:                return IP_NULL;
                    987: 
                    988:        if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
                    989:                return IP_NULL;
                    990: 
                    991:        port = (ipc_port_t) entry->ie_object;
                    992:        assert(port != IP_NULL);
                    993: 
                    994:        ip_lock(port);
                    995:        assert(ip_active(port));
                    996:        assert(port->ip_receiver_name == name);
                    997:        assert(port->ip_receiver == space);
                    998: 
                    999:        ip_reference(port);
                   1000:        port->ip_sorights++;
                   1001:        ip_unlock(port);
                   1002: 
                   1003:        return port;
                   1004: }
                   1005: 
                   1006: /*
                   1007:  *     Routine:        ipc_port_make_send
                   1008:  *     Purpose:
                   1009:  *             Make a naked send right from a receive right.
                   1010:  *     Conditions:
                   1011:  *             The port is not locked but it is active.
                   1012:  */
                   1013: 
                   1014: ipc_port_t
                   1015: ipc_port_make_send(
                   1016:        ipc_port_t      port)
                   1017: {
                   1018:        assert(IP_VALID(port));
                   1019: 
                   1020:        ip_lock(port);
                   1021:        assert(ip_active(port));
                   1022:        port->ip_mscount++;
                   1023:        port->ip_srights++;
                   1024:        ip_reference(port);
                   1025:        ip_unlock(port);
                   1026: 
                   1027:        return port;
                   1028: }
                   1029: 
                   1030: /*
                   1031:  *     Routine:        ipc_port_copy_send
                   1032:  *     Purpose:
                   1033:  *             Make a naked send right from another naked send right.
                   1034:  *                     IP_NULL         -> IP_NULL
                   1035:  *                     IP_DEAD         -> IP_DEAD
                   1036:  *                     dead port       -> IP_DEAD
                   1037:  *                     live port       -> port + ref
                   1038:  *     Conditions:
                   1039:  *             Nothing locked except possibly a space.
                   1040:  */
                   1041: 
                   1042: ipc_port_t
                   1043: ipc_port_copy_send(
                   1044:        ipc_port_t      port)
                   1045: {
                   1046:        ipc_port_t sright;
                   1047: 
                   1048:        if (!IP_VALID(port))
                   1049:                return port;
                   1050: 
                   1051:        ip_lock(port);
                   1052:        if (ip_active(port)) {
                   1053:                assert(port->ip_srights > 0);
                   1054: 
                   1055:                ip_reference(port);
                   1056:                port->ip_srights++;
                   1057:                sright = port;
                   1058:        } else
                   1059:                sright = IP_DEAD;
                   1060:        ip_unlock(port);
                   1061: 
                   1062:        return sright;
                   1063: }
                   1064: 
                   1065: /*
                   1066:  *     Routine:        ipc_port_copyout_send
                   1067:  *     Purpose:
                   1068:  *             Copyout a naked send right (possibly null/dead),
                   1069:  *             or if that fails, destroy the right.
                   1070:  *     Conditions:
                   1071:  *             Nothing locked.
                   1072:  */
                   1073: 
                   1074: mach_port_t
                   1075: ipc_port_copyout_send(
                   1076:        ipc_port_t      sright,
                   1077:        ipc_space_t     space)
                   1078: {
                   1079:        mach_port_t name;
                   1080: 
                   1081:        if (IP_VALID(sright)) {
                   1082:                kern_return_t kr;
                   1083: 
                   1084:                kr = ipc_object_copyout(space, (ipc_object_t) sright,
                   1085:                                        MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
                   1086:                if (kr != KERN_SUCCESS) {
                   1087:                        ipc_port_release_send(sright);
                   1088: 
                   1089:                        if (kr == KERN_INVALID_CAPABILITY)
                   1090:                                name = MACH_PORT_DEAD;
                   1091:                        else
                   1092:                                name = MACH_PORT_NULL;
                   1093:                }
                   1094:        } else
                   1095:                name = (mach_port_t) sright;
                   1096: 
                   1097:        return name;
                   1098: }
                   1099: 
                   1100: /*
                   1101:  *     Routine:        ipc_port_release_send
                   1102:  *     Purpose:
                   1103:  *             Release a (valid) naked send right.
                   1104:  *             Consumes a ref for the port.
                   1105:  *     Conditions:
                   1106:  *             Nothing locked.
                   1107:  */
                   1108: 
                   1109: void
                   1110: ipc_port_release_send(
                   1111:        ipc_port_t      port)
                   1112: {
                   1113:        ipc_port_t nsrequest = IP_NULL;
                   1114:        mach_port_mscount_t mscount;
                   1115: 
                   1116:        assert(IP_VALID(port));
                   1117: 
                   1118:        ip_lock(port);
                   1119:        ip_release(port);
                   1120: 
                   1121:        if (!ip_active(port)) {
                   1122:                ip_check_unlock(port);
                   1123:                return;
                   1124:        }
                   1125: 
                   1126:        assert(port->ip_srights > 0);
                   1127: 
                   1128:        if (--port->ip_srights == 0) {
                   1129:                nsrequest = port->ip_nsrequest;
                   1130:                if (nsrequest != IP_NULL) {
                   1131:                        port->ip_nsrequest = IP_NULL;
                   1132:                        mscount = port->ip_mscount;
                   1133:                }
                   1134:        }
                   1135: 
                   1136:        ip_unlock(port);
                   1137: 
                   1138:        if (nsrequest != IP_NULL)
                   1139:                ipc_notify_no_senders(nsrequest, mscount);
                   1140: }
                   1141: 
                   1142: /*
                   1143:  *     Routine:        ipc_port_make_sonce
                   1144:  *     Purpose:
                   1145:  *             Make a naked send-once right from a receive right.
                   1146:  *     Conditions:
                   1147:  *             The port is not locked but it is active.
                   1148:  */
                   1149: 
                   1150: ipc_port_t
                   1151: ipc_port_make_sonce(
                   1152:        ipc_port_t      port)
                   1153: {
                   1154:        assert(IP_VALID(port));
                   1155: 
                   1156:        ip_lock(port);
                   1157:        assert(ip_active(port));
                   1158:        port->ip_sorights++;
                   1159:        ip_reference(port);
                   1160:        ip_unlock(port);
                   1161: 
                   1162:        return port;
                   1163: }
                   1164: 
                   1165: /*
                   1166:  *     Routine:        ipc_port_release_sonce
                   1167:  *     Purpose:
                   1168:  *             Release a naked send-once right.
                   1169:  *             Consumes a ref for the port.
                   1170:  *
                   1171:  *             In normal situations, this is never used.
                   1172:  *             Send-once rights are only consumed when
                   1173:  *             a message (possibly a send-once notification)
                   1174:  *             is sent to them.
                   1175:  *     Conditions:
                   1176:  *             Nothing locked except possibly a space.
                   1177:  */
                   1178: 
                   1179: void
                   1180: ipc_port_release_sonce(
                   1181:        ipc_port_t      port)
                   1182: {
                   1183:        assert(IP_VALID(port));
                   1184: 
                   1185:        ip_lock(port);
                   1186: 
                   1187:        assert(port->ip_sorights > 0);
                   1188: 
                   1189:        port->ip_sorights--;
                   1190: 
                   1191:        ip_release(port);
                   1192: 
                   1193:        if (!ip_active(port)) {
                   1194:                ip_check_unlock(port);
                   1195:                return;
                   1196:        }
                   1197: 
                   1198:        ip_unlock(port);
                   1199: }
                   1200: 
                   1201: /*
                   1202:  *     Routine:        ipc_port_release_receive
                   1203:  *     Purpose:
                   1204:  *             Release a naked (in limbo or in transit) receive right.
                   1205:  *             Consumes a ref for the port; destroys the port.
                   1206:  *     Conditions:
                   1207:  *             Nothing locked.
                   1208:  */
                   1209: 
                   1210: void
                   1211: ipc_port_release_receive(
                   1212:        ipc_port_t      port)
                   1213: {
                   1214:        ipc_port_t dest;
                   1215: 
                   1216:        assert(IP_VALID(port));
                   1217: 
                   1218:        ip_lock(port);
                   1219:        assert(ip_active(port));
                   1220:        assert(port->ip_receiver_name == MACH_PORT_NULL);
                   1221:        dest = port->ip_destination;
                   1222: 
                   1223:        ipc_port_destroy(port); /* consumes ref, unlocks */
                   1224: 
                   1225:        if (dest != IP_NULL)
                   1226:                ipc_port_release(dest);
                   1227: }
                   1228: 
                   1229: /*
                   1230:  *     Routine:        ipc_port_alloc_special
                   1231:  *     Purpose:
                   1232:  *             Allocate a port in a special space.
                   1233:  *             The new port is returned with one ref.
                   1234:  *             If unsuccessful, IP_NULL is returned.
                   1235:  *     Conditions:
                   1236:  *             Nothing locked.
                   1237:  */
                   1238: 
                   1239: ipc_port_t
                   1240: ipc_port_alloc_special(space)
                   1241:        ipc_space_t space;
                   1242: {
                   1243: #if    NORMA_IPC
                   1244: #if    i386
                   1245:        int ret = (&ret)[2];    /* where we were called from */
                   1246: #else
                   1247:        int ret = (int) ipc_port_alloc_special;
                   1248: #endif
                   1249:        extern int input_msgh_id;
1.1.1.2 ! root     1250: #endif /* NORMA_IPC */
1.1       root     1251:        ipc_port_t port;
                   1252: 
                   1253:        port = (ipc_port_t) io_alloc(IOT_PORT);
                   1254:        if (port == IP_NULL)
                   1255:                return IP_NULL;
                   1256: 
                   1257:        io_lock_init(&port->ip_object);
                   1258:        port->ip_references = 1;
                   1259:        port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
                   1260: 
                   1261:        /*
                   1262:         *      The actual values of ip_receiver_name aren't important,
                   1263:         *      as long as they are valid (not null/dead).
                   1264:         *
                   1265:         *      Mach4: we set it to the internal port structure address
                   1266:         *      so we can always just pass on ip_receiver_name during
                   1267:         *      an rpc regardless of whether the destination is user or
                   1268:         *      kernel (i.e. no special-casing code for the kernel along
                   1269:         *      the fast rpc path).
                   1270:         */
                   1271: 
                   1272:        ipc_port_init(port, space, (mach_port_t)port);
                   1273: 
                   1274: #if    NORMA_IPC
                   1275:        port->ip_norma_spare1 = ret;
                   1276:        port->ip_norma_spare2 = input_msgh_id;
1.1.1.2 ! root     1277: #endif /* NORMA_IPC */
1.1       root     1278:        return port;
                   1279: }
                   1280: 
                   1281: /*
                   1282:  *     Routine:        ipc_port_dealloc_special
                   1283:  *     Purpose:
                   1284:  *             Deallocate a port in a special space.
                   1285:  *             Consumes one ref for the port.
                   1286:  *     Conditions:
                   1287:  *             Nothing locked.
                   1288:  */
                   1289: 
                   1290: void
                   1291: ipc_port_dealloc_special(
                   1292:        ipc_port_t      port,
                   1293:        ipc_space_t     space)
                   1294: {
                   1295:        ip_lock(port);
                   1296:        assert(ip_active(port));
                   1297:        assert(port->ip_receiver_name != MACH_PORT_NULL);
                   1298:        assert(port->ip_receiver == space);
                   1299: 
                   1300:        /*
                   1301:         *      We clear ip_receiver_name and ip_receiver to simplify
                   1302:         *      the ipc_space_kernel check in ipc_mqueue_send.
                   1303:         */
                   1304: 
                   1305:        port->ip_receiver_name = MACH_PORT_NULL;
                   1306:        port->ip_receiver = IS_NULL;
                   1307: 
                   1308:        /*
                   1309:         *      For ipc_space_kernel, all ipc_port_clear_receiver does
                   1310:         *      is clean things up for the assertions in ipc_port_destroy.
                   1311:         *      For ipc_space_reply, there might be a waiting receiver.
                   1312:         */
                   1313: 
                   1314:        ipc_port_clear_receiver(port);
                   1315:        ipc_port_destroy(port);
                   1316: }
                   1317: 
                   1318: #if    MACH_IPC_COMPAT
                   1319: 
                   1320: /*
                   1321:  *     Routine:        ipc_port_alloc_compat
                   1322:  *     Purpose:
                   1323:  *             Allocate a port.
                   1324:  *     Conditions:
                   1325:  *             Nothing locked.  If successful, the port is returned
                   1326:  *             locked.  (The caller doesn't have a reference.)
                   1327:  *
                   1328:  *             Like ipc_port_alloc, except that the new entry
                   1329:  *             is IE_BITS_COMPAT.
                   1330:  *     Returns:
                   1331:  *             KERN_SUCCESS            The port is allocated.
                   1332:  *             KERN_INVALID_TASK       The space is dead.
                   1333:  *             KERN_NO_SPACE           No room for an entry in the space.
                   1334:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1335:  */
                   1336: 
                   1337: kern_return_t
                   1338: ipc_port_alloc_compat(space, namep, portp)
                   1339:        ipc_space_t space;
                   1340:        mach_port_t *namep;
                   1341:        ipc_port_t *portp;
                   1342: {
                   1343:        ipc_port_t port;
                   1344:        ipc_entry_t entry;
                   1345:        mach_port_t name;
                   1346:        ipc_table_size_t its;
                   1347:        ipc_port_request_t table;
                   1348:        ipc_table_elems_t size;
                   1349:        ipc_port_request_index_t free, i;
                   1350:        kern_return_t kr;
                   1351: 
                   1352:        port = ip_alloc();
                   1353:        if (port == IP_NULL)
                   1354:                return KERN_RESOURCE_SHORTAGE;
                   1355: 
                   1356:        its = &ipc_table_dnrequests[0];
                   1357:        table = it_dnrequests_alloc(its);
                   1358:        if (table == IPR_NULL) {
                   1359:                ip_free(port);
                   1360:                return KERN_RESOURCE_SHORTAGE;
                   1361:        }
                   1362: 
                   1363:        kr = ipc_entry_alloc(space, &name, &entry);
                   1364:        if (kr != KERN_SUCCESS) {
                   1365:                ip_free(port);
                   1366:                it_dnrequests_free(its, table);
                   1367:                return kr;
                   1368:        }
                   1369:        /* space is write-locked */
                   1370: 
                   1371:        entry->ie_object = (ipc_object_t) port;
                   1372:        entry->ie_request = 1;
                   1373:        entry->ie_bits |= IE_BITS_COMPAT|MACH_PORT_TYPE_RECEIVE;
                   1374: 
                   1375:        ip_lock_init(port);
                   1376:        ip_lock(port);
                   1377:        is_write_unlock(space);
                   1378: 
                   1379:        port->ip_references = 1; /* for entry, not caller */
                   1380:        port->ip_bits = io_makebits(TRUE, IOT_PORT, 0);
                   1381: 
                   1382:        ipc_port_init(port, space, name);
                   1383: 
                   1384:        size = its->its_size;
                   1385:        assert(size > 1);
                   1386:        free = 0;
                   1387: 
                   1388:        for (i = 2; i < size; i++) {
                   1389:                ipc_port_request_t ipr = &table[i];
                   1390: 
                   1391:                ipr->ipr_name = MACH_PORT_NULL;
                   1392:                ipr->ipr_next = free;
                   1393:                free = i;
                   1394:        }
                   1395: 
                   1396:        table->ipr_next = free;
                   1397:        table->ipr_size = its;
                   1398:        port->ip_dnrequests = table;
                   1399: 
                   1400:        table[1].ipr_name = name;
                   1401:        table[1].ipr_soright = ipr_spacem(space);
                   1402:        is_reference(space);
                   1403: 
                   1404:        *namep = name;
                   1405:        *portp = port;
                   1406:        return KERN_SUCCESS;
                   1407: }
                   1408: 
                   1409: /*
                   1410:  *     Routine:        ipc_port_copyout_send_compat
                   1411:  *     Purpose:
                   1412:  *             Copyout a naked send right (possibly null/dead),
                   1413:  *             or if that fails, destroy the right.
                   1414:  *             Like ipc_port_copyout_send, except that if a
                   1415:  *             new translation is created it has the compat bit.
                   1416:  *     Conditions:
                   1417:  *             Nothing locked.
                   1418:  */
                   1419: 
                   1420: mach_port_t
                   1421: ipc_port_copyout_send_compat(sright, space)
                   1422:        ipc_port_t sright;
                   1423:        ipc_space_t space;
                   1424: {
                   1425:        mach_port_t name;
                   1426: 
                   1427:        if (IP_VALID(sright)) {
                   1428:                kern_return_t kr;
                   1429: 
                   1430:                kr = ipc_object_copyout_compat(space, (ipc_object_t) sright,
                   1431:                                               MACH_MSG_TYPE_PORT_SEND, &name);
                   1432:                if (kr != KERN_SUCCESS) {
                   1433:                        ipc_port_release_send(sright);
                   1434:                        name = MACH_PORT_NULL;
                   1435:                }
                   1436:        } else
                   1437:                name = (mach_port_t) sright;
                   1438: 
                   1439:        return name;
                   1440: }
                   1441: 
                   1442: /*
                   1443:  *     Routine:        ipc_port_copyout_receiver
                   1444:  *     Purpose:
                   1445:  *             Copyout a port reference (possibly null)
                   1446:  *             by giving the caller his name for the port,
                   1447:  *             if he is the receiver.
                   1448:  *     Conditions:
                   1449:  *             Nothing locked.  Consumes a ref for the port.
                   1450:  */
                   1451: 
                   1452: mach_port_t
                   1453: ipc_port_copyout_receiver(port, space)
                   1454:        ipc_port_t port;
                   1455:        ipc_space_t space;
                   1456: {
                   1457:        mach_port_t name;
                   1458: 
                   1459:        if (!IP_VALID(port))
                   1460:                return MACH_PORT_NULL;
                   1461: 
                   1462:        ip_lock(port);
                   1463:        if (port->ip_receiver == space) {
                   1464:                name = port->ip_receiver_name;
                   1465:                assert(MACH_PORT_VALID(name));
                   1466:        } else
                   1467:                name = MACH_PORT_NULL;
                   1468: 
                   1469:        ip_release(port);
                   1470:        ip_check_unlock(port);
                   1471: 
                   1472:        return name;
                   1473: }
                   1474: 
1.1.1.2 ! root     1475: #endif /* MACH_IPC_COMPAT */
1.1       root     1476: 
                   1477: #include <mach_kdb.h>
                   1478: 
                   1479: 
                   1480: #if    MACH_KDB
                   1481: #define        printf  kdbprintf
                   1482: 
                   1483: /*
                   1484:  *     Routine:        ipc_port_print
                   1485:  *     Purpose:
                   1486:  *             Pretty-print a port for kdb.
                   1487:  */
                   1488: 
                   1489: void
                   1490: ipc_port_print(port)
                   1491:        ipc_port_t port;
                   1492: {
                   1493:        extern int indent;
                   1494: 
                   1495:        printf("port 0x%x\n", port);
                   1496: 
                   1497:        indent += 2;
                   1498: 
                   1499:        ipc_object_print(&port->ip_object);
                   1500:        iprintf("receiver=0x%x", port->ip_receiver);
                   1501:        printf(", receiver_name=0x%x\n", port->ip_receiver_name);
                   1502: 
                   1503:        iprintf("mscount=%d", port->ip_mscount);
                   1504:        printf(", srights=%d", port->ip_srights);
                   1505:        printf(", sorights=%d\n", port->ip_sorights);
                   1506: 
                   1507:        iprintf("nsrequest=0x%x", port->ip_nsrequest);
                   1508:        printf(", pdrequest=0x%x", port->ip_pdrequest);
                   1509:        printf(", dnrequests=0x%x\n", port->ip_dnrequests);
                   1510: 
                   1511:        iprintf("pset=0x%x", port->ip_pset);
                   1512:        printf(", seqno=%d", port->ip_seqno);
                   1513:        printf(", msgcount=%d", port->ip_msgcount);
                   1514:        printf(", qlimit=%d\n", port->ip_qlimit);
                   1515: 
                   1516:        iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
                   1517:        printf(", rcvrs=0x%x", port->ip_messages.imq_threads.ithq_base);
                   1518:        printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
                   1519:        printf(", kobj=0x%x\n", port->ip_kobject);
                   1520: 
                   1521: #if    NORMA_IPC
                   1522:        iprintf("norma_uid=%x", port->ip_norma_uid);
                   1523:        printf(", dest_node=%d", port->ip_norma_dest_node);
                   1524:        printf(", stransit=%d", port->ip_norma_stransit);
                   1525:        printf(", xorefs=%d", port->ip_norma_xmm_object_refs);
                   1526:        printf(", sotransit=%d\n", port->ip_norma_sotransit);
                   1527: 
                   1528:        iprintf("norma_is_proxy=%d", port->ip_norma_is_proxy);
                   1529:        printf(", is_special=%d\n", port->ip_norma_is_special);
                   1530: 
                   1531:        iprintf("norma_atrium=0x%x", port->ip_norma_atrium);
                   1532:        printf(", queue_next=0x%x", port->ip_norma_queue_next);
                   1533:        printf(", xmm_object=0x%x", port->ip_norma_xmm_object);
                   1534:        printf(", next=0x%x\n", port->ip_norma_next);
                   1535: 
                   1536:        iprintf("norma_spare1=0x%x", port->ip_norma_spare1);
                   1537:        printf(", norma_spare2=0x%x", port->ip_norma_spare2);
                   1538:        printf(", norma_spare3=0x%x", port->ip_norma_spare3);
                   1539:        printf(", norma_spare4=0x%x\n", port->ip_norma_spare4);
1.1.1.2 ! root     1540: #endif /* NORMA_IPC */
1.1       root     1541: 
                   1542:        indent -=2;
                   1543: }
                   1544: 
1.1.1.2 ! root     1545: #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.