Annotation of kernel/ipc/mach_msg.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*
        !            26:  * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990  
        !            27:  * Open Software Foundation, Inc. 
        !            28:  *  
        !            29:  * Permission to use, copy, modify, and distribute this software and 
        !            30:  * its documentation for any purpose and without fee is hereby granted, 
        !            31:  * provided that the above copyright notice appears in all copies and 
        !            32:  * that both the copyright notice and this permission notice appear in 
        !            33:  * supporting documentation, and that the name of ("OSF") or Open Software 
        !            34:  * Foundation not be used in advertising or publicity pertaining to 
        !            35:  * distribution of the software without specific, written prior permission. 
        !            36:  *  
        !            37:  * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
        !            38:  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
        !            39:  * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY 
        !            40:  * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 
        !            41:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
        !            42:  * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING 
        !            43:  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE 
        !            44:  */
        !            45: /*
        !            46:  * OSF Research Institute MK6.1 (unencumbered) 1/31/1995
        !            47:  */
        !            48: /* 
        !            49:  * Mach Operating System
        !            50:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
        !            51:  * All Rights Reserved.
        !            52:  * 
        !            53:  * Permission to use, copy, modify and distribute this software and its
        !            54:  * documentation is hereby granted, provided that both the copyright
        !            55:  * notice and this permission notice appear in all copies of the
        !            56:  * software, derivative works or modified versions, and any portions
        !            57:  * thereof, and that both notices appear in supporting documentation.
        !            58:  * 
        !            59:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            60:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            61:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            62:  * 
        !            63:  * Carnegie Mellon requests users of this software to return to
        !            64:  * 
        !            65:  *  Software Distribution Coordinator  or  [email protected]
        !            66:  *  School of Computer Science
        !            67:  *  Carnegie Mellon University
        !            68:  *  Pittsburgh PA 15213-3890
        !            69:  * 
        !            70:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            71:  * the rights to redistribute these changes.
        !            72:  */
        !            73: /*
        !            74:  *     File:   ipc/mach_msg.c
        !            75:  *     Author: Rich Draves
        !            76:  *     Date:   1989
        !            77:  *
        !            78:  *     Exported message traps.  See mach/message.h.
        !            79:  */
        !            80: 
        !            81: #import <mach/features.h>
        !            82: 
        !            83: #include <mach/kern_return.h>
        !            84: #include <mach/port.h>
        !            85: #include <mach/message.h>
        !            86: #include <kern/assert.h>
        !            87: #include <kern/counters.h>
        !            88: #include <kern/lock.h>
        !            89: #include <kern/sched_prim.h>
        !            90: #include <kern/ipc_sched.h>
        !            91: #include <vm/vm_map.h>
        !            92: #include <ipc/ipc_kmsg.h>
        !            93: #include <ipc/ipc_marequest.h>
        !            94: #include <ipc/ipc_mqueue.h>
        !            95: #include <ipc/ipc_object.h>
        !            96: #include <ipc/ipc_notify.h>
        !            97: #include <ipc/ipc_port.h>
        !            98: #include <ipc/ipc_pset.h>
        !            99: #include <ipc/ipc_space.h>
        !           100: #include <ipc/ipc_thread.h>
        !           101: #include <ipc/ipc_entry.h>
        !           102: #include <ipc/mach_msg.h>
        !           103: 
        !           104: /*
        !           105:  * Forward declarations
        !           106:  */
        !           107: 
        !           108: mach_msg_return_t mach_msg_send(
        !           109:        mach_msg_header_t       *msg,
        !           110:        mach_msg_option_t       option,
        !           111:        mach_msg_size_t         send_size,
        !           112:        mach_msg_timeout_t      timeout,
        !           113:        mach_port_t             notify);
        !           114: 
        !           115: mach_msg_return_t mach_msg_receive(
        !           116:        mach_msg_header_t       *msg,
        !           117:        mach_msg_option_t       option,
        !           118:        mach_msg_size_t         rcv_size,
        !           119:        mach_port_t             rcv_name,
        !           120:        mach_msg_timeout_t      timeout,
        !           121:        mach_port_t             notify,
        !           122:        mach_msg_size_t         list_size);
        !           123: 
        !           124: mach_msg_return_t mach_msg_receive_error(
        !           125:        ipc_kmsg_t              kmsg,
        !           126:        mach_msg_header_t       *msg,
        !           127:        mach_msg_option_t       option,
        !           128:        mach_port_seqno_t       seqno,
        !           129:        ipc_space_t             space);
        !           130: 
        !           131: /* the size of each trailer has to be listed here for copyout purposes */
        !           132: vm_size_t trailer_size[] = {
        !           133:           sizeof (mach_msg_trailer_t), 
        !           134:          sizeof (mach_msg_seqno_trailer_t),
        !           135:          sizeof (mach_msg_security_trailer_t)
        !           136: };
        !           137: 
        !           138: /*
        !           139:  *     Routine:        mach_msg_send
        !           140:  *     Purpose:
        !           141:  *             Send a message.
        !           142:  *     Conditions:
        !           143:  *             Nothing locked.
        !           144:  *     Returns:
        !           145:  *             MACH_MSG_SUCCESS        Sent the message.
        !           146:  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
        !           147:  *             MACH_SEND_NO_BUFFER     Couldn't allocate buffer.
        !           148:  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
        !           149:  *             MACH_SEND_INVALID_HEADER
        !           150:  *                     Illegal value in the message header bits.
        !           151:  *             MACH_SEND_INVALID_DEST  The space is dead.
        !           152:  *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
        !           153:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !           154:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !           155:  *             MACH_SEND_TIMED_OUT     Timeout expired without delivery.
        !           156:  *             MACH_SEND_INTERRUPTED   Delivery interrupted.
        !           157:  *             MACH_SEND_NO_NOTIFY     Can't allocate a msg-accepted request.
        !           158:  *             MACH_SEND_WILL_NOTIFY   Msg-accepted notif. requested.
        !           159:  *             MACH_SEND_NOTIFY_IN_PROGRESS
        !           160:  *                     This space has already forced a message to this port.
        !           161:  */
        !           162: 
        !           163: mach_msg_return_t
        !           164: mach_msg_send(
        !           165:        mach_msg_header_t       *msg,
        !           166:        mach_msg_option_t       option,
        !           167:        mach_msg_size_t         send_size,
        !           168:        mach_msg_timeout_t      timeout,
        !           169:        mach_port_t             notify)
        !           170: {
        !           171:        ipc_space_t space = current_space();
        !           172:        vm_map_t map = current_map();
        !           173:        ipc_kmsg_t kmsg;
        !           174:        mach_msg_return_t mr;
        !           175: 
        !           176:        mr = ipc_kmsg_get(msg, option, send_size, MAX_TRAILER_SIZE, &kmsg);
        !           177:        if (mr != MACH_MSG_SUCCESS)
        !           178:                return mr;
        !           179: 
        !           180:        if (option & MACH_SEND_CANCEL) {
        !           181:                if (notify == MACH_PORT_NULL)
        !           182:                        mr = MACH_SEND_INVALID_NOTIFY;
        !           183:                else
        !           184:                        mr = ipc_kmsg_copyin(kmsg, space, map, notify);
        !           185:        } else
        !           186:                mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
        !           187:        if (mr != MACH_MSG_SUCCESS) {
        !           188:                ikm_free(kmsg);
        !           189:                return mr;
        !           190:        }
        !           191: 
        !           192:        mr = ipc_mqueue_send(kmsg, option & MACH_SEND_TIMEOUT,
        !           193:                                                timeout, IMQ_NULL_CONTINUE);
        !           194:        if (mr != MACH_MSG_SUCCESS) {
        !           195:                mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map, IKM_NULL);
        !           196: 
        !           197:                assert(kmsg->ikm_marequest == IMAR_NULL);
        !           198:                (void) ipc_kmsg_put(msg, kmsg, kmsg->ikm_header.msgh_size);
        !           199:        }
        !           200: 
        !           201:        return mr;
        !           202: }
        !           203: 
        !           204: #define FREE_SCATTER_LIST(l)                           \
        !           205: MACRO_BEGIN                                            \
        !           206:        if((l) != IKM_NULL) {                           \
        !           207:                ikm_free((l));                          \
        !           208:        }                                               \
        !           209: MACRO_END
        !           210: 
        !           211: /*
        !           212:  *     Routine:        mach_msg_receive
        !           213:  *     Purpose:
        !           214:  *             Receive a message.
        !           215:  *     Conditions:
        !           216:  *             Nothing locked.
        !           217:  *     Returns:
        !           218:  *             MACH_MSG_SUCCESS        Received a message.
        !           219:  *             MACH_RCV_INVALID_NAME   The name doesn't denote a right,
        !           220:  *                     or the denoted right is not receive or port set.
        !           221:  *             MACH_RCV_IN_SET         Receive right is a member of a set.
        !           222:  *             MACH_RCV_TOO_LARGE      Message wouldn't fit into buffer.
        !           223:  *             MACH_RCV_TIMED_OUT      Timeout expired without a message.
        !           224:  *             MACH_RCV_INTERRUPTED    Reception interrupted.
        !           225:  *             MACH_RCV_PORT_DIED      Port/set died while receiving.
        !           226:  *             MACH_RCV_PORT_CHANGED   Port moved into set while receiving.
        !           227:  *             MACH_RCV_INVALID_DATA   Couldn't copy to user buffer.
        !           228:  *             MACH_RCV_INVALID_NOTIFY Bad notify port.
        !           229:  *             MACH_RCV_HEADER_ERROR
        !           230:  */
        !           231: 
        !           232: mach_msg_return_t
        !           233: mach_msg_receive(
        !           234:        mach_msg_header_t       *msg,
        !           235:        mach_msg_option_t       option,
        !           236:        mach_msg_size_t         rcv_size,
        !           237:        mach_port_t             rcv_name,
        !           238:        mach_msg_timeout_t      timeout,
        !           239:        mach_port_t             notify,
        !           240:        mach_msg_size_t         list_size)
        !           241: {
        !           242:        ipc_thread_t self = current_thread();
        !           243:        ipc_space_t space = current_space();
        !           244:        vm_map_t map = current_map();
        !           245:        ipc_object_t object;
        !           246:        ipc_mqueue_t mqueue;
        !           247:        ipc_kmsg_t kmsg;
        !           248:        mach_port_seqno_t seqno;
        !           249:        ipc_kmsg_t list;
        !           250:        mach_msg_return_t mr;
        !           251:        mach_msg_trailer_t *trailer;
        !           252: 
        !           253:        /*
        !           254:         * If MACH_RCV_OVERWRITE was specified, both receive_msg (msg)
        !           255:         * and receive_msg_size (list_size) need to be non NULL.
        !           256:         */
        !           257:        if (option & MACH_RCV_OVERWRITE) {
        !           258:                if (list_size < sizeof(mach_msg_base_t)) 
        !           259:                        return MACH_RCV_SCATTER_SMALL;
        !           260:                else 
        !           261:                if (ipc_kmsg_get(msg, MACH_MSG_OPTION_NONE,
        !           262:                                list_size, 0, &list) != MACH_MSG_SUCCESS)
        !           263:                        return MACH_RCV_INVALID_DATA;
        !           264: 
        !           265:                else
        !           266:                if ((((mach_msg_base_t *)
        !           267:                        &kmsg->ikm_header)->body.msgh_descriptor_count *
        !           268:                                        sizeof (mach_msg_descriptor_t)) + 
        !           269:                                        sizeof (mach_msg_base_t) > list_size) {
        !           270:                        FREE_SCATTER_LIST(list);
        !           271:                        return MACH_RCV_INVALID_TYPE;
        !           272:                }
        !           273:        }
        !           274:        else
        !           275:                list = IKM_NULL;
        !           276: 
        !           277:        mr = ipc_mqueue_copyin(space, rcv_name, &mqueue, &object);
        !           278:        if (mr != MACH_MSG_SUCCESS) {
        !           279:                FREE_SCATTER_LIST(list);
        !           280:                return mr;
        !           281:        }
        !           282:        /* hold ref for object; mqueue is locked */
        !           283: 
        !           284:        /*
        !           285:         *      ipc_mqueue_receive may not return, because if we block
        !           286:         *      then our kernel stack may be discarded.  So we save
        !           287:         *      state here for mach_msg_receive_continue to pick up.
        !           288:         */
        !           289: 
        !           290:        self->ith_msg = msg;
        !           291:        self->ith_option = option;
        !           292:        self->ith_rcv_size = rcv_size;
        !           293:        self->ith_timeout = timeout;
        !           294:        self->ith_notify = notify;
        !           295:        self->ith_object = object;
        !           296:        self->ith_mqueue = mqueue;
        !           297: 
        !           298:        mr = ipc_mqueue_receive(mqueue,
        !           299:                                option & (MACH_RCV_TRAILER_MASK|
        !           300:                                                MACH_RCV_TIMEOUT|
        !           301:                                                MACH_RCV_LARGE),
        !           302:                                rcv_size, timeout,
        !           303:                                FALSE, mach_msg_receive_continue,
        !           304:                                &kmsg, &seqno, &list);
        !           305:        /* mqueue is unlocked */
        !           306:        ipc_object_release(object);
        !           307: 
        !           308:        if (mr != MACH_MSG_SUCCESS) {
        !           309:                if (mr == MACH_RCV_HEADER_ERROR) {
        !           310:                        mach_msg_return_t       pr;
        !           311: 
        !           312:                        pr = mach_msg_receive_error(kmsg, msg,
        !           313:                                                    option, seqno, space);
        !           314:                        if (pr != MACH_MSG_SUCCESS)
        !           315:                                mr = pr;
        !           316:                }
        !           317:                else
        !           318:                if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
        !           319:                        if (option & MACH_RCV_LARGE) {
        !           320:                                if (list != IKM_NULL) {
        !           321:                                        mach_msg_return_t       pr;
        !           322: 
        !           323:                                        list_size = list->ikm_header.msgh_size;
        !           324:                                        list->ikm_header.msgh_size =
        !           325:                                                (mach_msg_size_t)kmsg;
        !           326:                                        pr = ipc_kmsg_put(
        !           327:                                                msg, list, list_size);
        !           328:                                        if (pr != MACH_MSG_SUCCESS)
        !           329:                                                mr = pr;
        !           330:                                }
        !           331:                                else                                    
        !           332:                                if (copyout((char *) &kmsg,
        !           333:                                               (char *) &msg->msgh_size,
        !           334:                                               sizeof(mach_msg_size_t)))
        !           335:                                        mr = MACH_RCV_INVALID_DATA;
        !           336: 
        !           337:                                return mr;
        !           338:                        }
        !           339:                        else {
        !           340:                                mach_msg_return_t       pr;
        !           341: 
        !           342:                                pr = mach_msg_receive_error(kmsg, msg,
        !           343:                                                        option, seqno, space);
        !           344:                                if (pr != MACH_MSG_SUCCESS)
        !           345:                                        mr = pr;
        !           346:                        }
        !           347:                }
        !           348: 
        !           349:                FREE_SCATTER_LIST(list);
        !           350:                return mr;
        !           351:        }
        !           352: 
        !           353:        /*
        !           354:         * Generate requested trailer.
        !           355:         */
        !           356:        trailer = (mach_msg_trailer_t *)
        !           357:                        ((vm_offset_t)&kmsg->ikm_header +
        !           358:                                        kmsg->ikm_header.msgh_size);
        !           359: 
        !           360:        if (option & MACH_RCV_NO_TRAILER) {
        !           361:                trailer->msgh_trailer_size = 
        !           362:                                trailer->msgh_trailer_type = 0;
        !           363:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
        !           364:        }
        !           365:        else
        !           366:        if (kmsg->ikm_delta > 0) {
        !           367:                /* MACH_SEND_TRAILER */;
        !           368:        }
        !           369:        else {
        !           370:                int     elements = GET_RCV_ELEMENTS(option);
        !           371: #define trailer0       ((mach_msg_format_0_trailer_t *)trailer)
        !           372:                
        !           373:                if (elements == MACH_RCV_TRAILER_SENDER) {
        !           374:                        trailer0->msgh_sender = kmsg->ikm_sender;
        !           375:                        trailer0->msgh_seqno = seqno;
        !           376:                }
        !           377:                else
        !           378:                if (elements == MACH_RCV_TRAILER_SEQNO)
        !           379:                        trailer0->msgh_seqno = seqno;
        !           380: 
        !           381:                trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
        !           382:                trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
        !           383: #undef trailer0
        !           384:        }
        !           385: 
        !           386:        if (option & MACH_RCV_NOTIFY) {
        !           387:                if (notify == MACH_PORT_NULL)
        !           388:                        mr = MACH_RCV_INVALID_NOTIFY;
        !           389:                else
        !           390:                        mr = ipc_kmsg_copyout(kmsg, space, map, notify, list);
        !           391:        } else
        !           392:                mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL, list);
        !           393:        if (mr != MACH_MSG_SUCCESS) {
        !           394:                mach_msg_return_t       pr;
        !           395: 
        !           396:                if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
        !           397:                        pr = ipc_kmsg_put(msg, kmsg,
        !           398:                                        kmsg->ikm_header.msgh_size +
        !           399:                                                trailer->msgh_trailer_size);
        !           400:                        if (pr != MACH_MSG_SUCCESS)
        !           401:                                mr = pr;
        !           402:                                        
        !           403:                } else {
        !           404:                        pr = mach_msg_receive_error(kmsg, msg,
        !           405:                                                option, seqno, space);
        !           406:                        if (pr != MACH_MSG_SUCCESS)
        !           407:                                mr = pr;
        !           408:                }
        !           409: 
        !           410:                FREE_SCATTER_LIST(list);
        !           411:                return mr;
        !           412:        }
        !           413: 
        !           414:        FREE_SCATTER_LIST(list);
        !           415:        return ipc_kmsg_put(msg, kmsg,
        !           416:                        kmsg->ikm_header.msgh_size +
        !           417:                                trailer->msgh_trailer_size);
        !           418: }
        !           419: 
        !           420: /*
        !           421:  *     Routine:        mach_msg_receive_continue
        !           422:  *     Purpose:
        !           423:  *             Continue after blocking for a message.
        !           424:  *     Conditions:
        !           425:  *             Nothing locked.  We are running on a new kernel stack,
        !           426:  *             with the receive state saved in the thread.  From here
        !           427:  *             control goes back to user space.
        !           428:  */
        !           429: 
        !           430: void
        !           431: mach_msg_receive_continue(void)
        !           432: {
        !           433:        ipc_thread_t self = current_thread();
        !           434:        ipc_space_t space = current_space();
        !           435:        vm_map_t map = current_map();
        !           436:        mach_msg_header_t *msg = self->ith_msg;
        !           437:        mach_msg_option_t option = self->ith_option;
        !           438:        mach_msg_trailer_t *trailer;
        !           439:        ipc_kmsg_t kmsg;
        !           440:        mach_port_seqno_t seqno;
        !           441:        ipc_kmsg_t list;
        !           442:        mach_msg_return_t mr;
        !           443: 
        !           444:        mr = ipc_mqueue_receive(self->ith_mqueue,
        !           445:                                option & (MACH_RCV_TRAILER_MASK|
        !           446:                                                MACH_RCV_TIMEOUT|
        !           447:                                                MACH_RCV_LARGE),
        !           448:                                self->ith_rcv_size, self->ith_timeout,
        !           449:                                TRUE, mach_msg_receive_continue,
        !           450:                                &kmsg, &seqno, &list);
        !           451:        /* mqueue is unlocked */
        !           452:        ipc_object_release(self->ith_object);
        !           453: 
        !           454:        if (mr != MACH_MSG_SUCCESS) {
        !           455:                if (mr == MACH_RCV_HEADER_ERROR) {
        !           456:                        mach_msg_return_t       pr;
        !           457: 
        !           458:                        pr = mach_msg_receive_error(kmsg, msg,
        !           459:                                                    option, seqno, space);
        !           460:                        if (pr != MACH_MSG_SUCCESS)
        !           461:                                mr = pr;
        !           462:                }
        !           463:                else
        !           464:                if (mr == MACH_RCV_TOO_LARGE || mr == MACH_RCV_SCATTER_SMALL) {
        !           465:                        if (option & MACH_RCV_LARGE) {
        !           466:                                if (list != IKM_NULL) {
        !           467:                                        mach_msg_return_t       pr;
        !           468:                                        mach_msg_size_t         list_size;
        !           469: 
        !           470:                                        list_size = list->ikm_header.msgh_size;
        !           471:                                        list->ikm_header.msgh_size =
        !           472:                                                (mach_msg_size_t)kmsg;
        !           473:                                        pr = ipc_kmsg_put(
        !           474:                                                msg, list, list_size);
        !           475:                                        if (pr != MACH_MSG_SUCCESS)
        !           476:                                                mr = pr;
        !           477:                                }
        !           478:                                else                                    
        !           479:                                if (copyout((char *) &kmsg,
        !           480:                                               (char *) &msg->msgh_size,
        !           481:                                               sizeof(mach_msg_size_t)))
        !           482:                                        mr = MACH_RCV_INVALID_DATA;
        !           483: 
        !           484:                                thread_syscall_return(mr);
        !           485:                                /*NOTREACHED*/
        !           486:                        }
        !           487:                        else {
        !           488:                                mach_msg_return_t       pr;
        !           489: 
        !           490:                                pr = mach_msg_receive_error(kmsg, msg,
        !           491:                                                        option, seqno, space);
        !           492:                                if (pr != MACH_MSG_SUCCESS)
        !           493:                                        mr = pr;
        !           494:                        }
        !           495:                }
        !           496: 
        !           497:                FREE_SCATTER_LIST(list);
        !           498:                thread_syscall_return(mr);
        !           499:                /*NOTREACHED*/
        !           500:        }
        !           501: 
        !           502:        /*
        !           503:         * Generate requested trailer.
        !           504:         */
        !           505:        trailer = (mach_msg_trailer_t *)
        !           506:                        ((vm_offset_t)&kmsg->ikm_header +
        !           507:                                        kmsg->ikm_header.msgh_size);
        !           508: 
        !           509:        if (option & MACH_RCV_NO_TRAILER) {
        !           510:                trailer->msgh_trailer_size = 
        !           511:                                trailer->msgh_trailer_type = 0;
        !           512:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
        !           513:        }
        !           514:        else
        !           515:        if (kmsg->ikm_delta > 0) {
        !           516:                /* MACH_SEND_TRAILER */;
        !           517:        }
        !           518:        else {
        !           519:                int     elements = GET_RCV_ELEMENTS(option);
        !           520: #define trailer0       ((mach_msg_format_0_trailer_t *)trailer)
        !           521:                
        !           522:                if (elements == MACH_RCV_TRAILER_SENDER) {
        !           523:                        trailer0->msgh_sender = kmsg->ikm_sender;
        !           524:                        trailer0->msgh_seqno = seqno;
        !           525:                }
        !           526:                else
        !           527:                if (elements == MACH_RCV_TRAILER_SEQNO)
        !           528:                        trailer0->msgh_seqno = seqno;
        !           529: 
        !           530:                trailer0->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
        !           531:                trailer0->msgh_trailer_size = REQUESTED_TRAILER_SIZE(option);
        !           532: #undef trailer0
        !           533:        }
        !           534: 
        !           535:        if (option & MACH_RCV_NOTIFY) {
        !           536:                if (self->ith_notify == MACH_PORT_NULL)
        !           537:                        mr = MACH_RCV_INVALID_NOTIFY;
        !           538:                else
        !           539:                        mr = ipc_kmsg_copyout(
        !           540:                                        kmsg, space, map,
        !           541:                                        self->ith_notify, 
        !           542:                                        self->ith_list);
        !           543:        } else
        !           544:                mr = ipc_kmsg_copyout(
        !           545:                                kmsg, space, map,
        !           546:                                MACH_PORT_NULL,
        !           547:                                self->ith_list);
        !           548:        if (mr != MACH_MSG_SUCCESS) {
        !           549:                mach_msg_return_t       pr;
        !           550: 
        !           551:                if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
        !           552:                        pr = ipc_kmsg_put(msg, kmsg,
        !           553:                                        kmsg->ikm_header.msgh_size +
        !           554:                                                trailer->msgh_trailer_size);
        !           555:                        if (pr != MACH_MSG_SUCCESS)
        !           556:                                mr = pr;
        !           557:                                        
        !           558:                } else {
        !           559:                        pr = mach_msg_receive_error(kmsg, msg,
        !           560:                                                option, seqno, space);
        !           561:                        if (pr != MACH_MSG_SUCCESS)
        !           562:                                mr = pr;
        !           563:                }
        !           564: 
        !           565:                FREE_SCATTER_LIST(list);
        !           566:                thread_syscall_return(mr);
        !           567:                /*NOTREACHED*/
        !           568:        }
        !           569: 
        !           570:        FREE_SCATTER_LIST(list);
        !           571:        mr = ipc_kmsg_put(msg, kmsg,
        !           572:                        kmsg->ikm_header.msgh_size +
        !           573:                                trailer->msgh_trailer_size);
        !           574:        thread_syscall_return(mr);
        !           575:        /*NOTREACHED*/
        !           576: }
        !           577: 
        !           578: /*
        !           579:  *     Routine:        mach_msg_receive_error  [internal]
        !           580:  *     Purpose:
        !           581:  *             Builds a minimal header/trailer and copies it to
        !           582:  *             the user message buffer.  Invoked when in the case of a
        !           583:  *             MACH_RCV_TOO_LARGE or MACH_RCV_HEADER_ERROR error.
        !           584:  *     Conditions:
        !           585:  *             Nothing locked.
        !           586:  *     Returns:
        !           587:  *             MACH_MSG_SUCCESS        minimal headere/trailer copied
        !           588:  *             MACH_RCV_INVALID_DATA   copyout to user buffer failed
        !           589:  */
        !           590:        
        !           591: mach_msg_return_t
        !           592: mach_msg_receive_error(
        !           593:        ipc_kmsg_t              kmsg,
        !           594:        mach_msg_header_t       *msg,
        !           595:        mach_msg_option_t       option,
        !           596:        mach_port_seqno_t       seqno,
        !           597:        ipc_space_t             space)
        !           598: {
        !           599:        mach_msg_trailer_t *trailer;
        !           600: 
        !           601:        /*
        !           602:         * Copy out the destination port in the message.
        !           603:         * Destroy all other rights and memory in the message.
        !           604:         */
        !           605:        ipc_kmsg_copyout_dest(kmsg, space);
        !           606: 
        !           607:        /*
        !           608:         * Build a minimal message with a null trailer.
        !           609:         */
        !           610:        kmsg->ikm_header.msgh_size = sizeof(mach_msg_header_t);
        !           611:        trailer = (mach_msg_trailer_t *)
        !           612:                                ((vm_offset_t)&kmsg->ikm_header +
        !           613:                                                kmsg->ikm_header.msgh_size);
        !           614: 
        !           615:        if (option & MACH_RCV_NO_TRAILER) {
        !           616:            trailer->msgh_trailer_size = trailer->msgh_trailer_type = 0;
        !           617:            kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_NO_TRAILER;
        !           618:        }
        !           619:        else {
        !           620:            trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
        !           621:            trailer->msgh_trailer_size = sizeof (mach_msg_trailer_t);
        !           622:        }
        !           623: 
        !           624:        /*
        !           625:         * Copy the message to user space
        !           626:         */
        !           627:        return ipc_kmsg_put(msg, kmsg,
        !           628:                        kmsg->ikm_header.msgh_size +
        !           629:                                trailer->msgh_trailer_size);
        !           630: }
        !           631: 
        !           632: /*
        !           633:  *     Routine:        mach_msg_overwrite_trap [mach trap]
        !           634:  *     Purpose:
        !           635:  *             Possibly send a message; possibly receive a message.
        !           636:  *     Conditions:
        !           637:  *             Nothing locked.
        !           638:  *     Returns:
        !           639:  *             All of mach_msg_send and mach_msg_receive error codes.
        !           640:  */
        !           641: static __inline__
        !           642: mach_msg_return_t
        !           643: _mach_msg_overwrite(
        !           644:        mach_msg_header_t       *msg,
        !           645:        mach_msg_option_t       option,
        !           646:        mach_msg_size_t         send_size,
        !           647:        mach_msg_size_t         rcv_size,
        !           648:        mach_port_t             rcv_name,
        !           649:        mach_msg_timeout_t      timeout,
        !           650:        mach_port_t             notify,
        !           651:        mach_msg_header_t       *rcv_msg,
        !           652:         mach_msg_size_t                list_size)
        !           653: {
        !           654:        mach_msg_return_t mr;
        !           655: 
        !           656:        if (option & MACH_SEND_MSG) {
        !           657:                mr = mach_msg_send(msg, option, send_size,
        !           658:                                   timeout, notify);
        !           659:                if (mr != MACH_MSG_SUCCESS)
        !           660:                        return mr;
        !           661:        }
        !           662: 
        !           663:        if (option & MACH_RCV_MSG) {
        !           664:                mach_msg_header_t *rcv;
        !           665: 
        !           666:                /*
        !           667:                 * 1. MACH_RCV_OVERWRITE is on, and rcv_msg is our scatter list
        !           668:                 *    and receive buffer
        !           669:                 * 2. MACH_RCV_OVERWRITE is off, and rcv_msg might be the
        !           670:                 *    alternate receive buffer (separate send and receive buffers).
        !           671:                 */
        !           672:                if (option & MACH_RCV_OVERWRITE) 
        !           673:                    rcv = rcv_msg;
        !           674:                else if (rcv_msg != MACH_MSG_NULL)
        !           675:                    rcv = rcv_msg;
        !           676:                else
        !           677:                    rcv = msg;
        !           678:                mr = mach_msg_receive(rcv, option, rcv_size, rcv_name, 
        !           679:                                      timeout, notify, list_size);
        !           680:                if (mr != MACH_MSG_SUCCESS)
        !           681:                        return mr;
        !           682:        }
        !           683: 
        !           684:        return MACH_MSG_SUCCESS;
        !           685: }
        !           686: 
        !           687: mach_msg_return_t
        !           688: mach_msg_overwrite_trap(
        !           689:        mach_msg_header_t       *msg,
        !           690:        mach_msg_option_t       option,
        !           691:        mach_msg_size_t         sndsiz,
        !           692:        mach_msg_size_t         rcvsiz,
        !           693:        mach_port_t             rcvnam,
        !           694:        mach_msg_timeout_t      tout,
        !           695:        mach_port_t             notify,
        !           696:        mach_msg_header_t       *rmsg,
        !           697:        mach_msg_size_t         rmsgsiz)
        !           698: {
        !           699:        return
        !           700:        (
        !           701:                _mach_msg_overwrite(
        !           702:                                msg, option,
        !           703:                                sndsiz,
        !           704:                                rcvsiz, rcvnam,
        !           705:                                tout, notify,
        !           706:                                rmsg, rmsgsiz));
        !           707: }
        !           708: 
        !           709: mach_msg_return_t
        !           710: mach_msg_trap(
        !           711:        mach_msg_header_t       *msg,
        !           712:        mach_msg_option_t       option,
        !           713:        mach_msg_size_t         sndsiz,
        !           714:        mach_msg_size_t         rcvsiz,
        !           715:        mach_port_t             rcvnam,
        !           716:        mach_msg_timeout_t      tout,
        !           717:        mach_port_t             notify)
        !           718: {
        !           719:        return
        !           720:        (
        !           721:                _mach_msg_overwrite(
        !           722:                                msg, option,
        !           723:                                sndsiz,
        !           724:                                rcvsiz, rcvnam,
        !           725:                                tout, notify,
        !           726:                                MACH_MSG_NULL,  (mach_msg_size_t) 0));
        !           727: }
        !           728: 
        !           729: mach_msg_return_t
        !           730: mach_msg_simple_trap(
        !           731:        mach_msg_header_t       *msg,
        !           732:        mach_msg_option_t       option,
        !           733:        mach_msg_size_t         sndsiz,
        !           734:        mach_msg_size_t         rcvsiz,
        !           735:        mach_port_t             rcvnam)
        !           736: {
        !           737:        return
        !           738:        (
        !           739:                _mach_msg_overwrite(
        !           740:                                msg, option,
        !           741:                                sndsiz,
        !           742:                                rcvsiz, rcvnam,
        !           743:                                MACH_MSG_TIMEOUT_NONE, MACH_PORT_NULL,
        !           744:                                MACH_MSG_NULL,  (mach_msg_size_t) 0));
        !           745: }
        !           746: 
        !           747: /*
        !           748:  *     Routine:        mach_msg_interrupt
        !           749:  *     Purpose:
        !           750:  *             Attempts to force a thread waiting at mach_msg_continue or
        !           751:  *             mach_msg_receive_continue into a clean point.  Returns TRUE
        !           752:  *             if this was possible.
        !           753:  *     Conditions:
        !           754:  *             Nothing locked.  The thread must NOT be runnable.
        !           755:  */
        !           756: 
        !           757: boolean_t
        !           758: mach_msg_interrupt(
        !           759:        thread_t thread)
        !           760: {
        !           761:        ipc_mqueue_t mqueue;
        !           762: 
        !           763:        assert((thread->swap_func == (void (*)()) mach_msg_continue) ||
        !           764:               (thread->swap_func == (void (*)()) mach_msg_receive_continue));
        !           765: 
        !           766:        mqueue = thread->ith_mqueue;
        !           767:        imq_lock(mqueue);
        !           768:        if (thread->ith_state != MACH_RCV_IN_PROGRESS) {
        !           769:                /*
        !           770:                 *      The thread is no longer waiting for a message.
        !           771:                 *      It may have a message sitting in ith_kmsg.
        !           772:                 *      We can't clean this up.
        !           773:                 */
        !           774: 
        !           775:                imq_unlock(mqueue);
        !           776:                return FALSE;
        !           777:        }
        !           778:        ipc_thread_rmqueue(&mqueue->imq_threads, thread);
        !           779:        imq_unlock(mqueue);
        !           780: 
        !           781:        ipc_object_release(thread->ith_object);
        !           782: 
        !           783:        thread_set_syscall_return(thread, MACH_RCV_INTERRUPTED);
        !           784:        thread->swap_func = thread_exception_return;
        !           785:        return TRUE;
        !           786: }
        !           787: 
        !           788: #if    MACH_IPC_COMPAT
        !           789: 
        !           790: /*
        !           791:  *     Routine:        msg_return_translate
        !           792:  *     Purpose:
        !           793:  *             Translate from new error code to old error code.
        !           794:  */
        !           795: 
        !           796: msg_return_t
        !           797: msg_return_translate(
        !           798:        mach_msg_return_t mr)
        !           799: {
        !           800:        switch (mr &~ MACH_MSG_MASK) {
        !           801:            case MACH_MSG_SUCCESS:
        !           802:                return 0;       /* SEND_SUCCESS/RCV_SUCCESS/RPC_SUCCESS */
        !           803: 
        !           804:            case MACH_SEND_NO_BUFFER:
        !           805:            case MACH_SEND_NO_NOTIFY:
        !           806:                printf("msg_return_translate: %x -> interrupted\n", mr);
        !           807:                return SEND_INTERRUPTED;
        !           808: 
        !           809:            case MACH_SEND_MSG_TOO_SMALL:
        !           810:                return SEND_MSG_TOO_SMALL;
        !           811:            case MACH_SEND_INVALID_DATA:
        !           812:            case MACH_SEND_INVALID_MEMORY:
        !           813:                return SEND_INVALID_MEMORY;
        !           814:            case MACH_SEND_TIMED_OUT:
        !           815:                return SEND_TIMED_OUT;
        !           816:            case MACH_SEND_INTERRUPTED:
        !           817:                return SEND_INTERRUPTED;
        !           818:            case MACH_SEND_INVALID_DEST:
        !           819:            case MACH_SEND_INVALID_REPLY:
        !           820:            case MACH_SEND_INVALID_RIGHT:
        !           821:            case MACH_SEND_INVALID_TYPE:
        !           822:                return SEND_INVALID_PORT;
        !           823:            case MACH_SEND_WILL_NOTIFY:
        !           824:                return SEND_WILL_NOTIFY;
        !           825:            case MACH_SEND_NOTIFY_IN_PROGRESS:
        !           826:                return SEND_NOTIFY_IN_PROGRESS;
        !           827: 
        !           828:            case MACH_RCV_INVALID_NAME:
        !           829:            case MACH_RCV_IN_SET:
        !           830:            case MACH_RCV_PORT_DIED:
        !           831:                return RCV_INVALID_PORT;
        !           832:            case MACH_RCV_TOO_LARGE:
        !           833:                return RCV_TOO_LARGE;
        !           834:            case MACH_RCV_TIMED_OUT:
        !           835:                return RCV_TIMED_OUT;
        !           836:            case MACH_RCV_INTERRUPTED:
        !           837:                return RCV_INTERRUPTED;
        !           838:            case MACH_RCV_PORT_CHANGED:
        !           839:                return RCV_PORT_CHANGE;
        !           840:            case MACH_RCV_INVALID_DATA:
        !           841:                return RCV_INVALID_MEMORY;
        !           842: 
        !           843:            case MACH_SEND_IN_PROGRESS:
        !           844:            case MACH_SEND_INVALID_NOTIFY:
        !           845:            case MACH_SEND_INVALID_HEADER:
        !           846:            case MACH_RCV_IN_PROGRESS:
        !           847:            case MACH_RCV_INVALID_NOTIFY:
        !           848:            case MACH_RCV_HEADER_ERROR:
        !           849:            case MACH_RCV_BODY_ERROR:
        !           850:            default:
        !           851:                panic("msg_return_translate");
        !           852:        }
        !           853: }
        !           854: 
        !           855: /*
        !           856:  *     Routine:        msg_send_trap [mach trap]
        !           857:  *     Purpose:
        !           858:  *             Send a message.
        !           859:  *     Conditions:
        !           860:  *             Nothing locked.
        !           861:  *     Returns:
        !           862:  */
        !           863: 
        !           864: msg_return_t
        !           865: msg_send_trap(
        !           866:        msg_header_t *msg,
        !           867:        msg_option_t option,
        !           868:        msg_size_t send_size,
        !           869:        msg_timeout_t timeout)
        !           870: {
        !           871:        ipc_space_t space = current_space();
        !           872:        vm_map_t map = current_map();
        !           873:        ipc_kmsg_t kmsg;
        !           874:        integer_t send_delta = send_size;
        !           875:        mach_msg_return_t mr;
        !           876: 
        !           877:        send_size = (send_size + 3) & ~3; /* round up */
        !           878:        send_delta -= send_size;
        !           879: 
        !           880:        if (send_size > MSG_SIZE_MAX)
        !           881:                return SEND_MSG_TOO_LARGE;
        !           882: 
        !           883:        mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE,
        !           884:                          (mach_msg_size_t) send_size, send_delta,
        !           885:                          &kmsg);
        !           886:        if (mr != MACH_MSG_SUCCESS)
        !           887:                return msg_return_translate(mr);
        !           888: 
        !           889:        mr = ipc_kmsg_copyin_compat(kmsg, space, map);
        !           890:        if (mr != MACH_MSG_SUCCESS) {
        !           891:                ikm_free(kmsg);
        !           892:                return msg_return_translate(mr);
        !           893:        }
        !           894: 
        !           895:        if (option & SEND_NOTIFY) {
        !           896:                mr = ipc_mqueue_send(kmsg, 
        !           897:                                     ((option & SEND_SWITCH) ?
        !           898:                                      MACH_SEND_SWITCH :
        !           899:                                      MACH_MSG_OPTION_NONE) |
        !           900:                                      MACH_SEND_TIMEOUT,
        !           901:                                     ((option & SEND_TIMEOUT) ?
        !           902:                                      (mach_msg_timeout_t) timeout :
        !           903:                                      MACH_MSG_TIMEOUT_NONE),
        !           904:                                     IMQ_NULL_CONTINUE);
        !           905:                if (mr == MACH_SEND_TIMED_OUT) {
        !           906:                        ipc_port_t dest = (ipc_port_t)
        !           907:                                kmsg->ikm_header.msgh_remote_port;
        !           908: 
        !           909:                        mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
        !           910:                                                  &kmsg->ikm_marequest);
        !           911:                        if (mr == MACH_MSG_SUCCESS) {
        !           912:                                ipc_mqueue_send_always(kmsg);
        !           913:                                return SEND_WILL_NOTIFY;
        !           914:                        }
        !           915:                }
        !           916:        }
        !           917:        else if (option & SEND_SWITCH)
        !           918:                mr = ipc_mqueue_send(kmsg,
        !           919:                                     ((option & SEND_TIMEOUT) ?
        !           920:                                      MACH_SEND_TIMEOUT :
        !           921:                                      MACH_MSG_OPTION_NONE) |
        !           922:                                      MACH_SEND_SWITCH,
        !           923:                                     (mach_msg_timeout_t) timeout,
        !           924:                                     msg_send_switch_continue);
        !           925:        else
        !           926:                mr = ipc_mqueue_send(kmsg,
        !           927:                                     ((option & SEND_TIMEOUT) ?
        !           928:                                      MACH_SEND_TIMEOUT :
        !           929:                                      MACH_MSG_OPTION_NONE),
        !           930:                                     (mach_msg_timeout_t) timeout,
        !           931:                                     IMQ_NULL_CONTINUE);
        !           932: 
        !           933:        if (mr != MACH_MSG_SUCCESS)
        !           934:                ipc_kmsg_destroy(kmsg);
        !           935: 
        !           936:        return msg_return_translate(mr);
        !           937: }
        !           938: 
        !           939: void
        !           940: msg_send_switch_continue(void)
        !           941: {
        !           942:        thread_syscall_return(SEND_SUCCESS);
        !           943:        /*NOTREACHED*/
        !           944: }
        !           945: 
        !           946: mach_msg_return_t
        !           947: msg_receive_error(
        !           948:        ipc_kmsg_t      kmsg,
        !           949:        msg_header_t    *msg,
        !           950:        ipc_space_t     space);
        !           951: 
        !           952: /*
        !           953:  *     Routine:        msg_receive_trap [mach trap]
        !           954:  *     Purpose:
        !           955:  *             Receive a message.
        !           956:  *     Conditions:
        !           957:  *             Nothing locked.
        !           958:  *     Returns:
        !           959:  */
        !           960: 
        !           961: msg_return_t
        !           962: msg_receive_trap(
        !           963:        msg_header_t *msg,
        !           964:        msg_option_t option,
        !           965:        msg_size_t rcv_size,
        !           966:        port_name_t rcv_name,
        !           967:        msg_timeout_t timeout)
        !           968: {
        !           969:        ipc_thread_t self;
        !           970:        ipc_space_t space = current_space();
        !           971:        vm_map_t map = current_map();
        !           972:        ipc_object_t object;
        !           973:        ipc_mqueue_t mqueue;
        !           974:        ipc_kmsg_t kmsg;
        !           975:        mach_port_seqno_t seqno;
        !           976:        mach_msg_return_t mr;
        !           977: 
        !           978:        mr = ipc_mqueue_copyin(space, (mach_port_t) rcv_name,
        !           979:                               &mqueue, &object);
        !           980:        if (mr != MACH_MSG_SUCCESS)
        !           981:                return msg_return_translate(mr);
        !           982:        /* hold ref for object; mqueue is locked */
        !           983: 
        !           984:        /*
        !           985:         *      ipc_mqueue_receive may not return, because if we block
        !           986:         *      then our kernel stack may be discarded.  So we save
        !           987:         *      state here for msg_receive_continue to pick up.
        !           988:         */
        !           989: 
        !           990:        self = current_thread();
        !           991:        self->ith_msg = (mach_msg_header_t *) msg;
        !           992:        self->ith_option = (mach_msg_option_t) option;
        !           993:        self->ith_rcv_size = (mach_msg_size_t) rcv_size;
        !           994:        self->ith_timeout = (mach_msg_timeout_t) timeout;
        !           995:        self->ith_object = object;
        !           996:        self->ith_mqueue = mqueue;
        !           997: 
        !           998:        mr = ipc_mqueue_receive(mqueue,
        !           999:                                ((option & RCV_TIMEOUT) ?
        !          1000:                                MACH_RCV_TIMEOUT :
        !          1001:                                MACH_MSG_OPTION_NONE) |
        !          1002:                                MACH_RCV_OLD_FORMAT,
        !          1003:                                (option & RCV_LARGE) ?
        !          1004:                                (mach_msg_size_t) rcv_size :
        !          1005:                                MACH_MSG_SIZE_MAX,
        !          1006:                                (mach_msg_timeout_t) timeout,
        !          1007:                                FALSE, msg_receive_continue,
        !          1008:                                &kmsg, &seqno, 0);
        !          1009:        /* mqueue is unlocked */
        !          1010:        ipc_object_release(object);
        !          1011: 
        !          1012:        if (mr != MACH_MSG_SUCCESS) {
        !          1013:                if (mr == MACH_RCV_HEADER_ERROR)
        !          1014:                        mr = msg_receive_error(kmsg, msg, space);
        !          1015:                else
        !          1016:                if (mr == MACH_RCV_TOO_LARGE) {
        !          1017:                        msg_size_t real_size =
        !          1018:                                (msg_size_t) (mach_msg_size_t) kmsg;
        !          1019: 
        !          1020:                        assert(real_size > rcv_size);
        !          1021: 
        !          1022:                        (void) copyout((vm_offset_t) &real_size,
        !          1023:                                       (vm_offset_t) &msg->msg_size,
        !          1024:                                       sizeof(msg_size_t));
        !          1025:                }
        !          1026: 
        !          1027:                return msg_return_translate(mr);
        !          1028:        }
        !          1029:        
        !          1030:        if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
        !          1031:                assert(!(option & RCV_LARGE));
        !          1032:                
        !          1033:                ipc_kmsg_destroy(kmsg);
        !          1034:                return (RCV_TOO_LARGE);
        !          1035:        }
        !          1036: 
        !          1037:        assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
        !          1038: 
        !          1039:        mr = ipc_kmsg_copyout_compat(kmsg, space, map);
        !          1040:        assert(mr == MACH_MSG_SUCCESS);
        !          1041: 
        !          1042:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
        !          1043:        mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
        !          1044:                          kmsg->ikm_header.msgh_size);
        !          1045:        return msg_return_translate(mr);
        !          1046: }
        !          1047: 
        !          1048: /*
        !          1049:  *     Routine:        msg_rpc_trap [mach trap]
        !          1050:  *     Purpose:
        !          1051:  *             Send and receive a message.
        !          1052:  *     Conditions:
        !          1053:  *             Nothing locked.
        !          1054:  *     Returns:
        !          1055:  */
        !          1056: 
        !          1057: msg_return_t
        !          1058: msg_rpc_trap(
        !          1059:        msg_header_t *msg,
        !          1060:        msg_option_t option,
        !          1061:        msg_size_t send_size,
        !          1062:        msg_size_t rcv_size,
        !          1063:        msg_timeout_t send_timeout,
        !          1064:        msg_timeout_t rcv_timeout)
        !          1065: {
        !          1066:        ipc_thread_t self;
        !          1067:        ipc_space_t space = current_space();
        !          1068:        vm_map_t map = current_map();
        !          1069:        ipc_port_t reply;
        !          1070:        ipc_pset_t pset;
        !          1071:        ipc_mqueue_t mqueue;
        !          1072:        ipc_kmsg_t kmsg;
        !          1073:        integer_t send_delta = send_size;
        !          1074:        mach_port_seqno_t seqno;
        !          1075:        mach_msg_return_t mr;
        !          1076: 
        !          1077:        /*
        !          1078:         *      Instead of using msg_send_trap and msg_receive_trap,
        !          1079:         *      we implement msg_rpc_trap directly.  The difference
        !          1080:         *      is how the reply port is handled.  Instead of using
        !          1081:         *      ipc_mqueue_copyin, we save a reference for the reply
        !          1082:         *      port carried in the sent message.  For example,
        !          1083:         *      consider a rename kernel call which changes the name
        !          1084:         *      of the call's own reply port.  This is the behaviour
        !          1085:         *      of the Mach 2.5 msg_rpc_trap.
        !          1086:         */
        !          1087: 
        !          1088:        send_size = (send_size + 3) & ~3; /* round up */
        !          1089:        send_delta -= send_size;
        !          1090: 
        !          1091:        if (send_size > MSG_SIZE_MAX)
        !          1092:                return SEND_MSG_TOO_LARGE;
        !          1093: 
        !          1094:        mr = ipc_kmsg_get((mach_msg_header_t *) msg, MACH_MSG_OPTION_NONE,
        !          1095:                          (mach_msg_size_t) send_size, send_delta,
        !          1096:                          &kmsg);
        !          1097:        if (mr != MACH_MSG_SUCCESS)
        !          1098:                return msg_return_translate(mr);
        !          1099: 
        !          1100:        mr = ipc_kmsg_copyin_compat(kmsg, space, map);
        !          1101:        if (mr != MACH_MSG_SUCCESS) {
        !          1102:                ikm_free(kmsg);
        !          1103:                return msg_return_translate(mr);
        !          1104:        }
        !          1105: 
        !          1106:        reply = (ipc_port_t) kmsg->ikm_header.msgh_local_port;
        !          1107:        if (IP_VALID(reply)) {
        !          1108:                ipc_port_t      dest = (ipc_port_t)
        !          1109:                                        kmsg->ikm_header.msgh_remote_port;
        !          1110:                
        !          1111:                ipc_port_reference(reply);
        !          1112:                assert(IP_VALID(dest));
        !          1113:                
        !          1114:                ip_lock(dest);
        !          1115:                
        !          1116:                if (dest->ip_receiver == ipc_space_kernel) {
        !          1117:                        ipc_mqueue_t    mqueue;
        !          1118: 
        !          1119:                        assert(ip_active(dest));
        !          1120:                        ip_unlock(dest);
        !          1121:                        
        !          1122:                        kmsg = ipc_kobject_server(kmsg);
        !          1123:                        if (kmsg == IKM_NULL)
        !          1124:                                goto receive_reply;
        !          1125:                        
        !          1126:                        ip_lock(reply);
        !          1127:                        
        !          1128:                        if ((!ip_active(reply)) ||
        !          1129:                            (reply->ip_receiver != space) ||
        !          1130:                            (reply->ip_pset != IPS_NULL) ||
        !          1131:                            (rcv_size < (kmsg->ikm_header.msgh_size + 
        !          1132:                                                        kmsg->ikm_delta)))
        !          1133:                        {
        !          1134:                                ip_unlock(reply);
        !          1135:                                ipc_mqueue_send_always(kmsg);
        !          1136:                                goto receive_reply;
        !          1137:                        }
        !          1138: 
        !          1139:                        mqueue = &reply->ip_messages;
        !          1140:                        imq_lock(mqueue);
        !          1141:                        
        !          1142:                        if ((ipc_thread_queue_first(&mqueue->imq_threads)
        !          1143:                                != ITH_NULL) ||
        !          1144:                            (ipc_kmsg_queue_first(&mqueue->imq_messages)
        !          1145:                                != IKM_NULL))
        !          1146:                        {
        !          1147:                                imq_unlock(mqueue);
        !          1148:                                ip_unlock(reply);
        !          1149:                                ipc_mqueue_send_always(kmsg);
        !          1150:                                goto receive_reply;
        !          1151:                        }
        !          1152: 
        !          1153:                        assert(kmsg->ikm_marequest == IMAR_NULL);
        !          1154:                        assert(ipc_thread_queue_first(&reply->ip_blocked)
        !          1155:                                == ITH_NULL);
        !          1156: 
        !          1157:                        reply->ip_seqno++;
        !          1158:                        imq_unlock(mqueue);
        !          1159: 
        !          1160:                        ip_release(reply);
        !          1161:                        ip_unlock(reply);
        !          1162:                        
        !          1163:                        goto copyout_reply;
        !          1164:                }
        !          1165:                
        !          1166:                ip_unlock(dest);
        !          1167:        }
        !          1168: 
        !          1169:        if (option & SEND_NOTIFY) {
        !          1170:                mr = ipc_mqueue_send(kmsg,
        !          1171:                                     ((option & SEND_SWITCH) ?
        !          1172:                                      MACH_SEND_SWITCH :
        !          1173:                                      MACH_MSG_OPTION_NONE) |
        !          1174:                                      MACH_SEND_TIMEOUT,
        !          1175:                                     ((option & SEND_TIMEOUT) ?
        !          1176:                                      (mach_msg_timeout_t) send_timeout :
        !          1177:                                      MACH_MSG_TIMEOUT_NONE),
        !          1178:                                     IMQ_NULL_CONTINUE);
        !          1179:                if (mr == MACH_SEND_TIMED_OUT) {
        !          1180:                        ipc_port_t dest = (ipc_port_t)
        !          1181:                                kmsg->ikm_header.msgh_remote_port;
        !          1182: 
        !          1183:                        mr = ipc_marequest_create(space, dest, MACH_PORT_NULL,
        !          1184:                                                  &kmsg->ikm_marequest);
        !          1185:                        if (mr == MACH_MSG_SUCCESS) {
        !          1186:                                ipc_mqueue_send_always(kmsg);
        !          1187:                                if (IP_VALID(reply))
        !          1188:                                        ipc_port_release(reply);
        !          1189:                                return SEND_WILL_NOTIFY;
        !          1190:                        }
        !          1191:                }
        !          1192:        }
        !          1193:        else if (option & SEND_SWITCH)
        !          1194:                mr = ipc_mqueue_send(kmsg,
        !          1195:                                     ((option & SEND_TIMEOUT) ?
        !          1196:                                      MACH_SEND_TIMEOUT :
        !          1197:                                      MACH_MSG_OPTION_NONE) |
        !          1198:                                      MACH_SEND_SWITCH,
        !          1199:                                     (mach_msg_timeout_t) send_timeout,
        !          1200:                                     IMQ_NULL_CONTINUE);
        !          1201:        else
        !          1202:                mr = ipc_mqueue_send(kmsg,
        !          1203:                                     ((option & SEND_TIMEOUT) ?
        !          1204:                                      MACH_SEND_TIMEOUT :
        !          1205:                                      MACH_MSG_OPTION_NONE),
        !          1206:                                     (mach_msg_timeout_t) send_timeout,
        !          1207:                                     IMQ_NULL_CONTINUE);
        !          1208: 
        !          1209:        if (mr != MACH_MSG_SUCCESS) {
        !          1210:                ipc_kmsg_destroy(kmsg);
        !          1211:                if (IP_VALID(reply))
        !          1212:                        ipc_port_release(reply);
        !          1213:                return msg_return_translate(mr);
        !          1214:        }
        !          1215: 
        !          1216: receive_reply:
        !          1217:        if (!IP_VALID(reply))
        !          1218:                return RCV_INVALID_PORT;
        !          1219: 
        !          1220:        ip_lock(reply);
        !          1221:        if (reply->ip_receiver != space) {
        !          1222:                ip_release(reply);
        !          1223:                ip_check_unlock(reply);
        !          1224:                return RCV_INVALID_PORT;
        !          1225:        }
        !          1226: 
        !          1227:        assert(ip_active(reply));
        !          1228:        pset = reply->ip_pset;
        !          1229: 
        !          1230:        if (pset != IPS_NULL) {
        !          1231:                ips_lock(pset);
        !          1232:                if (ips_active(pset)) {
        !          1233:                        ips_unlock(pset);
        !          1234:                        ip_release(reply);
        !          1235:                        ip_unlock(reply);
        !          1236:                        return RCV_INVALID_PORT;
        !          1237:                }
        !          1238: 
        !          1239:                ipc_pset_remove(pset, reply);
        !          1240:                ips_check_unlock(pset);
        !          1241:                assert(reply->ip_pset == IPS_NULL);
        !          1242:        }
        !          1243: 
        !          1244:        mqueue = &reply->ip_messages;
        !          1245:        imq_lock(mqueue);
        !          1246:        ip_unlock(reply);
        !          1247: 
        !          1248:        /*
        !          1249:         *      ipc_mqueue_receive may not return, because if we block
        !          1250:         *      then our kernel stack may be discarded.  So we save
        !          1251:         *      state here for msg_receive_continue to pick up.
        !          1252:         */
        !          1253: 
        !          1254:        self = current_thread();
        !          1255:        self->ith_msg = (mach_msg_header_t *) msg;
        !          1256:        self->ith_option = (mach_msg_option_t) option;
        !          1257:        self->ith_rcv_size = (mach_msg_size_t) rcv_size;
        !          1258:        self->ith_timeout = (mach_msg_timeout_t) rcv_timeout;
        !          1259:        self->ith_object = (ipc_object_t) reply;
        !          1260:        self->ith_mqueue = mqueue;
        !          1261: 
        !          1262:        mr = ipc_mqueue_receive(mqueue,
        !          1263:                                ((option & RCV_TIMEOUT) ?
        !          1264:                                MACH_RCV_TIMEOUT :
        !          1265:                                MACH_MSG_OPTION_NONE) |
        !          1266:                                MACH_RCV_OLD_FORMAT,
        !          1267:                                (option & RCV_LARGE) ?
        !          1268:                                (mach_msg_size_t) rcv_size :
        !          1269:                                MACH_MSG_SIZE_MAX,
        !          1270:                                (mach_msg_timeout_t) rcv_timeout,
        !          1271:                                FALSE, msg_receive_continue,
        !          1272:                                &kmsg, &seqno, 0);
        !          1273:        /* mqueue is unlocked */
        !          1274:        ipc_port_release(reply);
        !          1275: 
        !          1276:        if (mr != MACH_MSG_SUCCESS) {
        !          1277:                if (mr == MACH_RCV_HEADER_ERROR)
        !          1278:                        mr = msg_receive_error(kmsg, msg, space);
        !          1279:                else
        !          1280:                if (mr == MACH_RCV_TOO_LARGE) {
        !          1281:                        msg_size_t real_size =
        !          1282:                                (msg_size_t) (mach_msg_size_t) kmsg;
        !          1283: 
        !          1284:                        assert(real_size > rcv_size);
        !          1285: 
        !          1286:                        (void) copyout((vm_offset_t) &real_size,
        !          1287:                                       (vm_offset_t) &msg->msg_size,
        !          1288:                                       sizeof(msg_size_t));
        !          1289:                }
        !          1290: 
        !          1291:                return msg_return_translate(mr);
        !          1292:        }
        !          1293:        
        !          1294:        if (kmsg->ikm_header.msgh_size > (mach_msg_size_t) rcv_size) {
        !          1295:                assert(!(option & RCV_LARGE));
        !          1296:                
        !          1297:                ipc_kmsg_destroy(kmsg);
        !          1298:                return (RCV_TOO_LARGE);
        !          1299:        }
        !          1300: 
        !          1301: copyout_reply:
        !          1302:        assert(kmsg->ikm_header.msgh_size <= (mach_msg_size_t) rcv_size);
        !          1303: 
        !          1304:        mr = ipc_kmsg_copyout_compat(kmsg, space, map);
        !          1305:        assert(mr == MACH_MSG_SUCCESS);
        !          1306: 
        !          1307:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
        !          1308:        mr = ipc_kmsg_put((mach_msg_header_t *) msg,
        !          1309:                          kmsg, kmsg->ikm_header.msgh_size);
        !          1310:        return msg_return_translate(mr);
        !          1311: }
        !          1312: 
        !          1313: /*
        !          1314:  *     Routine:        msg_receive_continue
        !          1315:  *     Purpose:
        !          1316:  *             Continue after blocking for a message.
        !          1317:  *     Conditions:
        !          1318:  *             Nothing locked.  We are running on a new kernel stack,
        !          1319:  *             with the receive state saved in the thread.  From here
        !          1320:  *             control goes back to user space.
        !          1321:  */
        !          1322: 
        !          1323: void
        !          1324: msg_receive_continue(void)
        !          1325: {
        !          1326:        ipc_thread_t self = current_thread();
        !          1327:        msg_header_t *msg = (msg_header_t *) self->ith_msg;
        !          1328:        msg_option_t option = (msg_option_t) self->ith_option;
        !          1329:        ipc_kmsg_t kmsg;
        !          1330:        mach_port_seqno_t seqno;
        !          1331:        mach_msg_return_t mr;
        !          1332: 
        !          1333:        mr = ipc_mqueue_receive(self->ith_mqueue,
        !          1334:                                ((option & RCV_TIMEOUT) ?
        !          1335:                                MACH_RCV_TIMEOUT :
        !          1336:                                MACH_MSG_OPTION_NONE) |
        !          1337:                                MACH_RCV_OLD_FORMAT,
        !          1338:                                (option & RCV_LARGE) ?
        !          1339:                                self->ith_rcv_size :
        !          1340:                                MACH_MSG_SIZE_MAX,
        !          1341:                                self->ith_timeout,
        !          1342:                                TRUE, msg_receive_continue,
        !          1343:                                &kmsg, &seqno, 0);
        !          1344:        /* mqueue is unlocked */
        !          1345:        ipc_object_release(self->ith_object);
        !          1346: 
        !          1347:        if (mr != MACH_MSG_SUCCESS) {
        !          1348:                if (mr == MACH_RCV_HEADER_ERROR)
        !          1349:                        mr = msg_receive_error(kmsg, msg, current_space());
        !          1350:                else
        !          1351:                if (mr == MACH_RCV_TOO_LARGE) {
        !          1352:                        msg_size_t real_size =
        !          1353:                                (msg_size_t) (mach_msg_size_t) kmsg;
        !          1354: 
        !          1355:                        assert(real_size > rcv_size);
        !          1356: 
        !          1357:                        (void) copyout((vm_offset_t) &real_size,
        !          1358:                                       (vm_offset_t) &msg->msg_size,
        !          1359:                                       sizeof(msg_size_t));
        !          1360:                }
        !          1361: 
        !          1362:                thread_syscall_return(msg_return_translate(mr));
        !          1363:                /*NOTREACHED*/
        !          1364:        }
        !          1365:        
        !          1366:        if (kmsg->ikm_header.msgh_size > self->ith_rcv_size) {
        !          1367:                assert(!(option & RCV_LARGE));
        !          1368:                
        !          1369:                ipc_kmsg_destroy(kmsg);
        !          1370:                thread_syscall_return(RCV_TOO_LARGE);
        !          1371:                /*NOTREACHED*/
        !          1372:        }
        !          1373: 
        !          1374:        assert(kmsg->ikm_header.msgh_size <= self->ith_rcv_size);
        !          1375: 
        !          1376:        mr = ipc_kmsg_copyout_compat(kmsg, current_space(), current_map());
        !          1377:        assert(mr == MACH_MSG_SUCCESS);
        !          1378: 
        !          1379:        kmsg->ikm_header.msgh_size += kmsg->ikm_delta;
        !          1380:        mr = ipc_kmsg_put((mach_msg_header_t *) msg, kmsg,
        !          1381:                          kmsg->ikm_header.msgh_size);
        !          1382:        thread_syscall_return(msg_return_translate(mr));
        !          1383:        /*NOTREACHED*/
        !          1384: }
        !          1385: 
        !          1386: mach_msg_return_t
        !          1387: msg_receive_error(
        !          1388:        ipc_kmsg_t      kmsg,
        !          1389:        msg_header_t    *msg,
        !          1390:        ipc_space_t     space)
        !          1391: {
        !          1392:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          1393:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          1394:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          1395:        mach_msg_return_t mr;
        !          1396: 
        !          1397:        if (IO_VALID(reply))
        !          1398:                ipc_object_destroy(reply, reply_type);
        !          1399:        (ipc_object_t)kmsg->ikm_header.msgh_local_port = IO_NULL;
        !          1400: 
        !          1401:        assert(!(mbits & MACH_MSGH_BITS_OLD_FORMAT));
        !          1402:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          1403:                mach_msg_body_t *body;
        !          1404: 
        !          1405:                body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
        !          1406:                ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
        !          1407:        }
        !          1408: 
        !          1409:        kmsg->ikm_header.msgh_size = sizeof (mach_msg_header_t);
        !          1410:        kmsg->ikm_header.msgh_reserved = 0;     /* copied to msg_type */
        !          1411:        mr = ipc_kmsg_copyout_compat(kmsg, space, VM_MAP_NULL);
        !          1412:        assert(mr == MACH_MSG_SUCCESS);
        !          1413: 
        !          1414:        return ipc_kmsg_put((mach_msg_header_t *)msg, kmsg,
        !          1415:                                        kmsg->ikm_header.msgh_size);
        !          1416: }
        !          1417: 
        !          1418: #endif MACH_IPC_COMPAT

unix.superglobalmegacorp.com

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