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

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: /*
                     53:  *     File:   ipc/mach_port.c
                     54:  *     Author: Rich Draves
                     55:  *     Date:   1989
                     56:  *
                     57:  *     Exported kernel calls.  See mach/mach_port.defs.
                     58:  */
                     59: 
                     60: #include <mach_debug.h>
                     61: #include <mach_rt.h>
                     62: 
                     63: #include <mach/port.h>
                     64: #include <mach/kern_return.h>
                     65: #include <mach/notify.h>
                     66: #include <mach/mach_param.h>
                     67: #include <mach/vm_param.h>
                     68: #include <mach/vm_prot.h>
                     69: #include <kern/task.h>
                     70: #include <kern/counters.h>
                     71: #include <kern/thread_act.h>
                     72: #include <kern/thread_pool.h>
                     73: #include <mach/mach_port_server.h>
                     74: #include <vm/vm_map.h>
                     75: #include <vm/vm_kern.h>
                     76: #include <vm/vm_user.h>
                     77: #include <ipc/ipc_entry.h>
                     78: #include <ipc/ipc_space.h>
                     79: #include <ipc/ipc_object.h>
                     80: #include <ipc/ipc_notify.h>
                     81: #include <ipc/ipc_port.h>
                     82: #include <ipc/ipc_pset.h>
                     83: #include <ipc/ipc_right.h>
                     84: #include <kern/misc_protos.h>
                     85: 
                     86: /*
                     87:  * Forward declarations
                     88:  */
                     89: void mach_port_names_helper(
                     90:        ipc_port_timestamp_t    timestamp,
                     91:        ipc_entry_t             entry,
                     92:        mach_port_name_t        name,
                     93:        mach_port_name_t        *names,
                     94:        mach_port_type_t        *types,
                     95:        ipc_entry_num_t         *actualp,
                     96:        ipc_space_t             space);
                     97: 
                     98: void mach_port_gst_helper(
                     99:        ipc_pset_t              pset,
                    100:        ipc_port_t              port,
                    101:        ipc_entry_num_t         maxnames,
                    102:        mach_port_name_t        *names,
                    103:        ipc_entry_num_t         *actualp);
                    104: 
                    105: 
                    106: /* Zeroed template of qos flags */
                    107: 
                    108: static mach_port_qos_t qos_template;
                    109: 
                    110: /*
                    111:  *     Routine:        mach_port_names_helper
                    112:  *     Purpose:
                    113:  *             A helper function for mach_port_names.
                    114:  */
                    115: 
                    116: void
                    117: mach_port_names_helper(
                    118:        ipc_port_timestamp_t    timestamp,
                    119:        ipc_entry_t             entry,
                    120:        mach_port_name_t        name,
                    121:        mach_port_name_t        *names,
                    122:        mach_port_type_t        *types,
                    123:        ipc_entry_num_t         *actualp,
                    124:        ipc_space_t             space)
                    125: {
                    126:        ipc_entry_bits_t bits;
                    127:        ipc_port_request_index_t request;
                    128:        mach_port_type_t type;
                    129:        ipc_entry_num_t actual;
                    130: 
                    131:        bits = entry->ie_bits;
                    132:        request = entry->ie_request;
                    133:        if (bits & MACH_PORT_TYPE_SEND_RIGHTS) {
                    134:                ipc_port_t port;
                    135:                boolean_t died;
                    136: 
                    137:                port = (ipc_port_t) entry->ie_object;
                    138:                assert(port != IP_NULL);
                    139: 
                    140:                /*
                    141:                 *      The timestamp serializes mach_port_names
                    142:                 *      with ipc_port_destroy.  If the port died,
                    143:                 *      but after mach_port_names started, pretend
                    144:                 *      that it isn't dead.
                    145:                 */
                    146: 
                    147:                ip_lock(port);
                    148:                died = (!ip_active(port) &&
                    149:                        IP_TIMESTAMP_ORDER(port->ip_timestamp, timestamp));
                    150:                ip_unlock(port);
                    151: 
                    152:                if (died) {
                    153:                        /* pretend this is a dead-name entry */
                    154: 
                    155:                        bits &= ~(IE_BITS_TYPE_MASK);
                    156:                        bits |= MACH_PORT_TYPE_DEAD_NAME;
                    157:                        if (request != 0)
                    158:                                bits++;
                    159:                        request = 0;
                    160:                }
                    161:        }
                    162: 
                    163:        type = IE_BITS_TYPE(bits);
                    164:        if (request != 0)
                    165:                type |= MACH_PORT_TYPE_DNREQUEST;
                    166: 
                    167:        actual = *actualp;
                    168:        names[actual] = name;
                    169:        types[actual] = type;
                    170:        *actualp = actual+1;
                    171: }
                    172: 
                    173: /*
                    174:  *     Routine:        mach_port_names [kernel call]
                    175:  *     Purpose:
                    176:  *             Retrieves a list of the rights present in the space,
                    177:  *             along with type information.  (Same as returned
                    178:  *             by mach_port_type.)  The names are returned in
                    179:  *             no particular order, but they (and the type info)
                    180:  *             are an accurate snapshot of the space.
                    181:  *     Conditions:
                    182:  *             Nothing locked.
                    183:  *     Returns:
                    184:  *             KERN_SUCCESS            Arrays of names and types returned.
                    185:  *             KERN_INVALID_TASK       The space is null.
                    186:  *             KERN_INVALID_TASK       The space is dead.
                    187:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    188:  */
                    189: 
                    190: kern_return_t
                    191: mach_port_names(
                    192:        ipc_space_t             space,
                    193:        mach_port_name_t        **namesp,
                    194:        mach_msg_type_number_t  *namesCnt,
                    195:        mach_port_type_t        **typesp,
                    196:        mach_msg_type_number_t  *typesCnt)
                    197: {
                    198:        ipc_entry_bits_t *capability;
                    199:        ipc_tree_entry_t tentry;
                    200:        ipc_entry_t table;
                    201:        ipc_entry_num_t tsize;
                    202:        mach_port_index_t index;
                    203:        ipc_entry_num_t actual; /* this many names */
                    204:        ipc_port_timestamp_t timestamp; /* logical time of this operation */
                    205:        mach_port_name_t *names;
                    206:        mach_port_type_t *types;
                    207:        kern_return_t kr;
                    208: 
                    209:        vm_size_t size;         /* size of allocated memory */
                    210:        vm_offset_t addr1;      /* allocated memory, for names */
                    211:        vm_offset_t addr2;      /* allocated memory, for types */
                    212:        vm_map_copy_t memory1;  /* copied-in memory, for names */
                    213:        vm_map_copy_t memory2;  /* copied-in memory, for types */
                    214: 
                    215:        /* safe simplifying assumption */
                    216:        assert_static(sizeof(mach_port_name_t) == sizeof(mach_port_type_t));
                    217: 
                    218:        if (space == IS_NULL)
                    219:                return KERN_INVALID_TASK;
                    220: 
                    221:        size = 0;
                    222: 
                    223:        for (;;) {
                    224:                ipc_entry_num_t bound;
                    225:                vm_size_t size_needed;
                    226: 
                    227:                is_read_lock(space);
                    228:                if (!space->is_active) {
                    229:                        is_read_unlock(space);
                    230:                        if (size != 0) {
                    231:                                kmem_free(ipc_kernel_map, addr1, size);
                    232:                                kmem_free(ipc_kernel_map, addr2, size);
                    233:                        }
                    234:                        return KERN_INVALID_TASK;
                    235:                }
                    236: 
                    237:                /* upper bound on number of names in the space */
                    238: 
                    239:                bound = space->is_table_size + space->is_tree_total;
                    240:                size_needed = round_page(bound * sizeof(mach_port_name_t));
                    241: 
                    242:                if (size_needed <= size)
                    243:                        break;
                    244: 
                    245:                is_read_unlock(space);
                    246: 
                    247:                if (size != 0) {
                    248:                        kmem_free(ipc_kernel_map, addr1, size);
                    249:                        kmem_free(ipc_kernel_map, addr2, size);
                    250:                }
                    251:                size = size_needed;
                    252: 
                    253:                kr = vm_allocate(ipc_kernel_map, &addr1, size, TRUE);
                    254:                if (kr != KERN_SUCCESS)
                    255:                        return KERN_RESOURCE_SHORTAGE;
                    256: 
                    257:                kr = vm_allocate(ipc_kernel_map, &addr2, size, TRUE);
                    258:                if (kr != KERN_SUCCESS) {
                    259:                        kmem_free(ipc_kernel_map, addr1, size);
                    260:                        return KERN_RESOURCE_SHORTAGE;
                    261:                }
                    262: 
                    263:                /* can't fault while we hold locks */
                    264: 
                    265:                kr = vm_map_wire(ipc_kernel_map, addr1, addr1 + size,
                    266:                                     VM_PROT_READ|VM_PROT_WRITE, FALSE);
                    267:                assert(kr == KERN_SUCCESS);
                    268: 
                    269:                kr = vm_map_wire(ipc_kernel_map, addr2, addr2 + size,
                    270:                                     VM_PROT_READ|VM_PROT_WRITE, FALSE);
                    271:                assert(kr == KERN_SUCCESS);
                    272:        }
                    273:        /* space is read-locked and active */
                    274: 
                    275:        names = (mach_port_name_t *) addr1;
                    276:        types = (mach_port_type_t *) addr2;
                    277:        actual = 0;
                    278: 
                    279:        timestamp = ipc_port_timestamp();
                    280: 
                    281:        table = space->is_table;
                    282:        tsize = space->is_table_size;
                    283: 
                    284:        for (index = 0; index < tsize; index++) {
                    285:                ipc_entry_t entry = &table[index];
                    286:                ipc_entry_bits_t bits = entry->ie_bits;
                    287: 
                    288:                if (IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE) {
                    289:                        mach_port_name_t name;
                    290: 
                    291:                        name = MACH_PORT_MAKE(index, IE_BITS_GEN(bits));
                    292:                        mach_port_names_helper(timestamp, entry, name, names,
                    293:                                               types, &actual, space);
                    294:                }
                    295:        }
                    296: 
                    297:        for (tentry = ipc_splay_traverse_start(&space->is_tree);
                    298:            tentry != ITE_NULL;
                    299:            tentry = ipc_splay_traverse_next(&space->is_tree, FALSE)) {
                    300:                ipc_entry_t entry = &tentry->ite_entry;
                    301:                mach_port_name_t name = tentry->ite_name;
                    302: 
                    303:                assert(IE_BITS_TYPE(tentry->ite_bits) != MACH_PORT_TYPE_NONE);
                    304:                mach_port_names_helper(timestamp, entry, name, names,
                    305:                                       types, &actual, space);
                    306:        }
                    307:        ipc_splay_traverse_finish(&space->is_tree);
                    308:        is_read_unlock(space);
                    309: 
                    310:        if (actual == 0) {
                    311:                memory1 = VM_MAP_COPY_NULL;
                    312:                memory2 = VM_MAP_COPY_NULL;
                    313: 
                    314:                if (size != 0) {
                    315:                        kmem_free(ipc_kernel_map, addr1, size);
                    316:                        kmem_free(ipc_kernel_map, addr2, size);
                    317:                }
                    318:        } else {
                    319:                vm_size_t size_used;
                    320:                vm_size_t vm_size_used;
                    321: 
                    322:                size_used = actual * sizeof(mach_port_name_t);
                    323:                vm_size_used = round_page(size_used);
                    324: 
                    325:                /*
                    326:                 *      Make used memory pageable and get it into
                    327:                 *      copied-in form.  Free any unused memory.
                    328:                 */
                    329: 
                    330:                kr = vm_map_unwire(ipc_kernel_map,
                    331:                                     addr1, addr1 + vm_size_used, FALSE);
                    332:                assert(kr == KERN_SUCCESS);
                    333: 
                    334:                kr = vm_map_unwire(ipc_kernel_map,
                    335:                                     addr2, addr2 + vm_size_used, FALSE);
                    336:                assert(kr == KERN_SUCCESS);
                    337: 
                    338:                kr = vm_map_copyin(ipc_kernel_map, addr1, size_used,
                    339:                                   TRUE, &memory1);
                    340:                assert(kr == KERN_SUCCESS);
                    341: 
                    342:                kr = vm_map_copyin(ipc_kernel_map, addr2, size_used,
                    343:                                   TRUE, &memory2);
                    344:                assert(kr == KERN_SUCCESS);
                    345: 
                    346:                if (vm_size_used != size) {
                    347:                        kmem_free(ipc_kernel_map,
                    348:                                  addr1 + vm_size_used, size - vm_size_used);
                    349:                        kmem_free(ipc_kernel_map,
                    350:                                  addr2 + vm_size_used, size - vm_size_used);
                    351:                }
                    352:        }
                    353: 
                    354:        *namesp = (mach_port_name_t *) memory1;
                    355:        *namesCnt = actual;
                    356:        *typesp = (mach_port_type_t *) memory2;
                    357:        *typesCnt = actual;
                    358:        return KERN_SUCCESS;
                    359: }
                    360: 
                    361: /*
                    362:  *     Routine:        mach_port_type [kernel call]
                    363:  *     Purpose:
                    364:  *             Retrieves the type of a right in the space.
                    365:  *             The type is a bitwise combination of one or more
                    366:  *             of the following type bits:
                    367:  *                     MACH_PORT_TYPE_SEND
                    368:  *                     MACH_PORT_TYPE_RECEIVE
                    369:  *                     MACH_PORT_TYPE_SEND_ONCE
                    370:  *                     MACH_PORT_TYPE_PORT_SET
                    371:  *                     MACH_PORT_TYPE_DEAD_NAME
                    372:  *             In addition, the following pseudo-type bits may be present:
                    373:  *                     MACH_PORT_TYPE_DNREQUEST
                    374:  *                             A dead-name notification is requested.
                    375:  *     Conditions:
                    376:  *             Nothing locked.
                    377:  *     Returns:
                    378:  *             KERN_SUCCESS            Type is returned.
                    379:  *             KERN_INVALID_TASK       The space is null.
                    380:  *             KERN_INVALID_TASK       The space is dead.
                    381:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    382:  */
                    383: 
                    384: kern_return_t
                    385: mach_port_type(
                    386:        ipc_space_t             space,
                    387:        mach_port_name_t        name,
                    388:        mach_port_type_t        *typep)
                    389: {
                    390:        mach_port_urefs_t urefs;
                    391:        ipc_entry_t entry;
                    392:        kern_return_t kr;
                    393: 
                    394:        if (space == IS_NULL)
                    395:                return KERN_INVALID_TASK;
                    396: 
                    397:        kr = ipc_right_lookup_write(space, name, &entry);
                    398:        if (kr != KERN_SUCCESS)
                    399:                return kr;
                    400:        /* space is write-locked and active */
                    401: 
                    402:        kr = ipc_right_info(space, name, entry, typep, &urefs);
                    403:        if (kr == KERN_SUCCESS)
                    404:                is_write_unlock(space);
                    405:        /* space is unlocked */
                    406:        return kr;
                    407: }
                    408: 
                    409: /*
                    410:  *     Routine:        mach_port_rename [kernel call]
                    411:  *     Purpose:
                    412:  *             Changes the name denoting a right,
                    413:  *             from oname to nname.
                    414:  *     Conditions:
                    415:  *             Nothing locked.
                    416:  *     Returns:
                    417:  *             KERN_SUCCESS            The right is renamed.
                    418:  *             KERN_INVALID_TASK       The space is null.
                    419:  *             KERN_INVALID_TASK       The space is dead.
                    420:  *             KERN_INVALID_NAME       The oname doesn't denote a right.
                    421:  *             KERN_INVALID_VALUE      The nname isn't a legal name.
                    422:  *             KERN_NAME_EXISTS        The nname already denotes a right.
                    423:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    424:  */
                    425: 
                    426: kern_return_t
                    427: mach_port_rename(
                    428:        ipc_space_t             space,
                    429:        mach_port_name_t        oname,
                    430:        mach_port_name_t        nname)
                    431: {
                    432:        if (space == IS_NULL)
                    433:                return KERN_INVALID_TASK;
                    434: 
                    435:        if (!MACH_PORT_VALID(nname))
                    436:                return KERN_INVALID_VALUE;
                    437: 
                    438:        return ipc_object_rename(space, oname, nname);
                    439: }
                    440: 
                    441: /*
                    442:  *     Routine:        mach_port_allocate_name [kernel call]
                    443:  *     Purpose:
                    444:  *             Allocates a right in a space, using a specific name
                    445:  *             for the new right.  Possible rights:
                    446:  *                     MACH_PORT_RIGHT_RECEIVE
                    447:  *                     MACH_PORT_RIGHT_PORT_SET
                    448:  *                     MACH_PORT_RIGHT_DEAD_NAME
                    449:  *
                    450:  *             A new port (allocated with MACH_PORT_RIGHT_RECEIVE)
                    451:  *             has no extant send or send-once rights and no queued
                    452:  *             messages.  Its queue limit is MACH_PORT_QLIMIT_DEFAULT
                    453:  *             and its make-send count is 0.  It is not a member of
                    454:  *             a port set.  It has no registered no-senders or
                    455:  *             port-destroyed notification requests.
                    456:  *
                    457:  *             A new port set has no members.
                    458:  *
                    459:  *             A new dead name has one user reference.
                    460:  *     Conditions:
                    461:  *             Nothing locked.
                    462:  *     Returns:
                    463:  *             KERN_SUCCESS            The right is allocated.
                    464:  *             KERN_INVALID_TASK       The space is null.
                    465:  *             KERN_INVALID_TASK       The space is dead.
                    466:  *             KERN_INVALID_VALUE      The name isn't a legal name.
                    467:  *             KERN_INVALID_VALUE      "right" isn't a legal kind of right.
                    468:  *             KERN_NAME_EXISTS        The name already denotes a right.
                    469:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    470:  *
                    471:  *     Restrictions on name allocation:  NT bits are reserved by kernel,
                    472:  *     must be set on any chosen name.  Can't do this at all in kernel
                    473:  *     loaded server.
                    474:  */
                    475: 
                    476: kern_return_t
                    477: mach_port_allocate_name(
                    478:        ipc_space_t             space,
                    479:        mach_port_right_t       right,
                    480:        mach_port_name_t        name)
                    481: {
                    482:        kern_return_t           kr;
                    483:        mach_port_qos_t         qos = qos_template;
                    484: 
                    485:        qos.name = TRUE;
                    486: 
                    487:        kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL,
                    488:                                        &qos, &name);
                    489:        return (kr);
                    490: }
                    491: 
                    492: /*
                    493:  *     Routine:        mach_port_allocate [kernel call]
                    494:  *     Purpose:
                    495:  *             Allocates a right in a space.  Like mach_port_allocate_name,
                    496:  *             except that the implementation picks a name for the right.
                    497:  *             The name may be any legal name in the space that doesn't
                    498:  *             currently denote a right.
                    499:  *     Conditions:
                    500:  *             Nothing locked.
                    501:  *     Returns:
                    502:  *             KERN_SUCCESS            The right is allocated.
                    503:  *             KERN_INVALID_TASK       The space is null.
                    504:  *             KERN_INVALID_TASK       The space is dead.
                    505:  *             KERN_INVALID_VALUE      "right" isn't a legal kind of right.
                    506:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    507:  *             KERN_NO_SPACE           No room in space for another right.
                    508:  */
                    509: 
                    510: kern_return_t
                    511: mach_port_allocate(
                    512:        ipc_space_t             space,
                    513:        mach_port_right_t       right,
                    514:        mach_port_name_t        *namep)
                    515: {
                    516:        kern_return_t           kr;
                    517:        mach_port_qos_t         qos = qos_template;
                    518: 
                    519:        kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL,
                    520:                                        &qos, namep);
                    521:        return (kr);
                    522: }
                    523: 
                    524: /*
                    525:  *     Routine:        mach_port_allocate_qos [kernel call]
                    526:  *     Purpose:
                    527:  *             Allocates a right, with qos options, in a space.  Like 
                    528:  *             mach_port_allocate_name, except that the implementation 
                    529:  *             picks a name for the right. The name may be any legal name 
                    530:  *             in the space that doesn't currently denote a right.
                    531:  *     Conditions:
                    532:  *             Nothing locked.
                    533:  *     Returns:
                    534:  *             KERN_SUCCESS            The right is allocated.
                    535:  *             KERN_INVALID_TASK       The space is null.
                    536:  *             KERN_INVALID_TASK       The space is dead.
                    537:  *             KERN_INVALID_VALUE      "right" isn't a legal kind of right.
                    538:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    539:  *             KERN_NO_SPACE           No room in space for another right.
                    540:  */
                    541: 
                    542: kern_return_t
                    543: mach_port_allocate_qos(
                    544:        ipc_space_t             space,
                    545:        mach_port_right_t       right,
                    546:        mach_port_qos_t         *qosp,
                    547:        mach_port_name_t        *namep)
                    548: {
                    549:        kern_return_t           kr;
                    550: 
                    551:        kr = mach_port_allocate_full (space, right, SUBSYSTEM_NULL,
                    552:                                        qosp, namep);
                    553:        return (kr);
                    554: }
                    555: 
                    556: /*
                    557:  *     Routine:        mach_port_allocate_subsystem [kernel call]
                    558:  *     Purpose:
                    559:  *             Allocates a receive right in a space.  Like
                    560:  *             mach_port_allocate, except that the caller specifies an
                    561:  *             RPC subsystem that is to be used to implement RPC's to the
                    562:  *             port. When possible, allocate rpc subsystem ports without
                    563:  *             nms, since within RPC ports are intended to be used for
                    564:  *             identity only (i.e. nms is painful in the distributed case
                    565:  *             and we don't need or want it for RPC anyway).
                    566:  *     Conditions:
                    567:  *             Nothing locked.
                    568:  *     Returns:
                    569:  *             KERN_SUCCESS            The right is allocated.
                    570:  *             KERN_INVALID_TASK       The space is null.
                    571:  *             KERN_INVALID_TASK       The space is dead.
                    572:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    573:  *             KERN_NO_SPACE           No room in space for another right.
                    574:  *             KERN_INVALID_ARGUMENT   bogus subsystem
                    575:  */
                    576: 
                    577: kern_return_t
                    578: mach_port_allocate_subsystem(
                    579:        ipc_space_t             space,
                    580:        subsystem_t             subsystem,
                    581:        mach_port_name_t        *namep)
                    582: {
                    583:        kern_return_t           kr;
                    584:        ipc_port_t              port;
                    585:        mach_port_qos_t         qos = qos_template;
                    586: 
                    587:        kr = mach_port_allocate_full (space, 
                    588: #if    TEMPORARY_NO_NMS
                    589:                                        MACH_PORT_RIGHT_RECEIVE_NO_NMS,
                    590: #else
                    591:                                        MACH_PORT_RIGHT_RECEIVE,
                    592: #endif /* TEMPORARY_NO_NMS */
                    593:                                        subsystem, &qos, namep);
                    594:        return (kr);
                    595: }
                    596: 
                    597: /*
                    598:  *     Routine:        mach_port_allocate_full [kernel call]
                    599:  *     Purpose:
                    600:  *             Allocates a right in a space.  Supports all of the
                    601:  *             special cases, such as specifying a subsystem,
                    602:  *             a specific name, a real-time port, etc.
                    603:  *             The name may be any legal name in the space that doesn't
                    604:  *             currently denote a right.
                    605:  *     Conditions:
                    606:  *             Nothing locked.
                    607:  *     Returns:
                    608:  *             KERN_SUCCESS            The right is allocated.
                    609:  *             KERN_INVALID_TASK       The space is null.
                    610:  *             KERN_INVALID_TASK       The space is dead.
                    611:  *             KERN_INVALID_VALUE      "right" isn't a legal kind of right.
                    612:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    613:  *             KERN_NO_SPACE           No room in space for another right.
                    614:  */
                    615: #if    TEMPORARY_NO_NMS
                    616: counter(unsigned int         c_mpalloc_fast = 0;)
                    617: #endif /* TEMPORARY_NO_NMS */
                    618: 
                    619: kern_return_t
                    620: mach_port_allocate_full(
                    621:        ipc_space_t             space,
                    622:        mach_port_right_t       right,
                    623:        subsystem_t             subsystem,
                    624:        mach_port_qos_t         *qosp,
                    625:        mach_port_name_t        *namep)
                    626: {
                    627:        kern_return_t           kr;
                    628: 
                    629:        if (space == IS_NULL)
                    630:                return (KERN_INVALID_TASK);
                    631: 
                    632:        if (qosp->name) {
                    633:                if (!MACH_PORT_VALID (*namep))
                    634:                        return (KERN_INVALID_VALUE);
                    635:                if (is_fast_space (space))
                    636:                        return (KERN_FAILURE);
                    637:        }
                    638: 
                    639:        if (subsystem != SUBSYSTEM_NULL) {
                    640:                if (right != MACH_PORT_RIGHT_RECEIVE
                    641: #if    TEMPORARY_NO_NMS
                    642:                    && right != MACH_PORT_RIGHT_RECEIVE_NO_NMS
                    643: #endif /* TEMPORARY_NO_NMS */
                    644:                     )
                    645:                        return (KERN_INVALID_VALUE);
                    646:        }
                    647: 
                    648:        if (qosp->rt) {
                    649: #if    MACH_RT
                    650:                if (right != MACH_PORT_RIGHT_RECEIVE)
                    651:                        return (KERN_INVALID_VALUE);
                    652: #else  /* MACH_RT */
                    653:                return (KERN_INVALID_ARGUMENT);
                    654: #endif /* MACH_RT */
                    655:        }
                    656: 
                    657:        switch (right) {
                    658: #if    TEMPORARY_NO_NMS
                    659:            case MACH_PORT_RIGHT_RECEIVE_NO_NMS:
                    660:            {
                    661:                ipc_port_t      port;
                    662: 
                    663:                if (qosp->name)
                    664:                        kr = ipc_port_alloc_name(space, *namep, &port);
                    665:                else
                    666:                        kr = ipc_port_alloc(space, namep, &port);
                    667:                if (kr == KERN_SUCCESS) {
                    668:                        counter(++c_mpalloc_fast);
                    669:                        IP_CLEAR_NMS(port);
                    670: 
                    671: #if    MACH_RT
                    672:                        if (qosp->rt) 
                    673:                                port->ip_flags |= IPC_PORT_FLAGS_RT;
                    674: #endif /* MACH_RT */
                    675: 
                    676:                        if (subsystem != SUBSYSTEM_NULL) {
                    677:                                port->ip_subsystem = &subsystem->user;
                    678:                                subsystem_reference (subsystem);
                    679:                        }
                    680:                        ip_unlock(port);
                    681:                }
                    682:                break;
                    683:            }
                    684: #endif /* TEMPORARY_NO_NMS */
                    685: 
                    686:            case MACH_PORT_RIGHT_RECEIVE:
                    687:            {
                    688:                ipc_port_t      port;
                    689: 
                    690:                if (qosp->name)
                    691:                        kr = ipc_port_alloc_name(space, *namep, &port);
                    692:                else
                    693:                        kr = ipc_port_alloc(space, namep, &port);
                    694:                if (kr == KERN_SUCCESS) {
                    695: #if    MACH_RT
                    696:                        if (qosp->rt)
                    697:                                port->ip_flags |= IPC_PORT_FLAGS_RT;
                    698: #endif /* MACH_RT */
                    699: 
                    700:                        if (subsystem != SUBSYSTEM_NULL) {
                    701:                                port->ip_subsystem = &subsystem->user;
                    702:                                subsystem_reference (subsystem);
                    703:                        }
                    704:                        ip_unlock(port);
                    705:                }
                    706:                break;
                    707:            }
                    708: 
                    709:            case MACH_PORT_RIGHT_PORT_SET:
                    710:            {
                    711:                ipc_pset_t      pset;
                    712: 
                    713:                if (qosp->name)
                    714:                        kr = ipc_pset_alloc_name(space, *namep, &pset);
                    715:                else
                    716:                        kr = ipc_pset_alloc(space, namep, &pset);
                    717:                if (kr == KERN_SUCCESS)
                    718:                        ips_unlock(pset);
                    719:                break;
                    720:            }
                    721: 
                    722:            case MACH_PORT_RIGHT_DEAD_NAME:
                    723:                kr = ipc_object_alloc_dead(space, namep);
                    724:                break;
                    725: 
                    726:            default:
                    727:                kr = KERN_INVALID_VALUE;
                    728:                break;
                    729:        }
                    730: 
                    731:        return (kr);
                    732: }
                    733: 
                    734: /*
                    735:  *     Routine:        mach_port_destroy [kernel call]
                    736:  *     Purpose:
                    737:  *             Cleans up and destroys all rights denoted by a name
                    738:  *             in a space.  The destruction of a receive right
                    739:  *             destroys the port, unless a port-destroyed request
                    740:  *             has been made for it; the destruction of a port-set right
                    741:  *             destroys the port set.
                    742:  *     Conditions:
                    743:  *             Nothing locked.
                    744:  *     Returns:
                    745:  *             KERN_SUCCESS            The name is destroyed.
                    746:  *             KERN_INVALID_TASK       The space is null.
                    747:  *             KERN_INVALID_TASK       The space is dead.
                    748:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    749:  */
                    750: 
                    751: kern_return_t
                    752: mach_port_destroy(
                    753:        ipc_space_t             space,
                    754:        mach_port_name_t        name)
                    755: {
                    756:        ipc_entry_t entry;
                    757:        kern_return_t kr;
                    758: 
                    759:        if (space == IS_NULL)
                    760:                return KERN_INVALID_TASK;
                    761: 
                    762:        kr = ipc_right_lookup_write(space, name, &entry);
                    763:        if (kr != KERN_SUCCESS)
                    764:                return kr;
                    765:        /* space is write-locked and active */
                    766: 
                    767:        kr = ipc_right_destroy(space, name, entry); 
                    768:        is_write_unlock(space);
                    769:        return kr;
                    770: }
                    771: 
                    772: /*
                    773:  *     Routine:        mach_port_deallocate [kernel call]
                    774:  *     Purpose:
                    775:  *             Deallocates a user reference from a send right,
                    776:  *             send-once right, or a dead-name right.  May
                    777:  *             deallocate the right, if this is the last uref,
                    778:  *             and destroy the name, if it doesn't denote
                    779:  *             other rights.
                    780:  *     Conditions:
                    781:  *             Nothing locked.
                    782:  *     Returns:
                    783:  *             KERN_SUCCESS            The uref is deallocated.
                    784:  *             KERN_INVALID_TASK       The space is null.
                    785:  *             KERN_INVALID_TASK       The space is dead.
                    786:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    787:  *             KERN_INVALID_RIGHT      The right isn't correct.
                    788:  */
                    789: 
                    790: kern_return_t
                    791: mach_port_deallocate(
                    792:        ipc_space_t             space,
                    793:        mach_port_name_t        name)
                    794: {
                    795:        ipc_entry_t entry;
                    796:        kern_return_t kr;
                    797: 
                    798:        if (space == IS_NULL)
                    799:                return KERN_INVALID_TASK;
                    800: 
                    801:        kr = ipc_right_lookup_write(space, name, &entry);
                    802:        if (kr != KERN_SUCCESS)
                    803:                return kr;
                    804:        /* space is write-locked */
                    805: 
                    806:        kr = ipc_right_dealloc(space, name, entry); /* unlocks space */
                    807:        return kr;
                    808: }
                    809: 
                    810: /*
                    811:  *     Routine:        mach_port_get_refs [kernel call]
                    812:  *     Purpose:
                    813:  *             Retrieves the number of user references held by a right.
                    814:  *             Receive rights, port-set rights, and send-once rights
                    815:  *             always have one user reference.  Returns zero if the
                    816:  *             name denotes a right, but not the queried right.
                    817:  *     Conditions:
                    818:  *             Nothing locked.
                    819:  *     Returns:
                    820:  *             KERN_SUCCESS            Number of urefs returned.
                    821:  *             KERN_INVALID_TASK       The space is null.
                    822:  *             KERN_INVALID_TASK       The space is dead.
                    823:  *             KERN_INVALID_VALUE      "right" isn't a legal value.
                    824:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    825:  */
                    826: 
                    827: kern_return_t
                    828: mach_port_get_refs(
                    829:        ipc_space_t             space,
                    830:        mach_port_name_t        name,
                    831:        mach_port_right_t       right,
                    832:        mach_port_urefs_t       *urefsp)
                    833: {
                    834:        mach_port_type_t type;
                    835:        mach_port_urefs_t urefs;
                    836:        ipc_entry_t entry;
                    837:        kern_return_t kr;
                    838: 
                    839:        if (space == IS_NULL)
                    840:                return KERN_INVALID_TASK;
                    841: 
                    842:        if (right >= MACH_PORT_RIGHT_NUMBER)
                    843:                return KERN_INVALID_VALUE;
                    844: 
                    845:        kr = ipc_right_lookup_write(space, name, &entry);
                    846:        if (kr != KERN_SUCCESS)
                    847:                return kr;
                    848:        /* space is write-locked and active */
                    849: 
                    850:        kr = ipc_right_info(space, name, entry, &type, &urefs); /* unlocks */
                    851:        if (kr != KERN_SUCCESS)
                    852:                return kr;      /* space is unlocked */
                    853:        is_write_unlock(space);
                    854: 
                    855:        if (type & MACH_PORT_TYPE(right))
                    856:                switch (right) {
                    857:                    case MACH_PORT_RIGHT_SEND_ONCE:
                    858:                        assert(urefs == 1);
                    859:                        /* fall-through */
                    860: 
                    861:                    case MACH_PORT_RIGHT_PORT_SET:
                    862:                    case MACH_PORT_RIGHT_RECEIVE:
                    863:                        *urefsp = 1;
                    864:                        break;
                    865: 
                    866:                    case MACH_PORT_RIGHT_DEAD_NAME:
                    867:                    case MACH_PORT_RIGHT_SEND:
                    868:                        assert(urefs > 0);
                    869:                        *urefsp = urefs;
                    870:                        break;
                    871: 
                    872:                    default:
                    873:                        panic("mach_port_get_refs: strange rights");
                    874:                }
                    875:        else
                    876:                *urefsp = 0;
                    877: 
                    878:        return kr;
                    879: }
                    880: 
                    881: /*
                    882:  *     Routine:        mach_port_mod_refs
                    883:  *     Purpose:
                    884:  *             Modifies the number of user references held by a right.
                    885:  *             The resulting number of user references must be non-negative.
                    886:  *             If it is zero, the right is deallocated.  If the name
                    887:  *             doesn't denote other rights, it is destroyed.
                    888:  *     Conditions:
                    889:  *             Nothing locked.
                    890:  *     Returns:
                    891:  *             KERN_SUCCESS            Modified number of urefs.
                    892:  *             KERN_INVALID_TASK       The space is null.
                    893:  *             KERN_INVALID_TASK       The space is dead.
                    894:  *             KERN_INVALID_VALUE      "right" isn't a legal value.
                    895:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    896:  *             KERN_INVALID_RIGHT      Name doesn't denote specified right.
                    897:  *             KERN_INVALID_VALUE      Impossible modification to urefs.
                    898:  *             KERN_UREFS_OVERFLOW     Urefs would overflow.
                    899:  */
                    900: 
                    901: kern_return_t
                    902: mach_port_mod_refs(
                    903:        ipc_space_t             space,
                    904:        mach_port_name_t        name,
                    905:        mach_port_right_t       right,
                    906:        mach_port_delta_t       delta)
                    907: {
                    908:        ipc_entry_t entry;
                    909:        kern_return_t kr;
                    910: 
                    911:        if (space == IS_NULL)
                    912:                return KERN_INVALID_TASK;
                    913: 
                    914:        if (right >= MACH_PORT_RIGHT_NUMBER)
                    915:                return KERN_INVALID_VALUE;
                    916: 
                    917:        kr = ipc_right_lookup_write(space, name, &entry);
                    918:        if (kr != KERN_SUCCESS)
                    919:                return kr;
                    920:        /* space is write-locked and active */
                    921: 
                    922:        kr = ipc_right_delta(space, name, entry, right, delta); /* unlocks */
                    923:        return kr;
                    924: }
                    925: 
                    926: 
                    927: /*
                    928:  *     Routine:        mach_port_set_mscount [kernel call]
                    929:  *     Purpose:
                    930:  *             Changes a receive right's make-send count.
                    931:  *     Conditions:
                    932:  *             Nothing locked.
                    933:  *     Returns:
                    934:  *             KERN_SUCCESS            Set make-send count.
                    935:  *             KERN_INVALID_TASK       The space is null.
                    936:  *             KERN_INVALID_TASK       The space is dead.
                    937:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    938:  *             KERN_INVALID_RIGHT      Name doesn't denote receive rights.
                    939:  */
                    940: 
                    941: kern_return_t
                    942: mach_port_set_mscount(
                    943:        ipc_space_t             space,
                    944:        mach_port_name_t        name,
                    945:        mach_port_mscount_t     mscount)
                    946: {
                    947:        ipc_port_t port;
                    948:        kern_return_t kr;
                    949: 
                    950:        if (space == IS_NULL)
                    951:                return KERN_INVALID_TASK;
                    952: 
                    953:        kr = ipc_port_translate_receive(space, name, &port);
                    954:        if (kr != KERN_SUCCESS)
                    955:                return kr;
                    956:        /* port is locked and active */
                    957: 
                    958:        ipc_port_set_mscount(port, mscount);
                    959: 
                    960:        ip_unlock(port);
                    961:        return KERN_SUCCESS;
                    962: }
                    963: 
                    964: /*
                    965:  *     Routine:        mach_port_set_seqno [kernel call]
                    966:  *     Purpose:
                    967:  *             Changes a receive right's sequence number.
                    968:  *     Conditions:
                    969:  *             Nothing locked.
                    970:  *     Returns:
                    971:  *             KERN_SUCCESS            Set sequence number.
                    972:  *             KERN_INVALID_TASK       The space is null.
                    973:  *             KERN_INVALID_TASK       The space is dead.
                    974:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                    975:  *             KERN_INVALID_RIGHT      Name doesn't denote receive rights.
                    976:  */
                    977: 
                    978: kern_return_t
                    979: mach_port_set_seqno(
                    980:        ipc_space_t             space,
                    981:        mach_port_name_t        name,
                    982:        mach_port_seqno_t       seqno)
                    983: {
                    984:        ipc_port_t port;
                    985:        kern_return_t kr;
                    986: 
                    987:        if (space == IS_NULL)
                    988:                return KERN_INVALID_TASK;
                    989: 
                    990:        kr = ipc_port_translate_receive(space, name, &port);
                    991:        if (kr != KERN_SUCCESS)
                    992:                return kr;
                    993:        /* port is locked and active */
                    994: 
                    995:        ipc_mqueue_set_seqno(&port->ip_messages, seqno);
                    996: 
                    997:        ip_unlock(port);
                    998:        return KERN_SUCCESS;
                    999: }
                   1000: 
                   1001: /*
                   1002:  *     Routine:        mach_port_gst_helper
                   1003:  *     Purpose:
                   1004:  *             A helper function for mach_port_get_set_status.
                   1005:  */
                   1006: 
                   1007: void
                   1008: mach_port_gst_helper(
                   1009:        ipc_pset_t              pset,
                   1010:        ipc_port_t              port,
                   1011:        ipc_entry_num_t         maxnames,
                   1012:        mach_port_name_t        *names,
                   1013:        ipc_entry_num_t         *actualp)
                   1014: {
                   1015:        ipc_pset_t ip_pset;
                   1016:        mach_port_name_t name;
                   1017: 
                   1018:        assert(port != IP_NULL);
                   1019: 
                   1020:        ip_lock(port);
                   1021:        assert(ip_active(port));
                   1022: 
                   1023:        name = port->ip_receiver_name;
                   1024:        assert(name != MACH_PORT_NULL);
                   1025: 
                   1026:        ip_unlock(port);
                   1027: 
                   1028:        if (ipc_pset_member(pset, port)) {
                   1029:                ipc_entry_num_t actual = *actualp;
                   1030: 
                   1031:                if (actual < maxnames)
                   1032:                        names[actual] = name;
                   1033: 
                   1034:                *actualp = actual+1;
                   1035:        }
                   1036: }
                   1037: 
                   1038: /*
                   1039:  *     Routine:        mach_port_get_set_status [kernel call]
                   1040:  *     Purpose:
                   1041:  *             Retrieves a list of members in a port set.
                   1042:  *             Returns the space's name for each receive right member.
                   1043:  *     Conditions:
                   1044:  *             Nothing locked.
                   1045:  *     Returns:
                   1046:  *             KERN_SUCCESS            Retrieved list of members.
                   1047:  *             KERN_INVALID_TASK       The space is null.
                   1048:  *             KERN_INVALID_TASK       The space is dead.
                   1049:  *             KERN_INVALID_NAME       The name doesn't denote a right.
                   1050:  *             KERN_INVALID_RIGHT      Name doesn't denote a port set.
                   1051:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1052:  */
                   1053: 
                   1054: kern_return_t
                   1055: mach_port_get_set_status(
                   1056:        ipc_space_t                     space,
                   1057:        mach_port_name_t                name,
                   1058:        mach_port_name_t                **members,
                   1059:        mach_msg_type_number_t          *membersCnt)
                   1060: {
                   1061:        ipc_entry_num_t actual;         /* this many members */
                   1062:        ipc_entry_num_t maxnames;       /* space for this many members */
                   1063:        kern_return_t kr;
                   1064: 
                   1065:        vm_size_t size;         /* size of allocated memory */
                   1066:        vm_offset_t addr;       /* allocated memory */
                   1067:        vm_map_copy_t memory;   /* copied-in memory */
                   1068: 
                   1069:        if (space == IS_NULL)
                   1070:                return KERN_INVALID_TASK;
                   1071: 
                   1072:        size = PAGE_SIZE;       /* initial guess */
                   1073: 
                   1074:        for (;;) {
                   1075:                ipc_tree_entry_t tentry;
                   1076:                ipc_entry_t entry, table;
                   1077:                ipc_entry_num_t tsize;
                   1078:                mach_port_index_t index;
                   1079:                mach_port_name_t *names;
                   1080:                ipc_pset_t pset;
                   1081: 
                   1082:                kr = vm_allocate(ipc_kernel_map, &addr, size, TRUE);
                   1083:                if (kr != KERN_SUCCESS)
                   1084:                        return KERN_RESOURCE_SHORTAGE;
                   1085: 
                   1086:                /* can't fault while we hold locks */
                   1087: 
                   1088:                kr = vm_map_wire(ipc_kernel_map, addr, addr + size,
                   1089:                                     VM_PROT_READ|VM_PROT_WRITE, FALSE);
                   1090:                assert(kr == KERN_SUCCESS);
                   1091: 
                   1092:                kr = ipc_right_lookup_read(space, name, &entry);
                   1093:                if (kr != KERN_SUCCESS) {
                   1094:                        kmem_free(ipc_kernel_map, addr, size);
                   1095:                        return kr;
                   1096:                }
                   1097:                /* space is read-locked and active */
                   1098: 
                   1099:                if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_PORT_SET) {
                   1100:                        is_read_unlock(space);
                   1101:                        kmem_free(ipc_kernel_map, addr, size);
                   1102:                        return KERN_INVALID_RIGHT;
                   1103:                }
                   1104: 
                   1105:                pset = (ipc_pset_t) entry->ie_object;
                   1106:                assert(pset != IPS_NULL);
                   1107:                /* the port set must be active */
                   1108: 
                   1109:                names = (mach_port_name_t *) addr;
                   1110:                maxnames = size / sizeof(mach_port_name_t);
                   1111:                actual = 0;
                   1112: 
                   1113:                table = space->is_table;
                   1114:                tsize = space->is_table_size;
                   1115: 
                   1116:                for (index = 0; index < tsize; index++) {
                   1117:                        ipc_entry_t ientry = &table[index];
                   1118: 
                   1119:                        if (ientry->ie_bits & MACH_PORT_TYPE_RECEIVE) {
                   1120:                                ipc_port_t port =
                   1121:                                        (ipc_port_t) ientry->ie_object;
                   1122: 
                   1123:                                mach_port_gst_helper(pset, port,
                   1124:                                                     maxnames, names, &actual);
                   1125:                        }
                   1126:                }
                   1127: 
                   1128:                for (tentry = ipc_splay_traverse_start(&space->is_tree);
                   1129:                    tentry != ITE_NULL;
                   1130:                    tentry = ipc_splay_traverse_next(&space->is_tree,FALSE)) {
                   1131:                        ipc_entry_bits_t bits = tentry->ite_bits;
                   1132: 
                   1133:                        assert(IE_BITS_TYPE(bits) != MACH_PORT_TYPE_NONE);
                   1134: 
                   1135:                        if (bits & MACH_PORT_TYPE_RECEIVE) {
                   1136:                            ipc_port_t port = (ipc_port_t) tentry->ite_object;
                   1137: 
                   1138:                            mach_port_gst_helper(pset, port, maxnames,
                   1139:                                                 names, &actual);
                   1140:                        }
                   1141:                }
                   1142:                ipc_splay_traverse_finish(&space->is_tree);
                   1143:                is_read_unlock(space);
                   1144: 
                   1145:                if (actual <= maxnames)
                   1146:                        break;
                   1147: 
                   1148:                /* didn't have enough memory; allocate more */
                   1149: 
                   1150:                kmem_free(ipc_kernel_map, addr, size);
                   1151:                size = round_page(actual * sizeof(mach_port_name_t)) + PAGE_SIZE;
                   1152:        }
                   1153: 
                   1154:        if (actual == 0) {
                   1155:                memory = VM_MAP_COPY_NULL;
                   1156: 
                   1157:                kmem_free(ipc_kernel_map, addr, size);
                   1158:        } else {
                   1159:                vm_size_t size_used;
                   1160:                vm_size_t vm_size_used;
                   1161: 
                   1162:                size_used = actual * sizeof(mach_port_name_t);
                   1163:                vm_size_used = round_page(size_used);
                   1164: 
                   1165:                /*
                   1166:                 *      Make used memory pageable and get it into
                   1167:                 *      copied-in form.  Free any unused memory.
                   1168:                 */
                   1169: 
                   1170:                kr = vm_map_unwire(ipc_kernel_map,
                   1171:                                     addr, addr + vm_size_used, FALSE);
                   1172:                assert(kr == KERN_SUCCESS);
                   1173: 
                   1174:                kr = vm_map_copyin(ipc_kernel_map, addr, size_used,
                   1175:                                   TRUE, &memory);
                   1176:                assert(kr == KERN_SUCCESS);
                   1177: 
                   1178:                if (vm_size_used != size)
                   1179:                        kmem_free(ipc_kernel_map,
                   1180:                                  addr + vm_size_used, size - vm_size_used);
                   1181:        }
                   1182: 
                   1183:        *members = (mach_port_name_t *) memory;
                   1184:        *membersCnt = actual;
                   1185:        return KERN_SUCCESS;
                   1186: }
                   1187: 
                   1188: /*
                   1189:  *     Routine:        mach_port_move_member [kernel call]
                   1190:  *     Purpose:
                   1191:  *             If after is MACH_PORT_NULL, removes member
                   1192:  *             from the port set it is in.  Otherwise, adds
                   1193:  *             member to after, removing it from any set
                   1194:  *             it might already be in.
                   1195:  *     Conditions:
                   1196:  *             Nothing locked.
                   1197:  *     Returns:
                   1198:  *             KERN_SUCCESS            Moved the port.
                   1199:  *             KERN_INVALID_TASK       The space is null.
                   1200:  *             KERN_INVALID_TASK       The space is dead.
                   1201:  *             KERN_INVALID_NAME       Member didn't denote a right.
                   1202:  *             KERN_INVALID_RIGHT      Member didn't denote a receive right.
                   1203:  *             KERN_INVALID_NAME       After didn't denote a right.
                   1204:  *             KERN_INVALID_RIGHT      After didn't denote a port set right.
                   1205:  *             KERN_NOT_IN_SET
                   1206:  *                     After is MACH_PORT_NULL and Member isn't in a port set.
                   1207:  */
                   1208: 
                   1209: kern_return_t
                   1210: mach_port_move_member(
                   1211:        ipc_space_t             space,
                   1212:        mach_port_name_t        member,
                   1213:        mach_port_name_t        after)
                   1214: {
                   1215:        ipc_entry_t entry;
                   1216:        ipc_port_t port;
                   1217:        ipc_pset_t nset;
                   1218:        kern_return_t kr;
                   1219: 
                   1220:        if (space == IS_NULL)
                   1221:                return KERN_INVALID_TASK;
                   1222: 
                   1223:        kr = ipc_right_lookup_read(space, member, &entry);
                   1224:        if (kr != KERN_SUCCESS)
                   1225:                return kr;
                   1226:        /* space is read-locked and active */
                   1227: 
                   1228:        if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
                   1229:                is_read_unlock(space);
                   1230:                return KERN_INVALID_RIGHT;
                   1231:        }
                   1232: 
                   1233:        port = (ipc_port_t) entry->ie_object;
                   1234:        assert(port != IP_NULL);
                   1235: 
                   1236:        if (after == MACH_PORT_NULL)
                   1237:                nset = IPS_NULL;
                   1238:        else {
                   1239:                entry = ipc_entry_lookup(space, after);
                   1240:                if (entry == IE_NULL) {
                   1241:                        is_read_unlock(space);
                   1242:                        return KERN_INVALID_NAME;
                   1243:                }
                   1244: 
                   1245:                if ((entry->ie_bits & MACH_PORT_TYPE_PORT_SET) == 0) {
                   1246:                        is_read_unlock(space);
                   1247:                        return KERN_INVALID_RIGHT;
                   1248:                }
                   1249: 
                   1250:                nset = (ipc_pset_t) entry->ie_object;
                   1251:                assert(nset != IPS_NULL);
                   1252:        }
                   1253:        ip_lock(port);
                   1254:        ipc_pset_remove_all(port);
                   1255: 
                   1256:        if (nset != IPS_NULL) {
                   1257:                ips_lock(nset);
                   1258:                kr = ipc_pset_add(nset, port);
                   1259:                ips_unlock(nset);
                   1260:        }
                   1261:        ip_unlock(port);
                   1262:        is_read_unlock(space);
                   1263:        return kr;
                   1264: }
                   1265: 
                   1266: /*
                   1267:  *     Routine:        mach_port_request_notification [kernel call]
                   1268:  *     Purpose:
                   1269:  *             Requests a notification.  The caller supplies
                   1270:  *             a send-once right for the notification to use,
                   1271:  *             and the call returns the previously registered
                   1272:  *             send-once right, if any.  Possible types:
                   1273:  *
                   1274:  *             MACH_NOTIFY_PORT_DESTROYED
                   1275:  *                     Requests a port-destroyed notification
                   1276:  *                     for a receive right.  Sync should be zero.
                   1277:  *             MACH_NOTIFY_NO_SENDERS
                   1278:  *                     Requests a no-senders notification for a
                   1279:  *                     receive right.  If there are currently no
                   1280:  *                     senders, sync is less than or equal to the
                   1281:  *                     current make-send count, and a send-once right
                   1282:  *                     is supplied, then an immediate no-senders
                   1283:  *                     notification is generated.
                   1284:  *             MACH_NOTIFY_DEAD_NAME
                   1285:  *                     Requests a dead-name notification for a send
                   1286:  *                     or receive right.  If the name is already a
                   1287:  *                     dead name, sync is non-zero, and a send-once
                   1288:  *                     right is supplied, then an immediate dead-name
                   1289:  *                     notification is generated.
                   1290:  *     Conditions:
                   1291:  *             Nothing locked.
                   1292:  *     Returns:
                   1293:  *             KERN_SUCCESS            Requested a notification.
                   1294:  *             KERN_INVALID_TASK       The space is null.
                   1295:  *             KERN_INVALID_TASK       The space is dead.
                   1296:  *             KERN_INVALID_VALUE      Bad id value.
                   1297:  *             KERN_INVALID_NAME       Name doesn't denote a right.
                   1298:  *             KERN_INVALID_RIGHT      Name doesn't denote appropriate right.
                   1299:  *             KERN_INVALID_CAPABILITY The notify port is dead.
                   1300:  *     MACH_NOTIFY_PORT_DESTROYED:
                   1301:  *             KERN_INVALID_VALUE      Sync isn't zero.
                   1302:  *     MACH_NOTIFY_DEAD_NAME:
                   1303:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1304:  *             KERN_INVALID_ARGUMENT   Name denotes dead name, but
                   1305:  *                     sync is zero or notify is IP_NULL.
                   1306:  *             KERN_UREFS_OVERFLOW     Name denotes dead name, but
                   1307:  *                     generating immediate notif. would overflow urefs.
                   1308:  */
                   1309: 
                   1310: kern_return_t
                   1311: mach_port_request_notification(
                   1312:        ipc_space_t             space,
                   1313:        mach_port_name_t        name,
                   1314:        mach_msg_id_t           id,
                   1315:        mach_port_mscount_t     sync,
                   1316:        ipc_port_t              notify,
                   1317:        ipc_port_t              *previousp)
                   1318: {
                   1319:        kern_return_t kr;
                   1320:        ipc_entry_t entry;      
                   1321:        ipc_port_t port;
                   1322:        
                   1323: 
                   1324:        if (space == IS_NULL)
                   1325:                return KERN_INVALID_TASK;
                   1326: 
                   1327:        if (notify == IP_DEAD)
                   1328:                return KERN_INVALID_CAPABILITY;
                   1329: 
                   1330: #if    NOTYET
                   1331:        /*
                   1332:         *      Requesting notifications on RPC ports is an error.
                   1333:         */
                   1334:        kr = ipc_right_lookup_write(space, name, &entry);       
                   1335:        if (kr != KERN_SUCCESS)
                   1336:                return kr;
                   1337: 
                   1338:        port = (ipc_port_t) entry->ie_object;
                   1339: 
                   1340:        if (port->ip_subsystem != NULL) {
                   1341:                is_write_unlock(space);
                   1342:                panic("mach_port_request_notification: on RPC port!!"); 
                   1343:                return KERN_INVALID_CAPABILITY;
                   1344:        }
                   1345:        is_write_unlock(space);
                   1346: #endif         /* NOTYET */
                   1347: 
                   1348: 
                   1349:        switch (id) {
                   1350:            case MACH_NOTIFY_PORT_DESTROYED: {
                   1351:                ipc_port_t port, previous;
                   1352: 
                   1353:                if (sync != 0)
                   1354:                        return KERN_INVALID_VALUE;
                   1355: 
                   1356:                kr = ipc_port_translate_receive(space, name, &port);
                   1357:                if (kr != KERN_SUCCESS)
                   1358:                        return kr;
                   1359:                /* port is locked and active */
                   1360: 
                   1361:                ipc_port_pdrequest(port, notify, &previous);
                   1362:                /* port is unlocked */
                   1363: 
                   1364:                *previousp = previous;
                   1365:                break;
                   1366:            }
                   1367: 
                   1368:            case MACH_NOTIFY_NO_SENDERS: {
                   1369:                ipc_port_t port;
                   1370: 
                   1371:                kr = ipc_port_translate_receive(space, name, &port);
                   1372:                if (kr != KERN_SUCCESS)
                   1373:                        return kr;
                   1374:                /* port is locked and active */
                   1375: 
                   1376:                if (!IP_NMS(port)) {
                   1377:                        ip_unlock(port);
                   1378:                        return KERN_INVALID_RIGHT;
                   1379:                }
                   1380: 
                   1381:                ipc_port_nsrequest(port, sync, notify, previousp);
                   1382:                /* port is unlocked */
                   1383:                break;
                   1384:            }
                   1385: 
                   1386:            case MACH_NOTIFY_DEAD_NAME:
                   1387:                kr = ipc_right_dnrequest(space, name, sync != 0,
                   1388:                                         notify, previousp);
                   1389:                if (kr != KERN_SUCCESS)
                   1390:                        return kr;
                   1391:                break;
                   1392: 
                   1393:            default:
                   1394:                return KERN_INVALID_VALUE;
                   1395:        }
                   1396: 
                   1397:        return KERN_SUCCESS;
                   1398: }
                   1399: 
                   1400: /*
                   1401:  *     Routine:        mach_port_insert_right [kernel call]
                   1402:  *     Purpose:
                   1403:  *             Inserts a right into a space, as if the space
                   1404:  *             voluntarily received the right in a message,
                   1405:  *             except that the right gets the specified name.
                   1406:  *     Conditions:
                   1407:  *             Nothing locked.
                   1408:  *     Returns:
                   1409:  *             KERN_SUCCESS            Inserted the right.
                   1410:  *             KERN_INVALID_TASK       The space is null.
                   1411:  *             KERN_INVALID_TASK       The space is dead.
                   1412:  *             KERN_INVALID_VALUE      The name isn't a legal name.
                   1413:  *             KERN_NAME_EXISTS        The name already denotes a right.
                   1414:  *             KERN_INVALID_VALUE      Message doesn't carry a port right.
                   1415:  *             KERN_INVALID_CAPABILITY Port is null or dead.
                   1416:  *             KERN_UREFS_OVERFLOW     Urefs limit would be exceeded.
                   1417:  *             KERN_RIGHT_EXISTS       Space has rights under another name.
                   1418:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                   1419:  */
                   1420: 
                   1421: kern_return_t
                   1422: mach_port_insert_right(
                   1423:        ipc_space_t                     space,
                   1424:        mach_port_name_t                name,
                   1425:        ipc_port_t                      poly,
                   1426:        mach_msg_type_name_t            polyPoly)
                   1427: {
                   1428:        if (space == IS_NULL)
                   1429:                return KERN_INVALID_TASK;
                   1430: 
                   1431:        if (!MACH_PORT_VALID(name) ||
                   1432:            !MACH_MSG_TYPE_PORT_ANY_RIGHT(polyPoly))
                   1433:                return KERN_INVALID_VALUE;
                   1434: 
                   1435:        if (!IO_VALID((ipc_object_t) poly))
                   1436:                return KERN_INVALID_CAPABILITY;
                   1437: 
                   1438:        return ipc_object_copyout_name(space, (ipc_object_t) poly, 
                   1439:                                       polyPoly, FALSE, name);
                   1440: }
                   1441: 
                   1442: /*
                   1443:  *     Routine:        mach_port_extract_right [kernel call]
                   1444:  *     Purpose:
                   1445:  *             Extracts a right from a space, as if the space
                   1446:  *             voluntarily sent the right to the caller.
                   1447:  *     Conditions:
                   1448:  *             Nothing locked.
                   1449:  *     Returns:
                   1450:  *             KERN_SUCCESS            Extracted the right.
                   1451:  *             KERN_INVALID_TASK       The space is null.
                   1452:  *             KERN_INVALID_TASK       The space is dead.
                   1453:  *             KERN_INVALID_VALUE      Requested type isn't a port right.
                   1454:  *             KERN_INVALID_NAME       Name doesn't denote a right.
                   1455:  *             KERN_INVALID_RIGHT      Name doesn't denote appropriate right.
                   1456:  */
                   1457: 
                   1458: kern_return_t
                   1459: mach_port_extract_right(
                   1460:        ipc_space_t             space,
                   1461:        mach_port_name_t        name,
                   1462:        mach_msg_type_name_t    msgt_name,
                   1463:        ipc_port_t              *poly,
                   1464:        mach_msg_type_name_t    *polyPoly)
                   1465: {
                   1466:        kern_return_t kr;
                   1467: 
                   1468:        if (space == IS_NULL)
                   1469:                return KERN_INVALID_TASK;
                   1470: 
                   1471:        if (!MACH_MSG_TYPE_PORT_ANY(msgt_name))
                   1472:                return KERN_INVALID_VALUE;
                   1473: 
                   1474:        kr = ipc_object_copyin(space, name, msgt_name, (ipc_object_t *) poly);
                   1475: 
                   1476:        if (kr == KERN_SUCCESS)
                   1477:                *polyPoly = ipc_object_copyin_type(msgt_name);
                   1478:        return kr;
                   1479: }
                   1480: 
                   1481: 
                   1482: kern_return_t
                   1483: mach_port_get_attributes(
                   1484:        ipc_space_t             space,
                   1485:        mach_port_name_t        name,
                   1486:        int                     flavor,
                   1487:         mach_port_info_t       info,
                   1488:         mach_msg_type_number_t *count)
                   1489: {
                   1490:        ipc_port_t port;
                   1491:        kern_return_t kr;
                   1492: 
                   1493:        if (space == IS_NULL)
                   1494:                return KERN_INVALID_TASK;
                   1495: 
                   1496:         switch (flavor) {
                   1497:         case MACH_PORT_LIMITS_INFO: {
                   1498:                 mach_port_limits_t *lp = (mach_port_limits_t *)info;
                   1499: 
                   1500:                 if (*count < MACH_PORT_LIMITS_INFO_COUNT)
                   1501:                         return KERN_FAILURE;
                   1502:                 
                   1503:                 kr = ipc_port_translate_receive(space, name, &port);
                   1504:                 if (kr != KERN_SUCCESS)
                   1505:                         return kr;
                   1506:                 /* port is locked and active */
                   1507: 
                   1508:                 lp->mpl_qlimit = port->ip_messages.imq_qlimit;
                   1509:                 *count = MACH_PORT_LIMITS_INFO_COUNT;
                   1510:                 ip_unlock(port);
                   1511:                 break;
                   1512:         }
                   1513: 
                   1514:         case MACH_PORT_RECEIVE_STATUS: {
                   1515:                 mach_port_status_t *statusp = (mach_port_status_t *)info;
                   1516:                 
                   1517:                 if (*count < MACH_PORT_RECEIVE_STATUS_COUNT)
                   1518:                         return KERN_FAILURE;
                   1519:                 
                   1520:                 kr = ipc_port_translate_receive(space, name, &port);
                   1521:                 if (kr != KERN_SUCCESS)
                   1522:                         return kr;
                   1523:                 /* port is locked and active */
                   1524: 
                   1525:                statusp->mps_pset = port->ip_pset_count;
                   1526:                imq_lock(&port->ip_messages);
                   1527:                statusp->mps_seqno = port->ip_messages.imq_seqno;
                   1528:                 statusp->mps_qlimit = port->ip_messages.imq_qlimit;
                   1529:                 statusp->mps_msgcount = port->ip_messages.imq_msgcount;
                   1530:                imq_unlock(&port->ip_messages);
                   1531: 
                   1532:                 statusp->mps_mscount = port->ip_mscount;
                   1533:                 statusp->mps_sorights = port->ip_sorights;
                   1534:                 statusp->mps_srights = port->ip_srights > 0;
                   1535:                 statusp->mps_pdrequest = port->ip_pdrequest != IP_NULL;
                   1536:                 statusp->mps_nsrequest = port->ip_nsrequest != IP_NULL;
                   1537:                statusp->mps_flags = port->ip_flags;
                   1538: 
                   1539:                 *count = MACH_PORT_RECEIVE_STATUS_COUNT;
                   1540:                 ip_unlock(port);
                   1541:                 break;
                   1542:         }
                   1543:        
                   1544:        case MACH_PORT_DNREQUESTS_SIZE: {
                   1545:                ipc_port_request_t      table;
                   1546:                
                   1547:                 if (*count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
                   1548:                         return KERN_FAILURE;
                   1549:                
                   1550:                 kr = ipc_port_translate_receive(space, name, &port);
                   1551:                 if (kr != KERN_SUCCESS)
                   1552:                         return kr;
                   1553:                 /* port is locked and active */
                   1554:                
                   1555:                table = port->ip_dnrequests;
                   1556:                if (table == IPR_NULL)
                   1557:                        *(int *)info = 0;
                   1558:                else
                   1559:                        *(int *)info = table->ipr_size->its_size;
                   1560:                 *count = MACH_PORT_DNREQUESTS_SIZE_COUNT;
                   1561:                 ip_unlock(port);
                   1562:                break;
                   1563:        }
                   1564: 
                   1565:         default:
                   1566:                return KERN_INVALID_ARGUMENT;
                   1567:                 /*NOTREACHED*/
                   1568:         }                
                   1569: 
                   1570:        return KERN_SUCCESS;
                   1571: }
                   1572: 
                   1573: kern_return_t
                   1574: mach_port_set_attributes(
                   1575:        ipc_space_t             space,
                   1576:        mach_port_name_t        name,
                   1577:        int                     flavor,
                   1578:         mach_port_info_t       info,
                   1579:         mach_msg_type_number_t count)
                   1580: {
                   1581:        ipc_port_t port;
                   1582:        kern_return_t kr;
                   1583:         
                   1584:        if (space == IS_NULL)
                   1585:                return KERN_INVALID_TASK;
                   1586: 
                   1587:         switch (flavor) {
                   1588:                 
                   1589:         case MACH_PORT_LIMITS_INFO: {
                   1590:                 mach_port_limits_t *mplp = (mach_port_limits_t *)info;
                   1591:                 
                   1592:                 if (count < MACH_PORT_LIMITS_INFO_COUNT)
                   1593:                         return KERN_FAILURE;
                   1594:                 
                   1595:                 if (mplp->mpl_qlimit > MACH_PORT_QLIMIT_MAX)
                   1596:                         return KERN_INVALID_VALUE;
                   1597: 
                   1598:                 kr = ipc_port_translate_receive(space, name, &port);
                   1599:                 if (kr != KERN_SUCCESS)
                   1600:                         return kr;
                   1601:                 /* port is locked and active */
                   1602: 
                   1603:                 ipc_mqueue_set_qlimit(&port->ip_messages, mplp->mpl_qlimit);
                   1604:                 ip_unlock(port);
                   1605:                 break;
                   1606:         }
                   1607:        case MACH_PORT_DNREQUESTS_SIZE: {
                   1608:                 if (count < MACH_PORT_DNREQUESTS_SIZE_COUNT)
                   1609:                         return KERN_FAILURE;
                   1610:                 
                   1611:                 kr = ipc_port_translate_receive(space, name, &port);
                   1612:                 if (kr != KERN_SUCCESS)
                   1613:                         return kr;
                   1614:                 /* port is locked and active */
                   1615:                
                   1616:                kr = ipc_port_dngrow(port, *(int *)info);
                   1617:                if (kr != KERN_SUCCESS)
                   1618:                        return kr;
                   1619:                break;
                   1620:        }
                   1621:         default:
                   1622:                return KERN_INVALID_ARGUMENT;
                   1623:                 /*NOTREACHED*/
                   1624:         }
                   1625:        return KERN_SUCCESS;
                   1626: }
                   1627: 
                   1628: 
                   1629: /*
                   1630:  * Create an empty thread_activation (sans thread_shuttle) attached to
                   1631:  * a port or port set in a given task to receive incoming threads.
                   1632:  */
                   1633: /*
                   1634:  * NOTE: the following calls targeted at a thread_act port may be
                   1635:  * called on an empty thread_act:
                   1636:  *
                   1637:  * thread_get_exception_ports  thread_set_exception_ports
                   1638:  * thread_get_special_port     thread_set_special_port
                   1639:  * thread_get_state            thread_suspend
                   1640:  * thread_resume               thread_swap_exception_ports
                   1641:  * thread_sample               thread_terminate
                   1642:  *
                   1643:  * The following calls targeted at a thread_act port may _not_ be
                   1644:  * called on an empty thread_act (and will return KERN_INVALID_ARGUMENT
                   1645:  * if they are called with one):
                   1646:  *
                   1647:  * thread_abort                thread_info
                   1648:  * thread_abort_safely         thread_wire
                   1649:  * thread_depress_abort
                   1650:  *
                   1651:  * Also, if thread_switch() is called with an empty thread_act as
                   1652:  * its first argument, the argument will be ignored (i.e., the
                   1653:  * function will behave as if a zero-valued argument had been
                   1654:  * given).
                   1655:  */
                   1656: kern_return_t
                   1657: thread_activation_create(
                   1658:        task_t                  task,
                   1659:        mach_port_name_t        name,
                   1660:        act_params_t            act_params,
                   1661:        thread_act_t            *new_act)
                   1662: {
                   1663:        ipc_space_t space;
                   1664:        ipc_object_t object;
                   1665:        kern_return_t kr;
                   1666:        thread_act_t thr_act;
                   1667:        int is_port = 1;
                   1668:         thread_act_params_t params = (thread_act_params_t)act_params;
                   1669: 
                   1670:        if (task == TASK_NULL)
                   1671:                return KERN_INVALID_TASK;
                   1672: 
                   1673:        /* First create the new activation.  */
                   1674:        /*
                   1675:         * We'll need this stack later -- make sure it's present.
                   1676:         */
                   1677:         assert(params != 0);
                   1678:        assert(params->stack != 0);
                   1679:        kr = act_create(task, params, &thr_act);
                   1680:        if (kr != KERN_SUCCESS)
                   1681:                return kr;
                   1682: 
                   1683:        space = task->itk_space;
                   1684: 
                   1685:        kr = ipc_object_translate(space, name,
                   1686:                                  MACH_PORT_RIGHT_PORT_SET, &object);
                   1687:        if (kr != KERN_SUCCESS) {
                   1688:                kr = ipc_object_translate(space, name,
                   1689:                                          MACH_PORT_RIGHT_RECEIVE, &object);
                   1690:                if (kr != KERN_SUCCESS) {
                   1691:                        thread_terminate(thr_act);
                   1692:                        act_deallocate(thr_act);
                   1693:                        return kr;
                   1694:                }
                   1695:                is_port = 0;
                   1696:        }
                   1697:        /* port/pset is locked and active */
                   1698: 
                   1699: #if    MACH_ASSERT
                   1700:        if (watchacts & WA_PORT)
                   1701:                printf("thr_act on %s=%x stack=%x thr_act=%x\n",
                   1702:                       (is_port ? "port" : "pset"),
                   1703:                       object, params->stack, thr_act);
                   1704: #endif /* MACH_ASSERT */
                   1705: 
                   1706:        /* Assign the activation to the thread_pool.  */
                   1707:        kr = act_set_thread_pool(thr_act, (ipc_port_t)object);
                   1708:        if (kr != KERN_SUCCESS) {
                   1709:                io_unlock(object);
                   1710:                thread_terminate(thr_act);
                   1711:                act_deallocate(thr_act);
                   1712:                return kr;
                   1713:        }
                   1714:        io_unlock(object);
                   1715: 
                   1716: #if    MACH_ASSERT
                   1717:        if (watchacts & WA_PORT)
                   1718:                printf("\tpool_port=%x thr_act=%x\n", (ipc_port_t)object, thr_act);
                   1719: #endif /* MACH_ASSERT */
                   1720: 
                   1721:        /* Pass our reference to the activation back to the user.  */
                   1722:        *new_act = thr_act;
                   1723: 
                   1724:        return KERN_SUCCESS;
                   1725: }
                   1726: 
                   1727: /*
                   1728:  *     Routine:        mach_port_insert_member [kernel call]
                   1729:  *     Purpose:
                   1730:  *             Add the receive right, specified by name, to
                   1731:  *             a portset.
                   1732:  *             The port cannot already be a member of the set.
                   1733:  *     Conditions:
                   1734:  *             Nothing locked.
                   1735:  *     Returns:
                   1736:  *             KERN_SUCCESS            Moved the port.
                   1737:  *             KERN_INVALID_TASK       The space is null.
                   1738:  *             KERN_INVALID_TASK       The space is dead.
                   1739:  *             KERN_INVALID_NAME       name didn't denote a right.
                   1740:  *             KERN_INVALID_RIGHT      name didn't denote a receive right.
                   1741:  *             KERN_INVALID_NAME       pset_name didn't denote a right.
                   1742:  *             KERN_INVALID_RIGHT      pset_name didn't denote a portset right.
                   1743:  *             KERN_ALREADY_IN_SET     name was already a member of pset.
                   1744:  */
                   1745: 
                   1746: kern_return_t
                   1747: mach_port_insert_member(
                   1748:        ipc_space_t             space,
                   1749:        mach_port_name_t        name,
                   1750:        mach_port_name_t        pset_name)
                   1751: {
                   1752:        ipc_object_t obj;
                   1753:        ipc_object_t pset_obj;
                   1754:        kern_return_t kr;
                   1755: 
                   1756:        if (space == IS_NULL)
                   1757:                return KERN_INVALID_TASK;
                   1758: 
                   1759:        kr = ipc_object_translate(space, pset_name, MACH_PORT_RIGHT_PORT_SET,
                   1760:                                  &pset_obj);  /* pset locked */
                   1761:        if (kr != KERN_SUCCESS)
                   1762:                return kr;
                   1763:        assert(pset_obj != IO_NULL);
                   1764: 
                   1765:        kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE, &obj);
                   1766: 
                   1767:        if (kr != KERN_SUCCESS) {
                   1768:                io_unlock(pset_obj);
                   1769:                return kr;
                   1770:        }
                   1771: 
                   1772:        assert(obj != IO_NULL);
                   1773: 
                   1774:        kr = ipc_pset_add((ipc_pset_t)pset_obj, (ipc_port_t)obj);
                   1775:        io_unlock(pset_obj);
                   1776:        io_unlock(obj);
                   1777:        return kr;
                   1778: }
                   1779: 
                   1780: /*
                   1781:  *     Routine:        mach_port_extract_member [kernel call]
                   1782:  *     Purpose:
                   1783:  *             If after is MACH_PORT_NULL, removes member
                   1784:  *             from the port set it is in.
                   1785:  *     Conditions:
                   1786:  *             Nothing locked.
                   1787:  *     Returns:
                   1788:  *             KERN_SUCCESS            Moved the port.
                   1789:  *             KERN_INVALID_TASK       The space is null.
                   1790:  *             KERN_INVALID_TASK       The space is dead.
                   1791:  *             KERN_INVALID_NAME       Member didn't denote a right.
                   1792:  *             KERN_INVALID_RIGHT      Member didn't denote a receive right.
                   1793:  *             KERN_INVALID_NAME       After didn't denote a right.
                   1794:  *             KERN_INVALID_RIGHT      After didn't denote a port set right.
                   1795:  *             KERN_NOT_IN_SET
                   1796:  *                     After is MACH_PORT_NULL and Member isn't in a port set.
                   1797:  */
                   1798: 
                   1799: kern_return_t
                   1800: mach_port_extract_member(
                   1801:        ipc_space_t             space,
                   1802:        mach_port_name_t        name,
                   1803:        mach_port_name_t        pset_name)
                   1804: {
                   1805:        mach_port_name_t oldname;
                   1806:        ipc_object_t pset_obj;
                   1807:        ipc_object_t obj;
                   1808:        kern_return_t kr;
                   1809: 
                   1810:        if (space == IS_NULL)
                   1811:                return KERN_INVALID_TASK;
                   1812: 
                   1813:        kr = ipc_object_translate(space, pset_name, MACH_PORT_RIGHT_PORT_SET,
                   1814:                                  &pset_obj);  /* pset locked and active */
                   1815:        if (kr != KERN_SUCCESS)
                   1816:                return kr;
                   1817:        assert(pset_obj != IO_NULL);
                   1818: 
                   1819:        kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE,
                   1820:                                  &obj);  /* obj locked and active */
                   1821:        if (kr != KERN_SUCCESS) {
                   1822:                io_unlock(pset_obj);
                   1823:                return kr;
                   1824:        }
                   1825: 
                   1826:        kr = ipc_pset_remove((ipc_pset_t)pset_obj, (ipc_port_t)obj);
                   1827:        io_unlock(pset_obj);
                   1828:        io_unlock(obj);
                   1829:        
                   1830:        if (kr != KERN_SUCCESS)
                   1831:                return kr;
                   1832: 
                   1833:        return kr;
                   1834: }
                   1835: 

unix.superglobalmegacorp.com

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