Annotation of kernel/ipc/ipc_mqueue.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/ipc_mqueue.c
        !            75:  *     Author: Rich Draves
        !            76:  *     Date:   1989
        !            77:  *
        !            78:  *     Functions to manipulate IPC message queues.
        !            79:  */
        !            80: 
        !            81: #include <mach/port.h>
        !            82: #include <mach/message.h>
        !            83: #include <kern/assert.h>
        !            84: #include <kern/counters.h>
        !            85: #include <kern/sched_prim.h>
        !            86: #include <kern/ipc_sched.h>
        !            87: #include <kern/ipc_kobject.h>
        !            88: #include <ipc/ipc_mqueue.h>
        !            89: #include <ipc/ipc_thread.h>
        !            90: #include <ipc/ipc_kmsg.h>
        !            91: #include <ipc/ipc_port.h>
        !            92: #include <ipc/ipc_pset.h>
        !            93: #include <ipc/ipc_space.h>
        !            94: #include <ipc/ipc_marequest.h>
        !            95: 
        !            96: /*
        !            97:  *     Routine:        ipc_mqueue_init
        !            98:  *     Purpose:
        !            99:  *             Initialize a newly-allocated message queue.
        !           100:  */
        !           101: 
        !           102: void
        !           103: ipc_mqueue_init(
        !           104:        ipc_mqueue_t    mqueue)
        !           105: {
        !           106:        imq_lock_init(mqueue);
        !           107:        ipc_kmsg_queue_init(&mqueue->imq_messages);
        !           108:        ipc_thread_queue_init(&mqueue->imq_threads);
        !           109: }
        !           110: 
        !           111: /*
        !           112:  *     Routine:        ipc_mqueue_move
        !           113:  *     Purpose:
        !           114:  *             Move messages from one queue (source) to another (dest).
        !           115:  *             Only moves messages sent to the specified port.
        !           116:  *     Conditions:
        !           117:  *             Both queues must be locked.
        !           118:  *             (This is sufficient to manipulate port->ip_seqno.)
        !           119:  */
        !           120: 
        !           121: void
        !           122: ipc_mqueue_move(
        !           123:        ipc_mqueue_t    dest,
        !           124:        ipc_mqueue_t    source,
        !           125:        ipc_port_t      port)
        !           126: {
        !           127:        ipc_kmsg_queue_t oldq, newq;
        !           128:        ipc_thread_queue_t blockedq;
        !           129:        ipc_kmsg_t kmsg, next;
        !           130:        ipc_thread_t th;
        !           131: 
        !           132:        oldq = &source->imq_messages;
        !           133:        newq = &dest->imq_messages;
        !           134:        blockedq = &dest->imq_threads;
        !           135: 
        !           136:        for (kmsg = ipc_kmsg_queue_first(oldq);
        !           137:             kmsg != IKM_NULL; kmsg = next) {
        !           138:                next = ipc_kmsg_queue_next(oldq, kmsg);
        !           139: 
        !           140:                /* only move messages sent to port */
        !           141: 
        !           142:                if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port)
        !           143:                        continue;
        !           144: 
        !           145:                ipc_kmsg_rmqueue(oldq, kmsg);
        !           146: 
        !           147:                /* before adding kmsg to newq, check for a blocked receiver */
        !           148: 
        !           149:                if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_OLD_FORMAT) {
        !           150:                    while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) {
        !           151:                        assert(ipc_kmsg_queue_empty(newq));
        !           152: 
        !           153:                        /* check if the receiver can handle the message */
        !           154: 
        !           155:                        if (!(th->ith_rcv_option & MACH_RCV_OLD_FORMAT)) {
        !           156:                            th->ith_state = MACH_RCV_HEADER_ERROR;
        !           157:                            th->ith_kmsg = kmsg;
        !           158:                            th->ith_seqno = port->ip_seqno++;
        !           159:                            thread_go(th);
        !           160: 
        !           161:                            goto next_kmsg;
        !           162:                        }
        !           163:                        else
        !           164:                        if (kmsg->ikm_header.msgh_size <= th->ith_msize) {
        !           165:                            th->ith_state = MACH_MSG_SUCCESS;
        !           166:                            th->ith_kmsg = kmsg;
        !           167:                            th->ith_seqno = port->ip_seqno++;
        !           168:                            thread_go(th);
        !           169: 
        !           170:                            goto next_kmsg;
        !           171:                        }
        !           172:                        else {
        !           173:                            th->ith_state = MACH_RCV_TOO_LARGE;
        !           174:                            th->ith_msize = kmsg->ikm_header.msgh_size;
        !           175:                        }
        !           176: 
        !           177:                        thread_go(th);
        !           178:                    }
        !           179:                }
        !           180:                else {
        !           181:                    boolean_t           msg_is_complex =
        !           182:                                (kmsg->ikm_header.msgh_bits &
        !           183:                                        MACH_MSGH_BITS_COMPLEX) != 0;
        !           184: 
        !           185:                    while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) {
        !           186:                        assert(ipc_kmsg_queue_empty(newq));
        !           187: 
        !           188:                        /* 
        !           189:                         * Check if the receiver can handle the message 
        !           190:                         */
        !           191:                        if (th->ith_rcv_option & MACH_RCV_OLD_FORMAT) {
        !           192:                            if (msg_is_complex ||
        !           193:                                        kmsg->ikm_header.msgh_size >
        !           194:                                                sizeof (mach_msg_header_t) ||
        !           195:                                        th->ith_msize <
        !           196:                                                sizeof (mach_msg_header_t)) {
        !           197:                                th->ith_state = MACH_RCV_HEADER_ERROR;
        !           198:                                th->ith_kmsg = kmsg;
        !           199:                                th->ith_seqno = port->ip_seqno++;
        !           200:                                thread_go(th);
        !           201: 
        !           202:                                goto next_kmsg;
        !           203:                            }
        !           204: 
        !           205:                            /*
        !           206:                             * As a special case, allow simple
        !           207:                             * messages which consist of only a
        !           208:                             * header to be received with the old
        !           209:                             * messaging primatives.
        !           210:                             */
        !           211:                            th->ith_state = MACH_MSG_SUCCESS;
        !           212:                        }
        !           213:                        else
        !           214:                        if (kmsg->ikm_header.msgh_size > (th->ith_msize - 
        !           215:                                REQUESTED_TRAILER_SIZE(th->ith_rcv_option))) {
        !           216:                            /*
        !           217:                             * The receive buffer isn't large enough
        !           218:                             */
        !           219:                            th->ith_state = MACH_RCV_TOO_LARGE;
        !           220: 
        !           221:                            if (th->ith_rcv_option & MACH_RCV_LARGE) {
        !           222:                                th->ith_msize = kmsg->ikm_header.msgh_size;
        !           223:                                thread_go(th);
        !           224:                                continue;
        !           225:                            }
        !           226:                        }
        !           227:                        else
        !           228:                        if (msg_is_complex && th->ith_list != IKM_NULL &&
        !           229:                            (th->ith_state =
        !           230:                                        ipc_kmsg_check_scatter(
        !           231:                                                kmsg, th->ith_rcv_option,
        !           232:                                                &th->ith_list))
        !           233:                                                        != MACH_MSG_SUCCESS) {
        !           234:                            /*
        !           235:                             * Check for type/VM errors.
        !           236:                             */
        !           237:                            if (th->ith_state == MACH_RCV_INVALID_TYPE ||
        !           238:                                (th->ith_state & MACH_MSG_VM_KERNEL) != 0) {
        !           239:                                thread_go(th);
        !           240:                                continue;
        !           241:                            }
        !           242: 
        !           243:                            /*
        !           244:                             * The scatter list isn't large enough.
        !           245:                             */
        !           246:                            if (th->ith_rcv_option & MACH_RCV_LARGE) {
        !           247:                                th->ith_msize = kmsg->ikm_header.msgh_size;
        !           248:                                thread_go(th);
        !           249:                                continue;
        !           250:                            }
        !           251:                        }
        !           252:                        else
        !           253:                            th->ith_state = MACH_MSG_SUCCESS;
        !           254: 
        !           255:                        /*
        !           256:                         * Got a receiver.  Possibly with a size error.
        !           257:                         * Hand the receiver the message and process the
        !           258:                         * next one.
        !           259:                         */
        !           260:                        th->ith_kmsg = kmsg;
        !           261:                        th->ith_seqno = port->ip_seqno++;
        !           262:                        thread_go(th);
        !           263:                        goto next_kmsg;
        !           264:                    }
        !           265:                }
        !           266: 
        !           267:                /* didn't find a receiver to handle the message */
        !           268: 
        !           269:                ipc_kmsg_enqueue(newq, kmsg);
        !           270:            next_kmsg:;
        !           271:        }
        !           272: }
        !           273: 
        !           274: /*
        !           275:  *     Routine:        ipc_mqueue_changed
        !           276:  *     Purpose:
        !           277:  *             Wake up receivers waiting in a message queue.
        !           278:  *     Conditions:
        !           279:  *             The message queue is locked.
        !           280:  */
        !           281: 
        !           282: void
        !           283: ipc_mqueue_changed(
        !           284:        ipc_mqueue_t            mqueue,
        !           285:        mach_msg_return_t       mr)
        !           286: {
        !           287:        ipc_thread_t th;
        !           288: 
        !           289:        while ((th = ipc_thread_dequeue(&mqueue->imq_threads)) != ITH_NULL) {
        !           290:                th->ith_state = mr;
        !           291:                thread_go(th);
        !           292:        }
        !           293: }
        !           294: 
        !           295: /*
        !           296:  *     Routine:        ipc_mqueue_send
        !           297:  *     Purpose:
        !           298:  *             Send a message to a port.  The message holds a reference
        !           299:  *             for the destination port in the msgh_remote_port field.
        !           300:  *
        !           301:  *             If unsuccessful, the caller still has possession of
        !           302:  *             the message and must do something with it.  If successful,
        !           303:  *             the message is queued, given to a receiver, destroyed,
        !           304:  *             or handled directly by the kernel via mach_msg.
        !           305:  *     Conditions:
        !           306:  *             Nothing locked.
        !           307:  *     Returns:
        !           308:  *             MACH_MSG_SUCCESS        The message was accepted.
        !           309:  *             MACH_SEND_TIMED_OUT     Caller still has message.
        !           310:  *             MACH_SEND_INTERRUPTED   Caller still has message.
        !           311:  */
        !           312: 
        !           313: mach_msg_return_t
        !           314: ipc_mqueue_send(
        !           315:        ipc_kmsg_t              kmsg,
        !           316:        mach_msg_option_t       option,
        !           317:        mach_msg_timeout_t      timeout,
        !           318:        void                    (*continuation)(void))
        !           319: {
        !           320:        ipc_port_t port;
        !           321: 
        !           322:        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
        !           323:        assert(IP_VALID(port));
        !           324: 
        !           325:        ip_lock(port);
        !           326: 
        !           327:        if (port->ip_receiver == ipc_space_kernel) {
        !           328:                ipc_kmsg_t reply;
        !           329: 
        !           330:                /*
        !           331:                 *      We can check ip_receiver == ipc_space_kernel
        !           332:                 *      before checking that the port is active because
        !           333:                 *      ipc_port_dealloc_kernel clears ip_receiver
        !           334:                 *      before destroying a kernel port.
        !           335:                 */
        !           336: 
        !           337:                assert(ip_active(port));
        !           338:                ip_unlock(port);
        !           339: 
        !           340:                reply = ipc_kobject_server(kmsg);
        !           341:                if (reply != IKM_NULL)
        !           342:                        ipc_mqueue_send_always(reply);
        !           343: 
        !           344:                return MACH_MSG_SUCCESS;
        !           345:        }
        !           346: 
        !           347:        for (;;) {
        !           348:                ipc_thread_t self;
        !           349: 
        !           350:                /*
        !           351:                 *      Can't deliver to a dead port.
        !           352:                 *      However, we can pretend it got sent
        !           353:                 *      and was then immediately destroyed.
        !           354:                 */
        !           355: 
        !           356:                if (!ip_active(port)) {
        !           357:                        /*
        !           358:                         *      We can't let ipc_kmsg_destroy deallocate
        !           359:                         *      the port right, because we might end up
        !           360:                         *      in an infinite loop trying to deliver
        !           361:                         *      a send-once notification.
        !           362:                         */
        !           363: 
        !           364:                        ip_release(port);
        !           365:                        ip_check_unlock(port);
        !           366:                        kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
        !           367:                        ipc_kmsg_destroy(kmsg);
        !           368:                        return MACH_MSG_SUCCESS;
        !           369:                }
        !           370: 
        !           371:                /*
        !           372:                 *  Don't block if:
        !           373:                 *      1) We're under the queue limit.
        !           374:                 *      2) Caller used the MACH_SEND_ALWAYS internal option.
        !           375:                 *      3) Message is sent to a send-once right.
        !           376:                 */
        !           377: 
        !           378:                if ((port->ip_msgcount < port->ip_qlimit) ||
        !           379:                    (option & MACH_SEND_ALWAYS) ||
        !           380:                    (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
        !           381:                                                MACH_MSG_TYPE_PORT_SEND_ONCE))
        !           382:                        break;
        !           383: 
        !           384:                /* must block waiting for queue to clear */
        !           385: 
        !           386:                self = current_thread();
        !           387: 
        !           388:                if (option & MACH_SEND_TIMEOUT) {
        !           389:                        if (timeout == 0) {
        !           390:                                ip_unlock(port);
        !           391:                                return MACH_SEND_TIMED_OUT;
        !           392:                        }
        !           393: 
        !           394:                        thread_will_wait_with_timeout(self, timeout);
        !           395:                } else
        !           396:                        thread_will_wait(self);
        !           397: 
        !           398:                ipc_thread_enqueue(&port->ip_blocked, self);
        !           399:                self->ith_state = MACH_SEND_IN_PROGRESS;
        !           400: 
        !           401:                ip_unlock(port);
        !           402:                counter(c_ipc_mqueue_send_block++);
        !           403:                thread_block_with_continuation((void (*)(void)) 0);
        !           404:                ip_lock(port);
        !           405: 
        !           406:                /* why did we wake up? */
        !           407: 
        !           408:                if (self->ith_state == MACH_MSG_SUCCESS)
        !           409:                        continue;
        !           410:                assert(self->ith_state == MACH_SEND_IN_PROGRESS);
        !           411: 
        !           412:                /* take ourselves off blocked queue */
        !           413: 
        !           414:                ipc_thread_rmqueue(&port->ip_blocked, self);
        !           415: 
        !           416:                /*
        !           417:                 *      Thread wakeup-reason field tells us why
        !           418:                 *      the wait was interrupted.
        !           419:                 */
        !           420: 
        !           421:                switch (self->ith_wait_result) {
        !           422:                    case THREAD_INTERRUPTED:
        !           423:                    case THREAD_SHOULD_TERMINATE:
        !           424:                        /* send was interrupted - give up */
        !           425: 
        !           426:                        ip_unlock(port);
        !           427:                        return MACH_SEND_INTERRUPTED;
        !           428: 
        !           429:                    case THREAD_TIMED_OUT:
        !           430:                        /* timeout expired */
        !           431: 
        !           432:                        assert(option & MACH_SEND_TIMEOUT);
        !           433:                        timeout = 0;
        !           434:                        break;
        !           435: 
        !           436:                    case THREAD_RESTART:
        !           437:                    default:
        !           438:                        panic("ipc_mqueue_send");
        !           439:                }
        !           440:        }
        !           441: 
        !           442:        if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
        !           443:                ip_unlock(port);
        !           444: 
        !           445:                /* don't allow the creation of a circular loop */
        !           446: 
        !           447:                ipc_kmsg_destroy(kmsg);
        !           448:                return MACH_MSG_SUCCESS;
        !           449:        }
        !           450: 
        !           451:     {
        !           452:        ipc_mqueue_t mqueue;
        !           453:        ipc_pset_t pset;
        !           454:        ipc_thread_t receiver;
        !           455:        ipc_thread_queue_t receivers;
        !           456: 
        !           457:        port->ip_msgcount++;
        !           458:        assert(port->ip_msgcount > 0);
        !           459: 
        !           460:        pset = port->ip_pset;
        !           461:        if (pset == IPS_NULL)
        !           462:                mqueue = &port->ip_messages;
        !           463:        else
        !           464:                mqueue = &pset->ips_messages;
        !           465: 
        !           466:        imq_lock(mqueue);
        !           467:        receivers = &mqueue->imq_threads;
        !           468: 
        !           469:        /*
        !           470:         *      Can unlock the port now that the msg queue is locked
        !           471:         *      and we know the port is active.  While the msg queue
        !           472:         *      is locked, we have control of the kmsg, so the ref in
        !           473:         *      it for the port is still good.  If the msg queue is in
        !           474:         *      a set (dead or alive), then we're OK because the port
        !           475:         *      is still a member of the set and the set won't go away
        !           476:         *      until the port is taken out, which tries to lock the
        !           477:         *      set's msg queue to remove the port's msgs.
        !           478:         */
        !           479: 
        !           480:        ip_unlock(port);
        !           481: 
        !           482:        /* check for a receiver for the message */
        !           483: 
        !           484:        if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_OLD_FORMAT) {
        !           485:            for (;;) {
        !           486:                receiver = ipc_thread_queue_first(receivers);
        !           487:                if (receiver == ITH_NULL) {
        !           488:                    /* no receivers; queue kmsg */
        !           489: 
        !           490:                    ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
        !           491:                    imq_unlock(mqueue);
        !           492:                    break;
        !           493:                }
        !           494: 
        !           495:                ipc_thread_rmqueue_first_macro(receivers, receiver);
        !           496:                assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
        !           497: 
        !           498:                if (!(receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT)) {
        !           499:                    receiver->ith_state = MACH_RCV_HEADER_ERROR;
        !           500:                    receiver->ith_kmsg = kmsg;
        !           501:                    receiver->ith_seqno = port->ip_seqno++;
        !           502:                    imq_unlock(mqueue);
        !           503: 
        !           504:                    thread_go(receiver);
        !           505:                    break;
        !           506:                }
        !           507:                else
        !           508:                if (kmsg->ikm_header.msgh_size <= receiver->ith_msize) {
        !           509:                    /* got a successful receiver */
        !           510: 
        !           511:                    receiver->ith_state = MACH_MSG_SUCCESS;
        !           512:                    receiver->ith_kmsg = kmsg;
        !           513:                    receiver->ith_seqno = port->ip_seqno++;
        !           514:                    imq_unlock(mqueue);
        !           515: 
        !           516:                    if (option & MACH_SEND_SWITCH)
        !           517:                            thread_go_and_switch(continuation, receiver);
        !           518:                    else
        !           519:                            thread_go(receiver);
        !           520:                    break;
        !           521:                }
        !           522:                else {
        !           523:                    receiver->ith_state = MACH_RCV_TOO_LARGE;
        !           524:                    receiver->ith_msize = kmsg->ikm_header.msgh_size;
        !           525:                }
        !           526: 
        !           527:                thread_go(receiver);
        !           528:            }
        !           529:        }
        !           530:        else {
        !           531:            boolean_t           msg_is_complex =
        !           532:                        (kmsg->ikm_header.msgh_bits &
        !           533:                                MACH_MSGH_BITS_COMPLEX) != 0;
        !           534: 
        !           535:            for (;;) {
        !           536:                receiver = ipc_thread_queue_first(receivers);
        !           537:                if (receiver == ITH_NULL) {
        !           538:                        /* no receivers; queue kmsg */
        !           539: 
        !           540:                        ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
        !           541:                        imq_unlock(mqueue);
        !           542:                        break;
        !           543:                }
        !           544: 
        !           545:                ipc_thread_rmqueue_first_macro(receivers, receiver);
        !           546:                assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
        !           547: 
        !           548:                /*
        !           549:                 * Got a potential receiver, verify sizes
        !           550:                 */
        !           551:                if (receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT) {
        !           552:                    if (msg_is_complex ||
        !           553:                                kmsg->ikm_header.msgh_size >
        !           554:                                                sizeof (mach_msg_header_t) ||
        !           555:                                receiver->ith_msize <
        !           556:                                                sizeof (mach_msg_header_t)) {
        !           557:                        receiver->ith_state = MACH_RCV_HEADER_ERROR;
        !           558:                        receiver->ith_kmsg = kmsg;
        !           559:                        receiver->ith_seqno = port->ip_seqno++;
        !           560:                        imq_unlock(mqueue);
        !           561:                        thread_go(receiver);
        !           562:                        break;
        !           563:                    }
        !           564: 
        !           565:                    receiver->ith_state = MACH_MSG_SUCCESS;
        !           566:                }
        !           567:                else
        !           568:                if (kmsg->ikm_header.msgh_size > (receiver->ith_msize -
        !           569:                        REQUESTED_TRAILER_SIZE(receiver->ith_rcv_option))) {
        !           570:                    /*
        !           571:                     * The receive buffer isn't large enough
        !           572:                     */
        !           573:                    receiver->ith_state = MACH_RCV_TOO_LARGE;
        !           574: 
        !           575:                    if (receiver->ith_rcv_option & MACH_RCV_LARGE) {
        !           576:                        receiver->ith_msize = kmsg->ikm_header.msgh_size;
        !           577:                        thread_go(receiver);
        !           578:                        continue;
        !           579:                    }
        !           580:                }
        !           581:                else
        !           582:                if (msg_is_complex && receiver->ith_list != IKM_NULL &&
        !           583:                    (receiver->ith_state =
        !           584:                                    ipc_kmsg_check_scatter(
        !           585:                                        kmsg, receiver->ith_rcv_option,
        !           586:                                        &receiver->ith_list))
        !           587:                                                        != MACH_MSG_SUCCESS) {
        !           588:                    /*
        !           589:                     * Check for type/VM errors.
        !           590:                     */
        !           591:                    if (receiver->ith_state == MACH_RCV_INVALID_TYPE ||
        !           592:                        (receiver->ith_state & MACH_MSG_VM_KERNEL) != 0) {
        !           593:                        thread_go(receiver);
        !           594:                        continue;
        !           595:                    }
        !           596: 
        !           597:                    /*
        !           598:                     * The scatter list isn't large enough.
        !           599:                     */
        !           600:                    if (receiver->ith_rcv_option & MACH_RCV_LARGE) {
        !           601:                        receiver->ith_msize = kmsg->ikm_header.msgh_size;
        !           602:                        thread_go(receiver);
        !           603:                        continue;
        !           604:                    }
        !           605:                }
        !           606:                else
        !           607:                    receiver->ith_state = MACH_MSG_SUCCESS;
        !           608: 
        !           609:                /*
        !           610:                 * Got a valid receiver.  Possibly with an error.
        !           611:                 * Hand the receiver the message.
        !           612:                 */
        !           613:                receiver->ith_kmsg = kmsg;
        !           614:                receiver->ith_seqno = port->ip_seqno++;
        !           615:                imq_unlock(mqueue);
        !           616:                thread_go(receiver);
        !           617:                break;
        !           618:            }
        !           619:        }
        !           620:     }
        !           621: 
        !           622:        return MACH_MSG_SUCCESS;
        !           623: }
        !           624: 
        !           625: mach_msg_return_t
        !           626: ipc_mqueue_send_interrupt(kmsg)
        !           627:        ipc_kmsg_t kmsg;
        !           628: {
        !           629:        ipc_port_t port;
        !           630: 
        !           631:        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
        !           632:        
        !           633:        if (!ip_lock_try(port))
        !           634:                return MACH_MSG_IPC_KERNEL;
        !           635:                
        !           636:        if (!ip_active(port)) {
        !           637:                ip_unlock(port);
        !           638:                return MACH_SEND_INVALID_DEST;
        !           639:        }
        !           640: 
        !           641:        assert(!(kmsg->ikm_header.msgh_bits &
        !           642:                        (MACH_MSGH_BITS_COMPLEX|MACH_MSGH_BITS_OLD_FORMAT)));
        !           643: 
        !           644:     {
        !           645:        ipc_mqueue_t mqueue;
        !           646:        ipc_pset_t pset;
        !           647:        ipc_thread_t receiver;
        !           648:        ipc_thread_queue_t receivers;
        !           649: 
        !           650:        pset = port->ip_pset;
        !           651:        if (pset == IPS_NULL)
        !           652:                mqueue = &port->ip_messages;
        !           653:        else
        !           654:                mqueue = &pset->ips_messages;
        !           655:                
        !           656:        if (!imq_lock_try(mqueue)) {
        !           657:                ip_unlock(port);
        !           658:                return MACH_MSG_IPC_KERNEL;
        !           659:        }
        !           660:        receivers = &mqueue->imq_threads;
        !           661: 
        !           662:        port->ip_msgcount++;
        !           663: 
        !           664:        /*
        !           665:         *      Can unlock the port now that the msg queue is locked
        !           666:         *      and we know the port is active.  While the msg queue
        !           667:         *      is locked, we have control of the kmsg, so the ref in
        !           668:         *      it for the port is still good.  If the msg queue is in
        !           669:         *      a set (dead or alive), then we're OK because the port
        !           670:         *      is still a member of the set and the set won't go away
        !           671:         *      until the port is taken out, which tries to lock the
        !           672:         *      set's msg queue to remove the port's msgs.
        !           673:         */
        !           674: 
        !           675:        ip_unlock(port);
        !           676: 
        !           677:        /* check for a receiver for the message */
        !           678: 
        !           679:        for (;;) {
        !           680:                receiver = ipc_thread_queue_first(receivers);
        !           681:                if (receiver == ITH_NULL) {
        !           682:                        /* no receivers; queue kmsg */
        !           683: 
        !           684:                        ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
        !           685:                        imq_unlock(mqueue);
        !           686:                        break;
        !           687:                }
        !           688: 
        !           689:                ipc_thread_rmqueue_first_macro(receivers, receiver);
        !           690:                assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
        !           691: 
        !           692:                /*
        !           693:                 * Got a potential receiver, verify sizes
        !           694:                 */
        !           695:                if (receiver->ith_rcv_option & MACH_RCV_OLD_FORMAT) {
        !           696:                    if (        kmsg->ikm_header.msgh_size >
        !           697:                                                sizeof (mach_msg_header_t) ||
        !           698:                                receiver->ith_msize <
        !           699:                                                sizeof (mach_msg_header_t)) {
        !           700:                        receiver->ith_state = MACH_RCV_HEADER_ERROR;
        !           701:                        receiver->ith_kmsg = kmsg;
        !           702:                        receiver->ith_seqno = port->ip_seqno++;
        !           703:                        imq_unlock(mqueue);
        !           704:                        thread_go(receiver);
        !           705:                        break;
        !           706:                    }
        !           707: 
        !           708:                    receiver->ith_state = MACH_MSG_SUCCESS;
        !           709:                }
        !           710:                else
        !           711:                if (kmsg->ikm_header.msgh_size > (receiver->ith_msize -
        !           712:                        REQUESTED_TRAILER_SIZE(receiver->ith_rcv_option))) {
        !           713:                    /*
        !           714:                     * The receive buffer isn't large enough
        !           715:                     */
        !           716:                    receiver->ith_state = MACH_RCV_TOO_LARGE;
        !           717: 
        !           718:                    if (receiver->ith_rcv_option & MACH_RCV_LARGE) {
        !           719:                        receiver->ith_msize = kmsg->ikm_header.msgh_size;
        !           720:                        thread_go(receiver);
        !           721:                        continue;
        !           722:                    }
        !           723:                }
        !           724:                else
        !           725:                    receiver->ith_state = MACH_MSG_SUCCESS;
        !           726: 
        !           727:                /*
        !           728:                 * Got a valid receiver.  Possibly with an error.
        !           729:                 * Hand the receiver the message.
        !           730:                 */
        !           731:                receiver->ith_kmsg = kmsg;
        !           732:                receiver->ith_seqno = port->ip_seqno++;
        !           733:                imq_unlock(mqueue);
        !           734:                thread_go(receiver);
        !           735:                break;
        !           736:        }
        !           737:     }
        !           738: 
        !           739:        return MACH_MSG_SUCCESS;
        !           740: }
        !           741: 
        !           742: /*
        !           743:  *     Routine:        ipc_mqueue_copyin
        !           744:  *     Purpose:
        !           745:  *             Convert a name in a space to a message queue.
        !           746:  *     Conditions:
        !           747:  *             Nothing locked.  If successful, the message queue
        !           748:  *             is returned locked and caller gets a ref for the object.
        !           749:  *             This ref ensures the continued existence of the queue.
        !           750:  *     Returns:
        !           751:  *             MACH_MSG_SUCCESS        Found a message queue.
        !           752:  *             MACH_RCV_INVALID_NAME   The space is dead.
        !           753:  *             MACH_RCV_INVALID_NAME   The name doesn't denote a right.
        !           754:  *             MACH_RCV_INVALID_NAME
        !           755:  *                     The denoted right is not receive or port set.
        !           756:  *             MACH_RCV_IN_SET         Receive right is a member of a set.
        !           757:  */
        !           758: 
        !           759: mach_msg_return_t
        !           760: ipc_mqueue_copyin(
        !           761:        ipc_space_t     space,
        !           762:        mach_port_t     name,
        !           763:        ipc_mqueue_t    *mqueuep,
        !           764:        ipc_object_t    *objectp)
        !           765: {
        !           766:        ipc_entry_t entry;
        !           767:        ipc_entry_bits_t bits;
        !           768:        ipc_object_t object;
        !           769:        ipc_mqueue_t mqueue;
        !           770: 
        !           771:        is_read_lock(space);
        !           772:        if (!space->is_active) {
        !           773:                is_read_unlock(space);
        !           774:                return MACH_RCV_INVALID_NAME;
        !           775:        }
        !           776: 
        !           777:        entry = ipc_entry_lookup(space, name);
        !           778:        if (entry == IE_NULL) {
        !           779:                is_read_unlock(space);
        !           780:                return MACH_RCV_INVALID_NAME;
        !           781:        }
        !           782: 
        !           783:        bits = entry->ie_bits;
        !           784:        object = entry->ie_object;
        !           785: 
        !           786:        if (bits & MACH_PORT_TYPE_RECEIVE) {
        !           787:                ipc_port_t port;
        !           788:                ipc_pset_t pset;
        !           789: 
        !           790:                port = (ipc_port_t) object;
        !           791:                assert(port != IP_NULL);
        !           792: 
        !           793:                ip_lock(port);
        !           794:                assert(ip_active(port));
        !           795:                assert(port->ip_receiver_name == name);
        !           796:                assert(port->ip_receiver == space);
        !           797:                is_read_unlock(space);
        !           798: 
        !           799:                pset = port->ip_pset;
        !           800:                if (pset != IPS_NULL) {
        !           801:                        ips_lock(pset);
        !           802:                        if (ips_active(pset)) {
        !           803:                                ips_unlock(pset);
        !           804:                                ip_unlock(port);
        !           805:                                return MACH_RCV_IN_SET;
        !           806:                        }
        !           807: 
        !           808:                        ipc_pset_remove(pset, port);
        !           809:                        ips_check_unlock(pset);
        !           810:                        assert(port->ip_pset == IPS_NULL);
        !           811:                }
        !           812: 
        !           813:                mqueue = &port->ip_messages;
        !           814:        } else if (bits & MACH_PORT_TYPE_PORT_SET) {
        !           815:                ipc_pset_t pset;
        !           816: 
        !           817:                pset = (ipc_pset_t) object;
        !           818:                assert(pset != IPS_NULL);
        !           819: 
        !           820:                ips_lock(pset);
        !           821:                assert(ips_active(pset));
        !           822:                assert(pset->ips_local_name == name);
        !           823:                is_read_unlock(space);
        !           824: 
        !           825:                mqueue = &pset->ips_messages;
        !           826:        } else {
        !           827:                is_read_unlock(space);
        !           828:                return MACH_RCV_INVALID_NAME;
        !           829:        }
        !           830: 
        !           831:        /*
        !           832:         *      At this point, the object is locked and active,
        !           833:         *      the space is unlocked, and mqueue is initialized.
        !           834:         */
        !           835: 
        !           836:        io_reference(object);
        !           837:        imq_lock(mqueue);
        !           838:        io_unlock(object);
        !           839: 
        !           840:        *objectp = object;
        !           841:        *mqueuep = mqueue;
        !           842:        return MACH_MSG_SUCCESS;
        !           843: }
        !           844: 
        !           845: /*
        !           846:  *     Routine:        ipc_mqueue_receive
        !           847:  *     Purpose:
        !           848:  *             Receive a message from a message queue.
        !           849:  *
        !           850:  *             If continuation is non-zero, then we might discard
        !           851:  *             our kernel stack when we block.  We will continue
        !           852:  *             after unblocking by executing continuation.
        !           853:  *
        !           854:  *             If resume is true, then we are resuming a receive
        !           855:  *             operation after a blocked receive discarded our stack.
        !           856:  *     Conditions:
        !           857:  *             The message queue is locked; it is unlocked.
        !           858:  *
        !           859:  *             Our caller must hold a reference for the port or port set
        !           860:  *             to which this queue belongs, to keep the queue
        !           861:  *             from being deallocated.  Furthermore, the port or set
        !           862:  *             must have been active when the queue was locked.
        !           863:  *
        !           864:  *             The kmsg is returned with clean header fields
        !           865:  *             and with the circular bit turned off.
        !           866:  *     Returns:
        !           867:  *             MACH_MSG_SUCCESS        Message returned in kmsgp.
        !           868:  *             MACH_RCV_TOO_LARGE      Message size returned in kmsgp.
        !           869:  *             MACH_RCV_TIMED_OUT      No message obtained.
        !           870:  *             MACH_RCV_INTERRUPTED    No message obtained.
        !           871:  *             MACH_RCV_PORT_DIED      Port/set died; no message.
        !           872:  *             MACH_RCV_PORT_CHANGED   Port moved into set; no msg.
        !           873:  */
        !           874: 
        !           875: mach_msg_return_t
        !           876: ipc_mqueue_receive(
        !           877:        ipc_mqueue_t            mqueue,
        !           878:        mach_msg_option_t       option,
        !           879:        mach_msg_size_t         max_size,
        !           880:        mach_msg_timeout_t      timeout,
        !           881:        boolean_t               resume,
        !           882:        void                    (*continuation)(void),
        !           883:        ipc_kmsg_t              *kmsgp,
        !           884:        mach_port_seqno_t       *seqnop,
        !           885:        ipc_kmsg_t              *list)
        !           886: {
        !           887:        ipc_port_t port;
        !           888:        ipc_kmsg_t kmsg;
        !           889:        mach_port_seqno_t seqno;
        !           890:        mach_msg_return_t mr;
        !           891: 
        !           892:     {
        !           893:        ipc_kmsg_queue_t kmsgs = &mqueue->imq_messages;
        !           894:        ipc_thread_t self = current_thread();
        !           895: 
        !           896:        if (resume)
        !           897:                goto after_thread_block;
        !           898: 
        !           899:        for (;;) {
        !           900:                kmsg = ipc_kmsg_queue_first(kmsgs);
        !           901:                if (kmsg != IKM_NULL) {
        !           902:                    if (kmsg->ikm_header.msgh_bits &
        !           903:                                        MACH_MSGH_BITS_OLD_FORMAT) {
        !           904:                        /*
        !           905:                         * Old format message. (typed data)  Verify
        !           906:                         * that one of the old messaging primatives
        !           907:                         * is being used for the receive operation.
        !           908:                         */
        !           909:                        if (!(option & MACH_RCV_OLD_FORMAT)) {
        !           910:                                self->ith_state = MACH_RCV_HEADER_ERROR;
        !           911:                                ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
        !           912:                                port = (ipc_port_t)
        !           913:                                    kmsg->ikm_header.msgh_remote_port;
        !           914:                                seqno = port->ip_seqno++;
        !           915:                                break;
        !           916:                        }
        !           917: 
        !           918:                        /* check space requirements */
        !           919: 
        !           920:                        if (kmsg->ikm_header.msgh_size > max_size) {
        !           921:                                * (mach_msg_size_t *) kmsgp =
        !           922:                                        kmsg->ikm_header.msgh_size;
        !           923:                                imq_unlock(mqueue);
        !           924:                                return MACH_RCV_TOO_LARGE;
        !           925:                        }
        !           926: 
        !           927:                        self->ith_state = MACH_MSG_SUCCESS;
        !           928:                    }
        !           929:                    else {
        !           930:                        /*
        !           931:                         * New format message. (untyped data)  Verify
        !           932:                         * that one of the new messaging primatives
        !           933:                         * is being used for the receive operation.
        !           934:                         */
        !           935:                        if (option & MACH_RCV_OLD_FORMAT) {
        !           936:                            if ((kmsg->ikm_header.msgh_bits &
        !           937:                                                MACH_MSGH_BITS_COMPLEX) ||
        !           938:                                        kmsg->ikm_header.msgh_size >
        !           939:                                                sizeof (mach_msg_header_t) ||
        !           940:                                        max_size <
        !           941:                                                sizeof (mach_msg_header_t)) {
        !           942:                                self->ith_state = MACH_RCV_HEADER_ERROR;
        !           943:                                ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
        !           944:                                port = (ipc_port_t)
        !           945:                                    kmsg->ikm_header.msgh_remote_port;
        !           946:                                seqno = port->ip_seqno++;
        !           947:                                break;
        !           948:                            }
        !           949: 
        !           950:                            self->ith_state = MACH_MSG_SUCCESS;
        !           951:                        }
        !           952:                        else
        !           953:                        /*
        !           954:                         * Verify sizes.
        !           955:                         */
        !           956:                        if (kmsg->ikm_header.msgh_size > (max_size -
        !           957:                                        REQUESTED_TRAILER_SIZE(option))) {
        !           958:                            /* 
        !           959:                             * The receive buffer isn't large enough.
        !           960:                             */
        !           961:                            if (option & MACH_RCV_LARGE) {
        !           962:                                *(mach_msg_size_t *)kmsgp =
        !           963:                                        kmsg->ikm_header.msgh_size;
        !           964:                                imq_unlock(mqueue);
        !           965:                                return MACH_RCV_TOO_LARGE;
        !           966:                            }
        !           967: 
        !           968:                            self->ith_state = MACH_RCV_TOO_LARGE;
        !           969:                        }
        !           970:                        else
        !           971:                        if ((kmsg->ikm_header.msgh_bits &
        !           972:                                        MACH_MSGH_BITS_COMPLEX) &&
        !           973:                            list && (*list) != IKM_NULL &&
        !           974:                            (self->ith_state =
        !           975:                                        ipc_kmsg_check_scatter(
        !           976:                                                kmsg, option, list))
        !           977:                                                        != MACH_MSG_SUCCESS) {
        !           978:                            /*
        !           979:                             * Check for type/VM errors.
        !           980:                             */
        !           981:                            if (self->ith_state == MACH_RCV_INVALID_TYPE ||
        !           982:                                (self->ith_state & MACH_MSG_VM_KERNEL) != 0) {
        !           983:                                imq_unlock(mqueue);
        !           984:                                return self->ith_state;
        !           985:                            }
        !           986: 
        !           987:                            /*
        !           988:                             * The scatter list isn't large enough.
        !           989:                             */
        !           990:                            if (option & MACH_RCV_LARGE) {
        !           991:                                *(mach_msg_size_t *)kmsgp =
        !           992:                                        kmsg->ikm_header.msgh_size;
        !           993:                                imq_unlock(mqueue);
        !           994:                                return self->ith_state;
        !           995:                            }
        !           996:                        }
        !           997:                        else
        !           998:                            self->ith_state = MACH_MSG_SUCCESS;
        !           999:                    }
        !          1000: 
        !          1001:                    ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
        !          1002:                    port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
        !          1003:                    seqno = port->ip_seqno++;
        !          1004:                    break;
        !          1005:                }
        !          1006: 
        !          1007:                /* must block waiting for a message */
        !          1008: 
        !          1009:                if (option & MACH_RCV_TIMEOUT) {
        !          1010:                        if (timeout == 0) {
        !          1011:                                imq_unlock(mqueue);
        !          1012:                                return MACH_RCV_TIMED_OUT;
        !          1013:                        }
        !          1014: 
        !          1015:                        thread_will_wait_with_timeout(self, timeout);
        !          1016:                } else
        !          1017:                        thread_will_wait(self);
        !          1018: 
        !          1019:                ipc_thread_enqueue_macro(&mqueue->imq_threads, self);
        !          1020:                self->ith_state = MACH_RCV_IN_PROGRESS;
        !          1021:                self->ith_msize = max_size;
        !          1022:                self->ith_rcv_option = option;
        !          1023:                self->ith_list = list ? *list : IKM_NULL;
        !          1024: 
        !          1025:                imq_unlock(mqueue);
        !          1026:                if (continuation != (void (*)(void)) 0) {
        !          1027:                        counter(c_ipc_mqueue_receive_block_user++);
        !          1028:                        thread_block_with_continuation(continuation);
        !          1029:                } else {
        !          1030:                        counter(c_ipc_mqueue_receive_block_kernel++);
        !          1031:                        thread_block_with_continuation((void (*)(void)) 0);
        !          1032:                }
        !          1033:        after_thread_block:
        !          1034:                imq_lock(mqueue);
        !          1035:                if (list)
        !          1036:                        (*list) = self->ith_list;
        !          1037: 
        !          1038:                /* why did we wake up? */
        !          1039: 
        !          1040:                if (self->ith_state == MACH_MSG_SUCCESS) {
        !          1041: return_kmsg:
        !          1042:                        /* pick up the message that was handed to us */
        !          1043: 
        !          1044:                        kmsg = self->ith_kmsg;
        !          1045:                        seqno = self->ith_seqno;
        !          1046:                        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
        !          1047:                        break;
        !          1048:                }
        !          1049: 
        !          1050:                switch (self->ith_state) {
        !          1051:                    case MACH_RCV_INVALID_TYPE:
        !          1052:                        /* bad invalid scatter list */
        !          1053: 
        !          1054:                        imq_unlock(mqueue);
        !          1055:                        return self->ith_state;
        !          1056: 
        !          1057:                    case MACH_RCV_TOO_LARGE:
        !          1058:                    case MACH_RCV_SCATTER_SMALL:
        !          1059:                        /* 
        !          1060:                         * The receive buffer isn't large enough or
        !          1061:                         * there is a scatter list and it doesn't match
        !          1062:                         * the gather list.
        !          1063:                         */
        !          1064:                        if (!(self->ith_rcv_option &
        !          1065:                                (MACH_RCV_LARGE|MACH_RCV_OLD_FORMAT)))
        !          1066:                            goto return_kmsg;
        !          1067: 
        !          1068:                        *(mach_msg_size_t *) kmsgp = self->ith_msize;
        !          1069: 
        !          1070:                        /* fall-through */
        !          1071: 
        !          1072:                    case MACH_RCV_PORT_DIED:
        !          1073:                    case MACH_RCV_PORT_CHANGED:
        !          1074:                        /* something bad happened to the port/set */
        !          1075: 
        !          1076:                        imq_unlock(mqueue);
        !          1077:                        return self->ith_state;
        !          1078: 
        !          1079:                    case MACH_RCV_IN_PROGRESS:
        !          1080:                        /*
        !          1081:                         *      Awakened for other than IPC completion.
        !          1082:                         *      Remove ourselves from the waiting queue,
        !          1083:                         *      then check the wakeup cause.
        !          1084:                         */
        !          1085: 
        !          1086:                        ipc_thread_rmqueue(&mqueue->imq_threads, self);
        !          1087: 
        !          1088:                        switch (self->ith_wait_result) {
        !          1089:                            case THREAD_INTERRUPTED:
        !          1090:                            case THREAD_SHOULD_TERMINATE:
        !          1091:                                /* receive was interrupted - give up */
        !          1092: 
        !          1093:                                imq_unlock(mqueue);
        !          1094:                                return MACH_RCV_INTERRUPTED;
        !          1095: 
        !          1096:                            case THREAD_TIMED_OUT:
        !          1097:                                /* timeout expired */
        !          1098: 
        !          1099:                                assert(option & MACH_RCV_TIMEOUT);
        !          1100:                                timeout = 0;
        !          1101:                                break;
        !          1102: 
        !          1103:                            case THREAD_RESTART:
        !          1104:                            default:
        !          1105:                                panic("ipc_mqueue_receive");
        !          1106:                        }
        !          1107:                        break;
        !          1108: 
        !          1109:                    case MACH_RCV_HEADER_ERROR:
        !          1110:                        /*
        !          1111:                         * There was a message was queued on the
        !          1112:                         * port, but its format was incompatible
        !          1113:                         * with the receive operation we were
        !          1114:                         * performing.
        !          1115:                         */
        !          1116:                        goto return_kmsg;
        !          1117: 
        !          1118:                    default:
        !          1119:                        panic("ipc_mqueue_receive: strange ith_state");
        !          1120:                }
        !          1121:        }
        !          1122: 
        !          1123:        mr = self->ith_state;
        !          1124: 
        !          1125:        /* we have a kmsg; unlock the msg queue */
        !          1126: 
        !          1127:        imq_unlock(mqueue);
        !          1128:     }
        !          1129: 
        !          1130:     {
        !          1131:        ipc_marequest_t marequest;
        !          1132: 
        !          1133:        marequest = kmsg->ikm_marequest;
        !          1134:        if (marequest != IMAR_NULL) {
        !          1135:                ipc_marequest_destroy(marequest);
        !          1136:                kmsg->ikm_marequest = IMAR_NULL;
        !          1137:        }
        !          1138:        assert((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0);
        !          1139: 
        !          1140:        assert(port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port);
        !          1141:        ip_lock(port);
        !          1142: 
        !          1143:        if (ip_active(port)) {
        !          1144:                ipc_thread_queue_t senders;
        !          1145:                ipc_thread_t sender;
        !          1146: 
        !          1147:                assert(port->ip_msgcount > 0);
        !          1148:                port->ip_msgcount--;
        !          1149: 
        !          1150:                senders = &port->ip_blocked;
        !          1151:                sender = ipc_thread_queue_first(senders);
        !          1152: 
        !          1153:                if ((sender != ITH_NULL) &&
        !          1154:                    (port->ip_msgcount < port->ip_qlimit)) {
        !          1155:                        ipc_thread_rmqueue(senders, sender);
        !          1156:                        sender->ith_state = MACH_MSG_SUCCESS;
        !          1157:                        thread_go(sender);
        !          1158:                }
        !          1159:        }
        !          1160: 
        !          1161:        ip_unlock(port);
        !          1162:     }
        !          1163: 
        !          1164:        *kmsgp = kmsg;
        !          1165:        *seqnop = seqno;
        !          1166:        return mr;
        !          1167: }

unix.superglobalmegacorp.com

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