Annotation of kernel/ipc/ipc_port.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.