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

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: 
1.1.1.3 ! root       37: #include <kern/printf.h>
        !            38: #include <string.h>
1.1       root       39: 
                     40: #include <mach/port.h>
                     41: #include <mach/kern_return.h>
                     42: #include <kern/lock.h>
                     43: #include <kern/ipc_sched.h>
                     44: #include <kern/ipc_kobject.h>
                     45: #include <ipc/ipc_entry.h>
                     46: #include <ipc/ipc_space.h>
                     47: #include <ipc/ipc_object.h>
                     48: #include <ipc/ipc_port.h>
                     49: #include <ipc/ipc_pset.h>
                     50: #include <ipc/ipc_thread.h>
                     51: #include <ipc/ipc_mqueue.h>
                     52: #include <ipc/ipc_notify.h>
                     53: 
1.1.1.3 ! root       54: #if    MACH_KDB
        !            55: #include <ddb/db_output.h>
        !            56: #include <ipc/ipc_print.h>
        !            57: #endif /* MACH_KDB */
1.1       root       58: 
                     59: 
                     60: decl_simple_lock_data(, ipc_port_multiple_lock_data)
                     61: 
                     62: decl_simple_lock_data(, ipc_port_timestamp_lock_data)
                     63: ipc_port_timestamp_t ipc_port_timestamp_data;
                     64: 
                     65: /*
                     66:  *     Routine:        ipc_port_timestamp
                     67:  *     Purpose:
                     68:  *             Retrieve a timestamp value.
                     69:  */
                     70: 
                     71: ipc_port_timestamp_t
                     72: ipc_port_timestamp(void)
                     73: {
                     74:        ipc_port_timestamp_t timestamp;
                     75: 
                     76:        ipc_port_timestamp_lock();
                     77:        timestamp = ipc_port_timestamp_data++;
                     78:        ipc_port_timestamp_unlock();
                     79: 
                     80:        return timestamp;
                     81: }
                     82: 
                     83: /*
                     84:  *     Routine:        ipc_port_dnrequest
                     85:  *     Purpose:
                     86:  *             Try to allocate a dead-name request slot.
                     87:  *             If successful, returns the request index.
                     88:  *             Otherwise returns zero.
                     89:  *     Conditions:
                     90:  *             The port is locked and active.
                     91:  *     Returns:
                     92:  *             KERN_SUCCESS            A request index was found.
                     93:  *             KERN_NO_SPACE           No index allocated.
                     94:  */
                     95: 
                     96: kern_return_t
                     97: ipc_port_dnrequest(port, name, soright, indexp)
                     98:        ipc_port_t port;
                     99:        mach_port_t name;
                    100:        ipc_port_t soright;
                    101:        ipc_port_request_index_t *indexp;
                    102: {
                    103:        ipc_port_request_t ipr, table;
                    104:        ipc_port_request_index_t index;
                    105: 
                    106:        assert(ip_active(port));
                    107:        assert(name != MACH_PORT_NULL);
                    108:        assert(soright != IP_NULL);
                    109: 
                    110:        table = port->ip_dnrequests;
                    111:        if (table == IPR_NULL)
                    112:                return KERN_NO_SPACE;
                    113: 
                    114:        index = table->ipr_next;
                    115:        if (index == 0)
                    116:                return KERN_NO_SPACE;
                    117: 
                    118:        ipr = &table[index];
                    119:        assert(ipr->ipr_name == MACH_PORT_NULL);
                    120: 
                    121:        table->ipr_next = ipr->ipr_next;
                    122:        ipr->ipr_name = name;
                    123:        ipr->ipr_soright = soright;
                    124: 
                    125:        *indexp = index;
                    126:        return KERN_SUCCESS;
                    127: }
                    128: 
                    129: /*
                    130:  *     Routine:        ipc_port_dngrow
                    131:  *     Purpose:
                    132:  *             Grow a port's table of dead-name requests.
                    133:  *     Conditions:
                    134:  *             The port must be locked and active.
                    135:  *             Nothing else locked; will allocate memory.
                    136:  *             Upon return the port is unlocked.
                    137:  *     Returns:
                    138:  *             KERN_SUCCESS            Grew the table.
                    139:  *             KERN_SUCCESS            Somebody else grew the table.
                    140:  *             KERN_SUCCESS            The port died.
                    141:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate new table.
                    142:  */
                    143: 
                    144: kern_return_t
                    145: ipc_port_dngrow(port)
                    146:        ipc_port_t port;
                    147: {
                    148:        ipc_table_size_t its;
                    149:        ipc_port_request_t otable, ntable;
                    150: 
                    151:        assert(ip_active(port));
                    152: 
                    153:        otable = port->ip_dnrequests;
                    154:        if (otable == IPR_NULL)
                    155:                its = &ipc_table_dnrequests[0];
                    156:        else
                    157:                its = otable->ipr_size + 1;
                    158: 
                    159:        ip_reference(port);
                    160:        ip_unlock(port);
                    161: 
                    162:        if ((its->its_size == 0) ||
                    163:            ((ntable = it_dnrequests_alloc(its)) == IPR_NULL)) {
                    164:                ipc_port_release(port);
                    165:                return KERN_RESOURCE_SHORTAGE;
                    166:        }
                    167: 
                    168:        ip_lock(port);
                    169:        ip_release(port);
                    170: 
                    171:        /*
                    172:         *      Check that port is still active and that nobody else
                    173:         *      has slipped in and grown the table on us.  Note that
                    174:         *      just checking port->ip_dnrequests == otable isn't
                    175:         *      sufficient; must check ipr_size.
                    176:         */
                    177: 
                    178:        if (ip_active(port) &&
                    179:            (port->ip_dnrequests == otable) &&
                    180:            ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) {
                    181:                ipc_table_size_t oits = 0; /* '=0' to shut up lint */
                    182:                ipc_table_elems_t osize, nsize;
                    183:                ipc_port_request_index_t free, i;
                    184: 
                    185:                /* copy old table to new table */
                    186: 
                    187:                if (otable != IPR_NULL) {
                    188:                        oits = otable->ipr_size;
                    189:                        osize = oits->its_size;
                    190:                        free = otable->ipr_next;
                    191: 
1.1.1.3 ! root      192:                        memcpy((ntable + 1), (otable + 1), 
1.1       root      193:                              (osize - 1) * sizeof(struct ipc_port_request));
                    194:                } else {
                    195:                        osize = 1;
                    196:                        free = 0;
                    197:                }
                    198: 
                    199:                nsize = its->its_size;
                    200:                assert(nsize > osize);
                    201: 
                    202:                /* add new elements to the new table's free list */
                    203: 
                    204:                for (i = osize; i < nsize; i++) {
                    205:                        ipc_port_request_t ipr = &ntable[i];
                    206: 
                    207:                        ipr->ipr_name = MACH_PORT_NULL;
                    208:                        ipr->ipr_next = free;
                    209:                        free = i;
                    210:                }
                    211: 
                    212:                ntable->ipr_next = free;
                    213:                ntable->ipr_size = its;
                    214:                port->ip_dnrequests = ntable;
                    215:                ip_unlock(port);
                    216: 
                    217:                if (otable != IPR_NULL)
                    218:                        it_dnrequests_free(oits, otable);
                    219:        } else {
                    220:                ip_check_unlock(port);
                    221:                it_dnrequests_free(its, ntable);
                    222:        }
                    223: 
                    224:        return KERN_SUCCESS;
                    225: }
1.1.1.2   root      226: 
1.1       root      227: /*
                    228:  *     Routine:        ipc_port_dncancel
                    229:  *     Purpose:
                    230:  *             Cancel a dead-name request and return the send-once right.
                    231:  *     Conditions:
                    232:  *             The port must locked and active.
                    233:  */
                    234: 
                    235: ipc_port_t
                    236: ipc_port_dncancel(
                    237:        ipc_port_t                      port,
                    238:        mach_port_t                     name,
                    239:        ipc_port_request_index_t        index)
                    240: {
                    241:        ipc_port_request_t ipr, table;
                    242:        ipc_port_t dnrequest;
                    243: 
                    244:        assert(ip_active(port));
                    245:        assert(name != MACH_PORT_NULL);
                    246:        assert(index != 0);
                    247: 
                    248:        table = port->ip_dnrequests;
                    249:        assert(table != IPR_NULL);
                    250: 
                    251:        ipr = &table[index];
                    252:        dnrequest = ipr->ipr_soright;
                    253:        assert(ipr->ipr_name == name);
                    254: 
                    255:        /* return ipr to the free list inside the table */
                    256: 
                    257:        ipr->ipr_name = MACH_PORT_NULL;
                    258:        ipr->ipr_next = table->ipr_next;
                    259:        table->ipr_next = index;
                    260: 
                    261:        return dnrequest;
                    262: }
                    263: 
                    264: /*
                    265:  *     Routine:        ipc_port_pdrequest
                    266:  *     Purpose:
                    267:  *             Make a port-deleted request, returning the
                    268:  *             previously registered send-once right.
                    269:  *             Just cancels the previous request if notify is IP_NULL.
                    270:  *     Conditions:
                    271:  *             The port is locked and active.  It is unlocked.
                    272:  *             Consumes a ref for notify (if non-null), and
                    273:  *             returns previous with a ref (if non-null).
                    274:  */
                    275: 
                    276: void
                    277: ipc_port_pdrequest(
                    278:        ipc_port_t      port,
                    279:        ipc_port_t      notify,
                    280:        ipc_port_t      *previousp)
                    281: {
                    282:        ipc_port_t previous;
                    283: 
                    284:        assert(ip_active(port));
                    285: 
                    286:        previous = port->ip_pdrequest;
                    287:        port->ip_pdrequest = notify;
                    288:        ip_unlock(port);
                    289: 
                    290:        *previousp = previous;
                    291: }
                    292: 
                    293: /*
                    294:  *     Routine:        ipc_port_nsrequest
                    295:  *     Purpose:
                    296:  *             Make a no-senders request, returning the
                    297:  *             previously registered send-once right.
                    298:  *             Just cancels the previous request if notify is IP_NULL.
                    299:  *     Conditions:
                    300:  *             The port is locked and active.  It is unlocked.
                    301:  *             Consumes a ref for notify (if non-null), and
                    302:  *             returns previous with a ref (if non-null).
                    303:  */
                    304: 
                    305: void
                    306: ipc_port_nsrequest(
                    307:        ipc_port_t              port,
                    308:        mach_port_mscount_t     sync,
                    309:        ipc_port_t              notify,
                    310:        ipc_port_t              *previousp)
                    311: {
                    312:        ipc_port_t previous;
                    313:        mach_port_mscount_t mscount;
                    314: 
                    315:        assert(ip_active(port));
                    316: 
                    317:        previous = port->ip_nsrequest;
                    318:        mscount = port->ip_mscount;
                    319: 
                    320:        if ((port->ip_srights == 0) &&
                    321:            (sync <= mscount) &&
                    322:            (notify != IP_NULL)) {
                    323:                port->ip_nsrequest = IP_NULL;
                    324:                ip_unlock(port);
                    325:                ipc_notify_no_senders(notify, mscount);
                    326:        } else {
                    327:                port->ip_nsrequest = notify;
                    328:                ip_unlock(port);
                    329:        }
                    330: 
                    331:        *previousp = previous;
                    332: }
                    333: 
                    334: /*
                    335:  *     Routine:        ipc_port_set_qlimit
                    336:  *     Purpose:
                    337:  *             Changes a port's queue limit; the maximum number
                    338:  *             of messages which may be queued to the port.
                    339:  *     Conditions:
                    340:  *             The port is locked and active.
                    341:  */
                    342: 
                    343: void
                    344: ipc_port_set_qlimit(
                    345:        ipc_port_t              port,
                    346:        mach_port_msgcount_t    qlimit)
                    347: {
                    348:        assert(ip_active(port));
                    349: 
                    350:        /* wake up senders allowed by the new qlimit */
                    351: 
                    352:        if (qlimit > port->ip_qlimit) {
                    353:                mach_port_msgcount_t i, wakeup;
                    354: 
                    355:                /* caution: wakeup, qlimit are unsigned */
                    356: 
                    357:                wakeup = qlimit - port->ip_qlimit;
                    358: 
                    359:                for (i = 0; i < wakeup; i++) {
                    360:                        ipc_thread_t th;
                    361: 
                    362:                        th = ipc_thread_dequeue(&port->ip_blocked);
                    363:                        if (th == ITH_NULL)
                    364:                                break;
                    365: 
                    366:                        th->ith_state = MACH_MSG_SUCCESS;
                    367:                        thread_go(th);
                    368:                }
                    369:        }
                    370: 
                    371:        port->ip_qlimit = qlimit;
                    372: }
                    373: 
                    374: /*
                    375:  *     Routine:        ipc_port_lock_mqueue
                    376:  *     Purpose:
                    377:  *             Locks and returns the message queue that the port is using.
                    378:  *             The message queue may be in the port or in its port set.
                    379:  *     Conditions:
                    380:  *             The port is locked and active.
                    381:  *             Port set, message queue locks may be taken.
                    382:  */
                    383: 
                    384: ipc_mqueue_t
                    385: ipc_port_lock_mqueue(port)
                    386:        ipc_port_t port;
                    387: {
                    388:        if (port->ip_pset != IPS_NULL) {
                    389:                ipc_pset_t pset = port->ip_pset;
                    390: 
                    391:                ips_lock(pset);
                    392:                if (ips_active(pset)) {
                    393:                        imq_lock(&pset->ips_messages);
                    394:                        ips_unlock(pset);
                    395:                        return &pset->ips_messages;
                    396:                }
                    397: 
                    398:                ipc_pset_remove(pset, port);
                    399:                ips_check_unlock(pset);
                    400:        }
                    401: 
                    402:        imq_lock(&port->ip_messages);
                    403:        return &port->ip_messages;
                    404: }
                    405: 
                    406: /*
                    407:  *     Routine:        ipc_port_set_seqno
                    408:  *     Purpose:
                    409:  *             Changes a port's sequence number.
                    410:  *     Conditions:
                    411:  *             The port is locked and active.
                    412:  *             Port set, message queue locks may be taken.
                    413:  */
                    414: 
                    415: void
                    416: ipc_port_set_seqno(port, seqno)
                    417:        ipc_port_t port;
                    418:        mach_port_seqno_t seqno;
                    419: {
                    420:        ipc_mqueue_t mqueue;
                    421: 
                    422:        mqueue = ipc_port_lock_mqueue(port);
                    423:        port->ip_seqno = seqno;
                    424:        imq_unlock(mqueue);
                    425: }
                    426: 
                    427: /*
                    428:  *     Routine:        ipc_port_clear_receiver
                    429:  *     Purpose:
                    430:  *             Prepares a receive right for transmission/destruction.
                    431:  *     Conditions:
                    432:  *             The port is locked and active.
                    433:  */
                    434: 
                    435: void
                    436: ipc_port_clear_receiver(
                    437:        ipc_port_t      port)
                    438: {
                    439:        ipc_pset_t pset;
                    440: 
                    441:        assert(ip_active(port));
                    442: 
                    443:        pset = port->ip_pset;
                    444:        if (pset != IPS_NULL) {
                    445:                /* No threads receiving from port, but must remove from set. */
                    446: 
                    447:                ips_lock(pset);
                    448:                ipc_pset_remove(pset, port);
                    449:                ips_check_unlock(pset);
                    450:        } else {
                    451:                /* Else, wake up all receivers, indicating why. */
                    452: 
                    453:                imq_lock(&port->ip_messages);
                    454:                ipc_mqueue_changed(&port->ip_messages, MACH_RCV_PORT_DIED);
                    455:                imq_unlock(&port->ip_messages);
                    456:        }
                    457: 
                    458:        ipc_port_set_mscount(port, 0);
                    459:        imq_lock(&port->ip_messages);
                    460:        port->ip_seqno = 0;
                    461:        imq_unlock(&port->ip_messages);
                    462: }
                    463: 
                    464: /*
                    465:  *     Routine:        ipc_port_init
                    466:  *     Purpose:
                    467:  *             Initializes a newly-allocated port.
                    468:  *             Doesn't touch the ip_object fields.
                    469:  */
                    470: 
                    471: void
                    472: ipc_port_init(
                    473:        ipc_port_t      port,
                    474:        ipc_space_t     space,
                    475:        mach_port_t     name)
                    476: {
                    477:        /* port->ip_kobject doesn't have to be initialized */
                    478: 
                    479:        ipc_target_init(&port->ip_target, name);
                    480: 
                    481:        port->ip_receiver = space;
                    482: 
                    483:        port->ip_mscount = 0;
                    484:        port->ip_srights = 0;
                    485:        port->ip_sorights = 0;
                    486: 
                    487:        port->ip_nsrequest = IP_NULL;
                    488:        port->ip_pdrequest = IP_NULL;
                    489:        port->ip_dnrequests = IPR_NULL;
                    490: 
                    491:        port->ip_pset = IPS_NULL;
                    492:        port->ip_cur_target = &port->ip_target;
                    493:        port->ip_seqno = 0;
                    494:        port->ip_msgcount = 0;
                    495:        port->ip_qlimit = MACH_PORT_QLIMIT_DEFAULT;
                    496: 
                    497:        ipc_mqueue_init(&port->ip_messages);
                    498:        ipc_thread_queue_init(&port->ip_blocked);
                    499: }
                    500: 
                    501: /*
                    502:  *     Routine:        ipc_port_alloc
                    503:  *     Purpose:
                    504:  *             Allocate a port.
                    505:  *     Conditions:
                    506:  *             Nothing locked.  If successful, the port is returned
                    507:  *             locked.  (The caller doesn't have a reference.)
                    508:  *     Returns:
                    509:  *             KERN_SUCCESS            The port is allocated.
                    510:  *             KERN_INVALID_TASK       The space is dead.
                    511:  *             KERN_NO_SPACE           No room for an entry in the space.
                    512:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    513:  */
                    514: 
                    515: kern_return_t
                    516: ipc_port_alloc(
                    517:        ipc_space_t     space,
                    518:        mach_port_t     *namep,
                    519:        ipc_port_t      *portp)
                    520: {
                    521:        ipc_port_t port;
                    522:        mach_port_t name;
                    523:        kern_return_t kr;
                    524: 
                    525:        kr = ipc_object_alloc(space, IOT_PORT,
                    526:                              MACH_PORT_TYPE_RECEIVE, 0,
                    527:                              &name, (ipc_object_t *) &port);
                    528:        if (kr != KERN_SUCCESS)
                    529:                return kr;
                    530: 
                    531:        /* port is locked */
                    532: 
                    533:        ipc_port_init(port, space, name);
                    534: 
                    535:        *namep = name;
                    536:        *portp = port;
                    537: 
                    538:        return KERN_SUCCESS;
                    539: }
                    540: 
                    541: /*
                    542:  *     Routine:        ipc_port_alloc_name
                    543:  *     Purpose:
                    544:  *             Allocate a port, with a specific name.
                    545:  *     Conditions:
                    546:  *             Nothing locked.  If successful, the port is returned
                    547:  *             locked.  (The caller doesn't have a reference.)
                    548:  *     Returns:
                    549:  *             KERN_SUCCESS            The port is allocated.
                    550:  *             KERN_INVALID_TASK       The space is dead.
                    551:  *             KERN_NAME_EXISTS        The name already denotes a right.
                    552:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    553:  */
                    554: 
                    555: kern_return_t
                    556: ipc_port_alloc_name(
                    557:        ipc_space_t     space,
                    558:        mach_port_t     name,
                    559:        ipc_port_t      *portp)
                    560: {
                    561:        ipc_port_t port;
                    562:        kern_return_t kr;
                    563: 
                    564:        kr = ipc_object_alloc_name(space, IOT_PORT,
                    565:                                   MACH_PORT_TYPE_RECEIVE, 0,
                    566:                                   name, (ipc_object_t *) &port);
                    567:        if (kr != KERN_SUCCESS)
                    568:                return kr;
                    569:        /* port is locked */
                    570: 
                    571:        ipc_port_init(port, space, name);
                    572: 
                    573:        *portp = port;
                    574:        return KERN_SUCCESS;
                    575: }
                    576: 
                    577: /*
                    578:  *     Routine:        ipc_port_destroy
                    579:  *     Purpose:
                    580:  *             Destroys a port.  Cleans up queued messages.
                    581:  *
                    582:  *             If the port has a backup, it doesn't get destroyed,
                    583:  *             but is sent in a port-destroyed notification to the backup.
                    584:  *     Conditions:
                    585:  *             The port is locked and alive; nothing else locked.
                    586:  *             The caller has a reference, which is consumed.
                    587:  *             Afterwards, the port is unlocked and dead.
                    588:  */
                    589: 
                    590: void
                    591: ipc_port_destroy(
                    592:        ipc_port_t      port)
                    593: {
                    594:        ipc_port_t pdrequest, nsrequest;
                    595:        ipc_mqueue_t mqueue;
                    596:        ipc_kmsg_queue_t kmqueue;
                    597:        ipc_kmsg_t kmsg;
                    598:        ipc_thread_t sender;
                    599:        ipc_port_request_t dnrequests;
                    600: 
                    601:        assert(ip_active(port));
                    602:        /* port->ip_receiver_name is garbage */
                    603:        /* port->ip_receiver/port->ip_destination is garbage */
                    604:        assert(port->ip_pset == IPS_NULL);
                    605:        assert(port->ip_mscount == 0);
                    606:        assert(port->ip_seqno == 0);
                    607: 
                    608:        /* first check for a backup port */
                    609: 
                    610:        pdrequest = port->ip_pdrequest;
                    611:        if (pdrequest != IP_NULL) {
                    612:                /* we assume the ref for pdrequest */
                    613:                port->ip_pdrequest = IP_NULL;
                    614: 
                    615:                /* make port be in limbo */
                    616:                port->ip_receiver_name = MACH_PORT_NULL;
                    617:                port->ip_destination = IP_NULL;
                    618:                ip_unlock(port);
                    619: 
                    620:                if (!ipc_port_check_circularity(port, pdrequest)) {
                    621:                        /* consumes our refs for port and pdrequest */
                    622:                        ipc_notify_port_destroyed(pdrequest, port);
                    623:                        return;
                    624:                } else {
                    625:                        /* consume pdrequest and destroy port */
                    626:                        ipc_port_release_sonce(pdrequest);
                    627:                }
                    628: 
                    629:                ip_lock(port);
                    630:                assert(ip_active(port));
                    631:                assert(port->ip_pset == IPS_NULL);
                    632:                assert(port->ip_mscount == 0);
                    633:                assert(port->ip_seqno == 0);
                    634:                assert(port->ip_pdrequest == IP_NULL);
                    635:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                    636:                assert(port->ip_destination == IP_NULL);
                    637: 
                    638:                /* fall through and destroy the port */
                    639:        }
                    640: 
                    641:        /*
                    642:         *      rouse all blocked senders
                    643:         *
                    644:         *      This must be done with the port locked, because
                    645:         *      ipc_mqueue_send can play with the ip_blocked queue
                    646:         *      of a dead port.
                    647:         */
                    648: 
                    649:        while ((sender = ipc_thread_dequeue(&port->ip_blocked)) != ITH_NULL) {
                    650:                sender->ith_state = MACH_MSG_SUCCESS;
                    651:                thread_go(sender);
                    652:        }
                    653: 
                    654:        /* once port is dead, we don't need to keep it locked */
                    655: 
                    656:        port->ip_object.io_bits &= ~IO_BITS_ACTIVE;
                    657:        port->ip_timestamp = ipc_port_timestamp();
                    658:        ip_unlock(port);
                    659: 
                    660:        /* throw away no-senders request */
                    661: 
                    662:        nsrequest = port->ip_nsrequest;
                    663:        if (nsrequest != IP_NULL)
                    664:                ipc_notify_send_once(nsrequest); /* consumes ref */
                    665: 
                    666:        /* destroy any queued messages */
                    667: 
                    668:        mqueue = &port->ip_messages;
                    669:        imq_lock(mqueue);
                    670:        assert(ipc_thread_queue_empty(&mqueue->imq_threads));
                    671:        kmqueue = &mqueue->imq_messages;
                    672: 
                    673:        while ((kmsg = ipc_kmsg_dequeue(kmqueue)) != IKM_NULL) {
                    674:                imq_unlock(mqueue);
                    675: 
                    676:                assert(kmsg->ikm_header.msgh_remote_port ==
                    677:                                                (mach_port_t) port);
                    678: 
                    679:                ipc_port_release(port);
                    680:                kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    681:                ipc_kmsg_destroy(kmsg);
                    682: 
                    683:                imq_lock(mqueue);
                    684:        }
                    685: 
                    686:        imq_unlock(mqueue);
                    687: 
                    688:        /* generate dead-name notifications */
                    689: 
                    690:        dnrequests = port->ip_dnrequests;
                    691:        if (dnrequests != IPR_NULL) {
                    692:                ipc_table_size_t its = dnrequests->ipr_size;
                    693:                ipc_table_elems_t size = its->its_size;
                    694:                ipc_port_request_index_t index;
                    695: 
                    696:                for (index = 1; index < size; index++) {
                    697:                        ipc_port_request_t ipr = &dnrequests[index];
                    698:                        mach_port_t name = ipr->ipr_name;
                    699:                        ipc_port_t soright;
                    700: 
                    701:                        if (name == MACH_PORT_NULL)
                    702:                                continue;
                    703: 
                    704:                        soright = ipr->ipr_soright;
                    705:                        assert(soright != IP_NULL);
                    706: 
                    707:                        ipc_notify_dead_name(soright, name);
                    708:                }
                    709: 
                    710:                it_dnrequests_free(its, dnrequests);
                    711:        }
                    712: 
                    713:        if (ip_kotype(port) != IKOT_NONE)
                    714:                ipc_kobject_destroy(port);
                    715: 
                    716:        /* Common destruction for the IPC target.  */
                    717:        ipc_target_terminate(&port->ip_target);
                    718: 
                    719:        ipc_port_release(port); /* consume caller's ref */
                    720: }
                    721: 
                    722: /*
                    723:  *     Routine:        ipc_port_check_circularity
                    724:  *     Purpose:
                    725:  *             Check if queueing "port" in a message for "dest"
                    726:  *             would create a circular group of ports and messages.
                    727:  *
                    728:  *             If no circularity (FALSE returned), then "port"
                    729:  *             is changed from "in limbo" to "in transit".
                    730:  *
                    731:  *             That is, we want to set port->ip_destination == dest,
                    732:  *             but guaranteeing that this doesn't create a circle
                    733:  *             port->ip_destination->ip_destination->... == port
                    734:  *     Conditions:
                    735:  *             No ports locked.  References held for "port" and "dest".
                    736:  */
                    737: 
                    738: boolean_t
                    739: ipc_port_check_circularity(
                    740:        ipc_port_t      port,
                    741:        ipc_port_t      dest)
                    742: {
                    743:        ipc_port_t base;
                    744: 
                    745:        assert(port != IP_NULL);
                    746:        assert(dest != IP_NULL);
                    747: 
                    748:        if (port == dest)
                    749:                return TRUE;
                    750:        base = dest;
                    751: 
                    752:        /*
                    753:         *      First try a quick check that can run in parallel.
                    754:         *      No circularity if dest is not in transit.
                    755:         */
                    756: 
                    757:        ip_lock(port);
                    758:        if (ip_lock_try(dest)) {
                    759:                if (!ip_active(dest) ||
                    760:                    (dest->ip_receiver_name != MACH_PORT_NULL) ||
                    761:                    (dest->ip_destination == IP_NULL))
                    762:                        goto not_circular;
                    763: 
                    764:                /* dest is in transit; further checking necessary */
                    765: 
                    766:                ip_unlock(dest);
                    767:        }
                    768:        ip_unlock(port);
                    769: 
                    770:        ipc_port_multiple_lock(); /* massive serialization */
                    771: 
                    772:        /*
                    773:         *      Search for the end of the chain (a port not in transit),
                    774:         *      acquiring locks along the way.
                    775:         */
                    776: 
                    777:        for (;;) {
                    778:                ip_lock(base);
                    779: 
                    780:                if (!ip_active(base) ||
                    781:                    (base->ip_receiver_name != MACH_PORT_NULL) ||
                    782:                    (base->ip_destination == IP_NULL))
                    783:                        break;
                    784: 
                    785:                base = base->ip_destination;
                    786:        }
                    787: 
                    788:        /* all ports in chain from dest to base, inclusive, are locked */
                    789: 
                    790:        if (port == base) {
                    791:                /* circularity detected! */
                    792: 
                    793:                ipc_port_multiple_unlock();
                    794: 
                    795:                /* port (== base) is in limbo */
                    796: 
                    797:                assert(ip_active(port));
                    798:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                    799:                assert(port->ip_destination == IP_NULL);
                    800: 
                    801:                while (dest != IP_NULL) {
                    802:                        ipc_port_t next;
                    803: 
                    804:                        /* dest is in transit or in limbo */
                    805: 
                    806:                        assert(ip_active(dest));
                    807:                        assert(dest->ip_receiver_name == MACH_PORT_NULL);
                    808: 
                    809:                        next = dest->ip_destination;
                    810:                        ip_unlock(dest);
                    811:                        dest = next;
                    812:                }
                    813: 
                    814:                return TRUE;
                    815:        }
                    816: 
                    817:        /*
                    818:         *      The guarantee:  lock port while the entire chain is locked.
                    819:         *      Once port is locked, we can take a reference to dest,
                    820:         *      add port to the chain, and unlock everything.
                    821:         */
                    822: 
                    823:        ip_lock(port);
                    824:        ipc_port_multiple_unlock();
                    825: 
                    826:     not_circular:
                    827: 
                    828:        /* port is in limbo */
                    829: 
                    830:        assert(ip_active(port));
                    831:        assert(port->ip_receiver_name == MACH_PORT_NULL);
                    832:        assert(port->ip_destination == IP_NULL);
                    833: 
                    834:        ip_reference(dest);
                    835:        port->ip_destination = dest;
                    836: 
                    837:        /* now unlock chain */
                    838: 
                    839:        while (port != base) {
                    840:                ipc_port_t next;
                    841: 
                    842:                /* port is in transit */
                    843: 
                    844:                assert(ip_active(port));
                    845:                assert(port->ip_receiver_name == MACH_PORT_NULL);
                    846:                assert(port->ip_destination != IP_NULL);
                    847: 
                    848:                next = port->ip_destination;
                    849:                ip_unlock(port);
                    850:                port = next;
                    851:        }
                    852: 
                    853:        /* base is not in transit */
                    854: 
                    855:        assert(!ip_active(base) ||
                    856:               (base->ip_receiver_name != MACH_PORT_NULL) ||
                    857:               (base->ip_destination == IP_NULL));
                    858:        ip_unlock(base);
                    859: 
                    860:        return FALSE;
                    861: }
                    862: 
                    863: /*
                    864:  *     Routine:        ipc_port_lookup_notify
                    865:  *     Purpose:
                    866:  *             Make a send-once notify port from a receive right.
                    867:  *             Returns IP_NULL if name doesn't denote a receive right.
                    868:  *     Conditions:
                    869:  *             The space must be locked (read or write) and active.
                    870:  */
                    871: 
                    872: ipc_port_t
                    873: ipc_port_lookup_notify(
                    874:        ipc_space_t     space,
                    875:        mach_port_t     name)
                    876: {
                    877:        ipc_port_t port;
                    878:        ipc_entry_t entry;
                    879: 
                    880:        assert(space->is_active);
                    881: 
                    882:        entry = ipc_entry_lookup(space, name);
                    883:        if (entry == IE_NULL)
                    884:                return IP_NULL;
                    885: 
                    886:        if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)
                    887:                return IP_NULL;
                    888: 
                    889:        port = (ipc_port_t) entry->ie_object;
                    890:        assert(port != IP_NULL);
                    891: 
                    892:        ip_lock(port);
                    893:        assert(ip_active(port));
                    894:        assert(port->ip_receiver_name == name);
                    895:        assert(port->ip_receiver == space);
                    896: 
                    897:        ip_reference(port);
                    898:        port->ip_sorights++;
                    899:        ip_unlock(port);
                    900: 
                    901:        return port;
                    902: }
                    903: 
                    904: /*
                    905:  *     Routine:        ipc_port_make_send
                    906:  *     Purpose:
                    907:  *             Make a naked send right from a receive right.
                    908:  *     Conditions:
                    909:  *             The port is not locked but it is active.
                    910:  */
                    911: 
                    912: ipc_port_t
                    913: ipc_port_make_send(
                    914:        ipc_port_t      port)
                    915: {
                    916:        assert(IP_VALID(port));
                    917: 
                    918:        ip_lock(port);
                    919:        assert(ip_active(port));
                    920:        port->ip_mscount++;
                    921:        port->ip_srights++;
                    922:        ip_reference(port);
                    923:        ip_unlock(port);
                    924: 
                    925:        return port;
                    926: }
                    927: 
                    928: /*
                    929:  *     Routine:        ipc_port_copy_send
                    930:  *     Purpose:
                    931:  *             Make a naked send right from another naked send right.
                    932:  *                     IP_NULL         -> IP_NULL
                    933:  *                     IP_DEAD         -> IP_DEAD
                    934:  *                     dead port       -> IP_DEAD
                    935:  *                     live port       -> port + ref
                    936:  *     Conditions:
                    937:  *             Nothing locked except possibly a space.
                    938:  */
                    939: 
                    940: ipc_port_t
                    941: ipc_port_copy_send(
                    942:        ipc_port_t      port)
                    943: {
                    944:        ipc_port_t sright;
                    945: 
                    946:        if (!IP_VALID(port))
                    947:                return port;
                    948: 
                    949:        ip_lock(port);
                    950:        if (ip_active(port)) {
                    951:                assert(port->ip_srights > 0);
                    952: 
                    953:                ip_reference(port);
                    954:                port->ip_srights++;
                    955:                sright = port;
                    956:        } else
                    957:                sright = IP_DEAD;
                    958:        ip_unlock(port);
                    959: 
                    960:        return sright;
                    961: }
                    962: 
                    963: /*
                    964:  *     Routine:        ipc_port_copyout_send
                    965:  *     Purpose:
                    966:  *             Copyout a naked send right (possibly null/dead),
                    967:  *             or if that fails, destroy the right.
                    968:  *     Conditions:
                    969:  *             Nothing locked.
                    970:  */
                    971: 
                    972: mach_port_t
                    973: ipc_port_copyout_send(
                    974:        ipc_port_t      sright,
                    975:        ipc_space_t     space)
                    976: {
                    977:        mach_port_t name;
                    978: 
                    979:        if (IP_VALID(sright)) {
                    980:                kern_return_t kr;
                    981: 
                    982:                kr = ipc_object_copyout(space, (ipc_object_t) sright,
                    983:                                        MACH_MSG_TYPE_PORT_SEND, TRUE, &name);
                    984:                if (kr != KERN_SUCCESS) {
                    985:                        ipc_port_release_send(sright);
                    986: 
                    987:                        if (kr == KERN_INVALID_CAPABILITY)
                    988:                                name = MACH_PORT_DEAD;
                    989:                        else
                    990:                                name = MACH_PORT_NULL;
                    991:                }
                    992:        } else
                    993:                name = (mach_port_t) sright;
                    994: 
                    995:        return name;
                    996: }
                    997: 
                    998: /*
                    999:  *     Routine:        ipc_port_release_send
                   1000:  *     Purpose:
                   1001:  *             Release a (valid) naked send right.
                   1002:  *             Consumes a ref for the port.
                   1003:  *     Conditions:
                   1004:  *             Nothing locked.
                   1005:  */
                   1006: 
                   1007: void
                   1008: ipc_port_release_send(
                   1009:        ipc_port_t      port)
                   1010: {
                   1011:        ipc_port_t nsrequest = IP_NULL;
                   1012:        mach_port_mscount_t mscount;
                   1013: 
                   1014:        assert(IP_VALID(port));
                   1015: 
                   1016:        ip_lock(port);
                   1017:        ip_release(port);
                   1018: 
                   1019:        if (!ip_active(port)) {
                   1020:                ip_check_unlock(port);
                   1021:                return;
                   1022:        }
                   1023: 
                   1024:        assert(port->ip_srights > 0);
                   1025: 
                   1026:        if (--port->ip_srights == 0) {
                   1027:                nsrequest = port->ip_nsrequest;
                   1028:                if (nsrequest != IP_NULL) {
                   1029:                        port->ip_nsrequest = IP_NULL;
                   1030:                        mscount = port->ip_mscount;
                   1031:                }
                   1032:        }
                   1033: 
                   1034:        ip_unlock(port);
                   1035: 
                   1036:        if (nsrequest != IP_NULL)
                   1037:                ipc_notify_no_senders(nsrequest, mscount);
                   1038: }
                   1039: 
                   1040: /*
                   1041:  *     Routine:        ipc_port_make_sonce
                   1042:  *     Purpose:
                   1043:  *             Make a naked send-once right from a receive right.
                   1044:  *     Conditions:
                   1045:  *             The port is not locked but it is active.
                   1046:  */
                   1047: 
                   1048: ipc_port_t
                   1049: ipc_port_make_sonce(
                   1050:        ipc_port_t      port)
                   1051: {
                   1052:        assert(IP_VALID(port));
                   1053: 
                   1054:        ip_lock(port);
                   1055:        assert(ip_active(port));
                   1056:        port->ip_sorights++;
                   1057:        ip_reference(port);
                   1058:        ip_unlock(port);
                   1059: 
                   1060:        return port;
                   1061: }
                   1062: 
                   1063: /*
                   1064:  *     Routine:        ipc_port_release_sonce
                   1065:  *     Purpose:
                   1066:  *             Release a naked send-once right.
                   1067:  *             Consumes a ref for the port.
                   1068:  *
                   1069:  *             In normal situations, this is never used.
                   1070:  *             Send-once rights are only consumed when
                   1071:  *             a message (possibly a send-once notification)
                   1072:  *             is sent to them.
                   1073:  *     Conditions:
                   1074:  *             Nothing locked except possibly a space.
                   1075:  */
                   1076: 
                   1077: void
                   1078: ipc_port_release_sonce(
                   1079:        ipc_port_t      port)
                   1080: {
                   1081:        assert(IP_VALID(port));
                   1082: 
                   1083:        ip_lock(port);
                   1084: 
                   1085:        assert(port->ip_sorights > 0);
                   1086: 
                   1087:        port->ip_sorights--;
                   1088: 
                   1089:        ip_release(port);
                   1090: 
                   1091:        if (!ip_active(port)) {
                   1092:                ip_check_unlock(port);
                   1093:                return;
                   1094:        }
                   1095: 
                   1096:        ip_unlock(port);
                   1097: }
                   1098: 
                   1099: /*
                   1100:  *     Routine:        ipc_port_release_receive
                   1101:  *     Purpose:
                   1102:  *             Release a naked (in limbo or in transit) receive right.
                   1103:  *             Consumes a ref for the port; destroys the port.
                   1104:  *     Conditions:
                   1105:  *             Nothing locked.
                   1106:  */
                   1107: 
                   1108: void
                   1109: ipc_port_release_receive(
                   1110:        ipc_port_t      port)
                   1111: {
                   1112:        ipc_port_t dest;
                   1113: 
                   1114:        assert(IP_VALID(port));
                   1115: 
                   1116:        ip_lock(port);
                   1117:        assert(ip_active(port));
                   1118:        assert(port->ip_receiver_name == MACH_PORT_NULL);
                   1119:        dest = port->ip_destination;
                   1120: 
                   1121:        ipc_port_destroy(port); /* consumes ref, unlocks */
                   1122: 
                   1123:        if (dest != IP_NULL)
                   1124:                ipc_port_release(dest);
                   1125: }
                   1126: 
                   1127: /*
                   1128:  *     Routine:        ipc_port_alloc_special
                   1129:  *     Purpose:
                   1130:  *             Allocate a port in a special space.
                   1131:  *             The new port is returned with one ref.
                   1132:  *             If unsuccessful, IP_NULL is returned.
                   1133:  *     Conditions:
                   1134:  *             Nothing locked.
                   1135:  */
                   1136: 
                   1137: ipc_port_t
                   1138: ipc_port_alloc_special(space)
                   1139:        ipc_space_t space;
                   1140: {
                   1141:        ipc_port_t port;
                   1142: 
                   1143:        port = (ipc_port_t) io_alloc(IOT_PORT);
                   1144:        if (port == IP_NULL)
                   1145:                return IP_NULL;
                   1146: 
                   1147:        io_lock_init(&port->ip_object);
                   1148:        port->ip_references = 1;
                   1149:        port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0);
                   1150: 
                   1151:        /*
                   1152:         *      The actual values of ip_receiver_name aren't important,
                   1153:         *      as long as they are valid (not null/dead).
                   1154:         *
                   1155:         *      Mach4: we set it to the internal port structure address
                   1156:         *      so we can always just pass on ip_receiver_name during
                   1157:         *      an rpc regardless of whether the destination is user or
                   1158:         *      kernel (i.e. no special-casing code for the kernel along
                   1159:         *      the fast rpc path).
                   1160:         */
                   1161: 
                   1162:        ipc_port_init(port, space, (mach_port_t)port);
                   1163: 
                   1164:        return port;
                   1165: }
                   1166: 
                   1167: /*
                   1168:  *     Routine:        ipc_port_dealloc_special
                   1169:  *     Purpose:
                   1170:  *             Deallocate a port in a special space.
                   1171:  *             Consumes one ref for the port.
                   1172:  *     Conditions:
                   1173:  *             Nothing locked.
                   1174:  */
                   1175: 
                   1176: void
                   1177: ipc_port_dealloc_special(
                   1178:        ipc_port_t      port,
                   1179:        ipc_space_t     space)
                   1180: {
                   1181:        ip_lock(port);
                   1182:        assert(ip_active(port));
                   1183:        assert(port->ip_receiver_name != MACH_PORT_NULL);
                   1184:        assert(port->ip_receiver == space);
                   1185: 
                   1186:        /*
                   1187:         *      We clear ip_receiver_name and ip_receiver to simplify
                   1188:         *      the ipc_space_kernel check in ipc_mqueue_send.
                   1189:         */
                   1190: 
                   1191:        port->ip_receiver_name = MACH_PORT_NULL;
                   1192:        port->ip_receiver = IS_NULL;
                   1193: 
                   1194:        /*
                   1195:         *      For ipc_space_kernel, all ipc_port_clear_receiver does
                   1196:         *      is clean things up for the assertions in ipc_port_destroy.
                   1197:         *      For ipc_space_reply, there might be a waiting receiver.
                   1198:         */
                   1199: 
                   1200:        ipc_port_clear_receiver(port);
                   1201:        ipc_port_destroy(port);
                   1202: }
                   1203: 
                   1204: #if    MACH_KDB
                   1205: #define        printf  kdbprintf
                   1206: 
                   1207: /*
                   1208:  *     Routine:        ipc_port_print
                   1209:  *     Purpose:
                   1210:  *             Pretty-print a port for kdb.
                   1211:  */
                   1212: 
                   1213: void
                   1214: ipc_port_print(port)
                   1215:        ipc_port_t port;
                   1216: {
                   1217:        printf("port 0x%x\n", port);
                   1218: 
                   1219:        indent += 2;
                   1220: 
                   1221:        ipc_object_print(&port->ip_object);
                   1222:        iprintf("receiver=0x%x", port->ip_receiver);
                   1223:        printf(", receiver_name=0x%x\n", port->ip_receiver_name);
                   1224: 
                   1225:        iprintf("mscount=%d", port->ip_mscount);
                   1226:        printf(", srights=%d", port->ip_srights);
                   1227:        printf(", sorights=%d\n", port->ip_sorights);
                   1228: 
                   1229:        iprintf("nsrequest=0x%x", port->ip_nsrequest);
                   1230:        printf(", pdrequest=0x%x", port->ip_pdrequest);
                   1231:        printf(", dnrequests=0x%x\n", port->ip_dnrequests);
                   1232: 
                   1233:        iprintf("pset=0x%x", port->ip_pset);
                   1234:        printf(", seqno=%d", port->ip_seqno);
                   1235:        printf(", msgcount=%d", port->ip_msgcount);
                   1236:        printf(", qlimit=%d\n", port->ip_qlimit);
                   1237: 
                   1238:        iprintf("kmsgs=0x%x", port->ip_messages.imq_messages.ikmq_base);
                   1239:        printf(", rcvrs=0x%x", port->ip_messages.imq_threads.ithq_base);
                   1240:        printf(", sndrs=0x%x", port->ip_blocked.ithq_base);
                   1241:        printf(", kobj=0x%x\n", port->ip_kobject);
                   1242: 
                   1243:        indent -=2;
                   1244: }
                   1245: 
1.1.1.2   root     1246: #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.