Annotation of XNU/osfmk/ipc/mach_port.c, revision 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.