Annotation of Gnu-Mach/ipc/ipc_mqueue.c, revision 1.1.1.3

1.1       root        1: /*
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
                      4:  * Copyright (c) 1993,1994 The University of Utah and
                      5:  * the Computer Systems Laboratory (CSL).
                      6:  * All rights reserved.
                      7:  *
                      8:  * Permission to use, copy, modify and distribute this software and its
                      9:  * documentation is hereby granted, provided that both the copyright
                     10:  * notice and this permission notice appear in all copies of the
                     11:  * software, derivative works or modified versions, and any portions
                     12:  * thereof, and that both notices appear in supporting documentation.
                     13:  *
                     14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
                     15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
                     16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
                     17:  * THIS SOFTWARE.
                     18:  *
                     19:  * Carnegie Mellon requests users of this software to return to
                     20:  *
                     21:  *  Software Distribution Coordinator  or  [email protected]
                     22:  *  School of Computer Science
                     23:  *  Carnegie Mellon University
                     24:  *  Pittsburgh PA 15213-3890
                     25:  *
                     26:  * any improvements or extensions that they make and grant Carnegie Mellon
                     27:  * the rights to redistribute these changes.
                     28:  */
                     29: /*
                     30:  *     File:   ipc/ipc_mqueue.c
                     31:  *     Author: Rich Draves
                     32:  *     Date:   1989
                     33:  *
                     34:  *     Functions to manipulate IPC message queues.
                     35:  */
                     36: 
                     37: #include <mach/port.h>
                     38: #include <mach/message.h>
                     39: #include <kern/assert.h>
                     40: #include <kern/counters.h>
1.1.1.3 ! root       41: #include <kern/debug.h>
1.1       root       42: #include <kern/sched_prim.h>
                     43: #include <kern/ipc_sched.h>
                     44: #include <kern/ipc_kobject.h>
                     45: #include <ipc/ipc_mqueue.h>
                     46: #include <ipc/ipc_thread.h>
                     47: #include <ipc/ipc_kmsg.h>
                     48: #include <ipc/ipc_port.h>
                     49: #include <ipc/ipc_pset.h>
                     50: #include <ipc/ipc_space.h>
                     51: #include <ipc/ipc_marequest.h>
                     52: 
                     53: 
                     54: 
                     55: /*
                     56:  *     Routine:        ipc_mqueue_init
                     57:  *     Purpose:
                     58:  *             Initialize a newly-allocated message queue.
                     59:  */
                     60: 
                     61: void
                     62: ipc_mqueue_init(
                     63:        ipc_mqueue_t    mqueue)
                     64: {
                     65:        imq_lock_init(mqueue);
                     66:        ipc_kmsg_queue_init(&mqueue->imq_messages);
                     67:        ipc_thread_queue_init(&mqueue->imq_threads);
                     68: }
                     69: 
                     70: /*
                     71:  *     Routine:        ipc_mqueue_move
                     72:  *     Purpose:
                     73:  *             Move messages from one queue (source) to another (dest).
                     74:  *             Only moves messages sent to the specified port.
                     75:  *     Conditions:
                     76:  *             Both queues must be locked.
                     77:  *             (This is sufficient to manipulate port->ip_seqno.)
                     78:  */
                     79: 
                     80: void
                     81: ipc_mqueue_move(
                     82:        ipc_mqueue_t    dest,
                     83:        ipc_mqueue_t    source,
                     84:        ipc_port_t      port)
                     85: {
                     86:        ipc_kmsg_queue_t oldq, newq;
                     87:        ipc_thread_queue_t blockedq;
                     88:        ipc_kmsg_t kmsg, next;
                     89:        ipc_thread_t th;
                     90: 
                     91:        oldq = &source->imq_messages;
                     92:        newq = &dest->imq_messages;
                     93:        blockedq = &dest->imq_threads;
                     94: 
                     95:        for (kmsg = ipc_kmsg_queue_first(oldq);
                     96:             kmsg != IKM_NULL; kmsg = next) {
                     97:                next = ipc_kmsg_queue_next(oldq, kmsg);
                     98: 
                     99:                /* only move messages sent to port */
                    100: 
                    101:                if (kmsg->ikm_header.msgh_remote_port != (mach_port_t) port)
                    102:                        continue;
                    103: 
                    104:                ipc_kmsg_rmqueue(oldq, kmsg);
                    105: 
                    106:                /* before adding kmsg to newq, check for a blocked receiver */
                    107: 
                    108:                while ((th = ipc_thread_dequeue(blockedq)) != ITH_NULL) {
                    109:                        assert(ipc_kmsg_queue_empty(newq));
                    110: 
                    111:                        thread_go(th);
                    112: 
                    113:                        /* check if the receiver can handle the message */
                    114: 
                    115:                        if (kmsg->ikm_header.msgh_size <= th->ith_msize) {
                    116:                                th->ith_state = MACH_MSG_SUCCESS;
                    117:                                th->ith_kmsg = kmsg;
                    118:                                th->ith_seqno = port->ip_seqno++;
                    119: 
                    120:                                goto next_kmsg;
                    121:                        }
                    122: 
                    123:                        th->ith_state = MACH_RCV_TOO_LARGE;
                    124:                        th->ith_msize = kmsg->ikm_header.msgh_size;
                    125:                }
                    126: 
                    127:                /* didn't find a receiver to handle the message */
                    128: 
                    129:                ipc_kmsg_enqueue(newq, kmsg);
                    130:            next_kmsg:;
                    131:        }
                    132: }
                    133: 
                    134: /*
                    135:  *     Routine:        ipc_mqueue_changed
                    136:  *     Purpose:
                    137:  *             Wake up receivers waiting in a message queue.
                    138:  *     Conditions:
                    139:  *             The message queue is locked.
                    140:  */
                    141: 
                    142: void
                    143: ipc_mqueue_changed(
                    144:        ipc_mqueue_t            mqueue,
                    145:        mach_msg_return_t       mr)
                    146: {
                    147:        ipc_thread_t th;
                    148: 
                    149:        while ((th = ipc_thread_dequeue(&mqueue->imq_threads)) != ITH_NULL) {
                    150:                th->ith_state = mr;
                    151:                thread_go(th);
                    152:        }
                    153: }
                    154: 
                    155: /*
                    156:  *     Routine:        ipc_mqueue_send
                    157:  *     Purpose:
                    158:  *             Send a message to a port.  The message holds a reference
                    159:  *             for the destination port in the msgh_remote_port field.
                    160:  *
                    161:  *             If unsuccessful, the caller still has possession of
                    162:  *             the message and must do something with it.  If successful,
                    163:  *             the message is queued, given to a receiver, destroyed,
                    164:  *             or handled directly by the kernel via mach_msg.
                    165:  *     Conditions:
                    166:  *             Nothing locked.
                    167:  *     Returns:
                    168:  *             MACH_MSG_SUCCESS        The message was accepted.
                    169:  *             MACH_SEND_TIMED_OUT     Caller still has message.
                    170:  *             MACH_SEND_INTERRUPTED   Caller still has message.
                    171:  */
                    172: 
                    173: mach_msg_return_t
                    174: ipc_mqueue_send(kmsg, option, time_out)
                    175:        ipc_kmsg_t kmsg;
                    176:        mach_msg_option_t option;
                    177:        mach_msg_timeout_t time_out;
                    178: {
                    179:        ipc_port_t port;
                    180: 
                    181:        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
                    182:        assert(IP_VALID(port));
                    183: 
                    184:        ip_lock(port);
                    185: 
                    186:        if (port->ip_receiver == ipc_space_kernel) {
                    187:                ipc_kmsg_t reply;
                    188: 
                    189:                /*
                    190:                 *      We can check ip_receiver == ipc_space_kernel
                    191:                 *      before checking that the port is active because
                    192:                 *      ipc_port_dealloc_kernel clears ip_receiver
                    193:                 *      before destroying a kernel port.
                    194:                 */
                    195: 
                    196:                assert(ip_active(port));
                    197:                ip_unlock(port);
                    198: 
                    199:                reply = ipc_kobject_server(kmsg);
                    200:                if (reply != IKM_NULL)
                    201:                        ipc_mqueue_send_always(reply);
                    202: 
                    203:                return MACH_MSG_SUCCESS;
                    204:        }
                    205: 
                    206:        for (;;) {
                    207:                ipc_thread_t self;
                    208: 
                    209:                /*
                    210:                 *      Can't deliver to a dead port.
                    211:                 *      However, we can pretend it got sent
                    212:                 *      and was then immediately destroyed.
                    213:                 */
                    214: 
                    215:                if (!ip_active(port)) {
                    216:                        /*
                    217:                         *      We can't let ipc_kmsg_destroy deallocate
                    218:                         *      the port right, because we might end up
                    219:                         *      in an infinite loop trying to deliver
                    220:                         *      a send-once notification.
                    221:                         */
                    222: 
                    223:                        ip_release(port);
                    224:                        ip_check_unlock(port);
                    225:                        kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    226:                        ipc_kmsg_destroy(kmsg);
                    227:                        return MACH_MSG_SUCCESS;
                    228:                }
                    229: 
                    230:                /*
                    231:                 *  Don't block if:
                    232:                 *      1) We're under the queue limit.
                    233:                 *      2) Caller used the MACH_SEND_ALWAYS internal option.
                    234:                 *      3) Message is sent to a send-once right.
                    235:                 */
                    236: 
                    237:                if ((port->ip_msgcount < port->ip_qlimit) ||
                    238:                    (option & MACH_SEND_ALWAYS) ||
                    239:                    (MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
                    240:                                                MACH_MSG_TYPE_PORT_SEND_ONCE))
                    241:                        break;
                    242: 
                    243:                /* must block waiting for queue to clear */
                    244: 
                    245:                self = current_thread();
                    246: 
                    247:                if (option & MACH_SEND_TIMEOUT) {
                    248:                        if (time_out == 0) {
                    249:                                ip_unlock(port);
                    250:                                return MACH_SEND_TIMED_OUT;
                    251:                        }
                    252: 
                    253:                        thread_will_wait_with_timeout(self, time_out);
                    254:                } else
                    255:                        thread_will_wait(self);
                    256: 
                    257:                ipc_thread_enqueue(&port->ip_blocked, self);
                    258:                self->ith_state = MACH_SEND_IN_PROGRESS;
                    259: 
                    260:                ip_unlock(port);
                    261:                counter(c_ipc_mqueue_send_block++);
                    262:                thread_block((void (*)(void)) 0);
                    263:                ip_lock(port);
                    264: 
                    265:                /* why did we wake up? */
                    266: 
                    267:                if (self->ith_state == MACH_MSG_SUCCESS)
                    268:                        continue;
                    269:                assert(self->ith_state == MACH_SEND_IN_PROGRESS);
                    270: 
                    271:                /* take ourselves off blocked queue */
                    272: 
                    273:                ipc_thread_rmqueue(&port->ip_blocked, self);
                    274: 
                    275:                /*
                    276:                 *      Thread wakeup-reason field tells us why
                    277:                 *      the wait was interrupted.
                    278:                 */
                    279: 
                    280:                switch (self->ith_wait_result) {
                    281:                    case THREAD_INTERRUPTED:
                    282:                        /* send was interrupted - give up */
                    283: 
                    284:                        ip_unlock(port);
                    285:                        return MACH_SEND_INTERRUPTED;
                    286: 
                    287:                    case THREAD_TIMED_OUT:
                    288:                        /* timeout expired */
                    289: 
                    290:                        assert(option & MACH_SEND_TIMEOUT);
                    291:                        time_out = 0;
                    292:                        break;
                    293: 
                    294:                    case THREAD_RESTART:
                    295:                    default:
                    296: #if MACH_ASSERT
                    297:                        assert(!"ipc_mqueue_send");
                    298: #else
                    299:                        panic("ipc_mqueue_send");
                    300: #endif
                    301:                }
                    302:        }
                    303: 
                    304:        if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
                    305:                ip_unlock(port);
                    306: 
                    307:                /* don't allow the creation of a circular loop */
                    308: 
                    309:                ipc_kmsg_destroy(kmsg);
                    310:                return MACH_MSG_SUCCESS;
                    311:        }
                    312: 
                    313:     {
                    314:        ipc_mqueue_t mqueue;
                    315:        ipc_pset_t pset;
                    316:        ipc_thread_t receiver;
                    317:        ipc_thread_queue_t receivers;
                    318: 
                    319:        port->ip_msgcount++;
                    320:        assert(port->ip_msgcount > 0);
                    321: 
                    322:        pset = port->ip_pset;
                    323:        if (pset == IPS_NULL)
                    324:                mqueue = &port->ip_messages;
                    325:        else
                    326:                mqueue = &pset->ips_messages;
                    327: 
                    328:        imq_lock(mqueue);
                    329:        receivers = &mqueue->imq_threads;
                    330: 
                    331:        /*
                    332:         *      Can unlock the port now that the msg queue is locked
                    333:         *      and we know the port is active.  While the msg queue
                    334:         *      is locked, we have control of the kmsg, so the ref in
                    335:         *      it for the port is still good.  If the msg queue is in
                    336:         *      a set (dead or alive), then we're OK because the port
                    337:         *      is still a member of the set and the set won't go away
                    338:         *      until the port is taken out, which tries to lock the
                    339:         *      set's msg queue to remove the port's msgs.
                    340:         */
                    341: 
                    342:        ip_unlock(port);
                    343: 
                    344:        /* check for a receiver for the message */
                    345: 
                    346:        for (;;) {
                    347:                receiver = ipc_thread_queue_first(receivers);
                    348:                if (receiver == ITH_NULL) {
                    349:                        /* no receivers; queue kmsg */
                    350: 
                    351:                        ipc_kmsg_enqueue_macro(&mqueue->imq_messages, kmsg);
                    352:                        imq_unlock(mqueue);
                    353:                        break;
                    354:                }
                    355: 
                    356:                ipc_thread_rmqueue_first_macro(receivers, receiver);
                    357:                assert(ipc_kmsg_queue_empty(&mqueue->imq_messages));
                    358: 
                    359:                if (kmsg->ikm_header.msgh_size <= receiver->ith_msize) {
                    360:                        /* got a successful receiver */
                    361: 
                    362:                        receiver->ith_state = MACH_MSG_SUCCESS;
                    363:                        receiver->ith_kmsg = kmsg;
                    364:                        receiver->ith_seqno = port->ip_seqno++;
                    365:                        imq_unlock(mqueue);
                    366: 
                    367:                        thread_go(receiver);
                    368:                        break;
                    369:                }
                    370: 
                    371:                receiver->ith_state = MACH_RCV_TOO_LARGE;
                    372:                receiver->ith_msize = kmsg->ikm_header.msgh_size;
                    373:                thread_go(receiver);
                    374:        }
                    375:     }
                    376: 
1.1.1.3 ! root      377:        current_task()->messages_sent++;
        !           378: 
1.1       root      379:        return MACH_MSG_SUCCESS;
                    380: }
                    381: 
                    382: /*
                    383:  *     Routine:        ipc_mqueue_copyin
                    384:  *     Purpose:
                    385:  *             Convert a name in a space to a message queue.
                    386:  *     Conditions:
                    387:  *             Nothing locked.  If successful, the message queue
                    388:  *             is returned locked and caller gets a ref for the object.
                    389:  *             This ref ensures the continued existence of the queue.
                    390:  *     Returns:
                    391:  *             MACH_MSG_SUCCESS        Found a message queue.
                    392:  *             MACH_RCV_INVALID_NAME   The space is dead.
                    393:  *             MACH_RCV_INVALID_NAME   The name doesn't denote a right.
                    394:  *             MACH_RCV_INVALID_NAME
                    395:  *                     The denoted right is not receive or port set.
                    396:  *             MACH_RCV_IN_SET         Receive right is a member of a set.
                    397:  */
                    398: 
                    399: mach_msg_return_t
                    400: ipc_mqueue_copyin(
                    401:        ipc_space_t     space,
                    402:        mach_port_t     name,
                    403:        ipc_mqueue_t    *mqueuep,
                    404:        ipc_object_t    *objectp)
                    405: {
                    406:        ipc_entry_t entry;
                    407:        ipc_entry_bits_t bits;
                    408:        ipc_object_t object;
                    409:        ipc_mqueue_t mqueue;
                    410: 
                    411:        is_read_lock(space);
                    412:        if (!space->is_active) {
                    413:                is_read_unlock(space);
                    414:                return MACH_RCV_INVALID_NAME;
                    415:        }
                    416: 
                    417:        entry = ipc_entry_lookup(space, name);
                    418:        if (entry == IE_NULL) {
                    419:                is_read_unlock(space);
                    420:                return MACH_RCV_INVALID_NAME;
                    421:        }
                    422: 
                    423:        bits = entry->ie_bits;
                    424:        object = entry->ie_object;
                    425: 
                    426:        if (bits & MACH_PORT_TYPE_RECEIVE) {
                    427:                ipc_port_t port;
                    428:                ipc_pset_t pset;
                    429: 
                    430:                port = (ipc_port_t) object;
                    431:                assert(port != IP_NULL);
                    432: 
                    433:                ip_lock(port);
                    434:                assert(ip_active(port));
                    435:                assert(port->ip_receiver_name == name);
                    436:                assert(port->ip_receiver == space);
                    437:                is_read_unlock(space);
                    438: 
                    439:                pset = port->ip_pset;
                    440:                if (pset != IPS_NULL) {
                    441:                        ips_lock(pset);
                    442:                        if (ips_active(pset)) {
                    443:                                ips_unlock(pset);
                    444:                                ip_unlock(port);
                    445:                                return MACH_RCV_IN_SET;
                    446:                        }
                    447: 
                    448:                        ipc_pset_remove(pset, port);
                    449:                        ips_check_unlock(pset);
                    450:                        assert(port->ip_pset == IPS_NULL);
                    451:                }
                    452: 
                    453:                mqueue = &port->ip_messages;
                    454:        } else if (bits & MACH_PORT_TYPE_PORT_SET) {
                    455:                ipc_pset_t pset;
                    456: 
                    457:                pset = (ipc_pset_t) object;
                    458:                assert(pset != IPS_NULL);
                    459: 
                    460:                ips_lock(pset);
                    461:                assert(ips_active(pset));
                    462:                assert(pset->ips_local_name == name);
                    463:                is_read_unlock(space);
                    464: 
                    465:                mqueue = &pset->ips_messages;
                    466:        } else {
                    467:                is_read_unlock(space);
                    468:                return MACH_RCV_INVALID_NAME;
                    469:        }
                    470: 
                    471:        /*
                    472:         *      At this point, the object is locked and active,
                    473:         *      the space is unlocked, and mqueue is initialized.
                    474:         */
                    475: 
                    476:        io_reference(object);
                    477:        imq_lock(mqueue);
                    478:        io_unlock(object);
                    479: 
                    480:        *objectp = object;
                    481:        *mqueuep = mqueue;
                    482:        return MACH_MSG_SUCCESS;
                    483: }
                    484: 
                    485: /*
                    486:  *     Routine:        ipc_mqueue_receive
                    487:  *     Purpose:
                    488:  *             Receive a message from a message queue.
                    489:  *
                    490:  *             If continuation is non-zero, then we might discard
                    491:  *             our kernel stack when we block.  We will continue
                    492:  *             after unblocking by executing continuation.
                    493:  *
                    494:  *             If resume is true, then we are resuming a receive
                    495:  *             operation after a blocked receive discarded our stack.
                    496:  *     Conditions:
                    497:  *             The message queue is locked; it will be returned unlocked.
                    498:  *
                    499:  *             Our caller must hold a reference for the port or port set
                    500:  *             to which this queue belongs, to keep the queue
                    501:  *             from being deallocated.  Furthermore, the port or set
                    502:  *             must have been active when the queue was locked.
                    503:  *
                    504:  *             The kmsg is returned with clean header fields
                    505:  *             and with the circular bit turned off.
                    506:  *     Returns:
                    507:  *             MACH_MSG_SUCCESS        Message returned in kmsgp.
                    508:  *             MACH_RCV_TOO_LARGE      Message size returned in kmsgp.
                    509:  *             MACH_RCV_TIMED_OUT      No message obtained.
                    510:  *             MACH_RCV_INTERRUPTED    No message obtained.
                    511:  *             MACH_RCV_PORT_DIED      Port/set died; no message.
                    512:  *             MACH_RCV_PORT_CHANGED   Port moved into set; no msg.
                    513:  *
                    514:  */
                    515: 
                    516: mach_msg_return_t
                    517: ipc_mqueue_receive(
                    518:        ipc_mqueue_t            mqueue,
                    519:        mach_msg_option_t       option,
                    520:        mach_msg_size_t         max_size,
                    521:        mach_msg_timeout_t      time_out,
                    522:        boolean_t               resume,
                    523:        void                    (*continuation)(void),
                    524:        ipc_kmsg_t              *kmsgp,
                    525:        mach_port_seqno_t       *seqnop)
                    526: {
                    527:        ipc_port_t port;
                    528:        ipc_kmsg_t kmsg;
                    529:        mach_port_seqno_t seqno;
                    530: 
                    531:     {
                    532:        ipc_kmsg_queue_t kmsgs = &mqueue->imq_messages;
                    533:        ipc_thread_t self = current_thread();
                    534: 
                    535:        if (resume)
                    536:                goto after_thread_block;
                    537: 
                    538:        for (;;) {
                    539:                kmsg = ipc_kmsg_queue_first(kmsgs);
                    540:                if (kmsg != IKM_NULL) {
                    541:                        /* check space requirements */
                    542: 
                    543:                        if (kmsg->ikm_header.msgh_size > max_size) {
                    544:                                * (mach_msg_size_t *) kmsgp =
                    545:                                        kmsg->ikm_header.msgh_size;
                    546:                                imq_unlock(mqueue);
                    547:                                return MACH_RCV_TOO_LARGE;
                    548:                        }
                    549: 
                    550:                        ipc_kmsg_rmqueue_first_macro(kmsgs, kmsg);
                    551:                        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
                    552:                        seqno = port->ip_seqno++;
                    553:                        break;
                    554:                }
                    555: 
                    556:                /* must block waiting for a message */
                    557: 
                    558:                if (option & MACH_RCV_TIMEOUT) {
                    559:                        if (time_out == 0) {
                    560:                                imq_unlock(mqueue);
                    561:                                return MACH_RCV_TIMED_OUT;
                    562:                        }
                    563: 
                    564:                        thread_will_wait_with_timeout(self, time_out);
                    565:                } else
                    566:                        thread_will_wait(self);
                    567: 
                    568:                ipc_thread_enqueue_macro(&mqueue->imq_threads, self);
                    569:                self->ith_state = MACH_RCV_IN_PROGRESS;
                    570:                self->ith_msize = max_size;
                    571: 
                    572:                imq_unlock(mqueue);
                    573:                if (continuation != (void (*)(void)) 0) {
                    574:                        counter(c_ipc_mqueue_receive_block_user++);
                    575:                } else {
                    576:                        counter(c_ipc_mqueue_receive_block_kernel++);
                    577:                }
                    578:                thread_block(continuation);
                    579:        after_thread_block:
                    580:                imq_lock(mqueue);
                    581: 
                    582:                /* why did we wake up? */
                    583: 
                    584:                if (self->ith_state == MACH_MSG_SUCCESS) {
                    585:                        /* pick up the message that was handed to us */
                    586: 
                    587:                        kmsg = self->ith_kmsg;
                    588:                        seqno = self->ith_seqno;
                    589:                        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
                    590:                        break;
                    591:                }
                    592: 
                    593:                switch (self->ith_state) {
                    594:                    case MACH_RCV_TOO_LARGE:
                    595:                        /* pick up size of the too-large message */
                    596: 
                    597:                        * (mach_msg_size_t *) kmsgp = self->ith_msize;
                    598:                        /* fall-through */
                    599: 
                    600:                    case MACH_RCV_PORT_DIED:
                    601:                    case MACH_RCV_PORT_CHANGED:
                    602:                        /* something bad happened to the port/set */
                    603: 
                    604:                        imq_unlock(mqueue);
                    605:                        return self->ith_state;
                    606: 
                    607:                    case MACH_RCV_IN_PROGRESS:
                    608:                        /*
                    609:                         *      Awakened for other than IPC completion.
                    610:                         *      Remove ourselves from the waiting queue,
                    611:                         *      then check the wakeup cause.
                    612:                         */
                    613: 
                    614:                        ipc_thread_rmqueue(&mqueue->imq_threads, self);
                    615: 
                    616:                        switch (self->ith_wait_result) {
                    617:                            case THREAD_INTERRUPTED:
                    618:                                /* receive was interrupted - give up */
                    619: 
                    620:                                imq_unlock(mqueue);
                    621:                                return MACH_RCV_INTERRUPTED;
                    622: 
                    623:                            case THREAD_TIMED_OUT:
                    624:                                /* timeout expired */
                    625: 
                    626:                                assert(option & MACH_RCV_TIMEOUT);
                    627:                                time_out = 0;
                    628:                                break;
                    629: 
                    630:                            case THREAD_RESTART:
                    631:                            default:
                    632: #if MACH_ASSERT
                    633:                                assert(!"ipc_mqueue_receive");
                    634: #else
                    635:                                panic("ipc_mqueue_receive");
                    636: #endif
                    637:                        }
                    638:                        break;
                    639: 
                    640:                    default:
                    641: #if MACH_ASSERT
                    642:                        assert(!"ipc_mqueue_receive: strange ith_state");
                    643: #else
                    644:                        panic("ipc_mqueue_receive: strange ith_state");
                    645: #endif
                    646:                }
                    647:        }
                    648: 
                    649:        /* we have a kmsg; unlock the msg queue */
                    650: 
                    651:        imq_unlock(mqueue);
                    652:        assert(kmsg->ikm_header.msgh_size <= max_size);
                    653:     }
                    654: 
                    655:     {
                    656:        ipc_marequest_t marequest;
                    657: 
                    658:        marequest = kmsg->ikm_marequest;
                    659:        if (marequest != IMAR_NULL) {
                    660:                ipc_marequest_destroy(marequest);
                    661:                kmsg->ikm_marequest = IMAR_NULL;
                    662:        }
                    663:        assert((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) == 0);
                    664: 
                    665:        assert(port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port);
                    666:        ip_lock(port);
                    667: 
                    668:        if (ip_active(port)) {
                    669:                ipc_thread_queue_t senders;
                    670:                ipc_thread_t sender;
                    671: 
                    672:                assert(port->ip_msgcount > 0);
                    673:                port->ip_msgcount--;
                    674: 
                    675:                senders = &port->ip_blocked;
                    676:                sender = ipc_thread_queue_first(senders);
                    677: 
                    678:                if ((sender != ITH_NULL) &&
                    679:                    (port->ip_msgcount < port->ip_qlimit)) {
                    680:                        ipc_thread_rmqueue(senders, sender);
                    681:                        sender->ith_state = MACH_MSG_SUCCESS;
                    682:                        thread_go(sender);
                    683:                }
                    684:        }
                    685: 
                    686:        ip_unlock(port);
                    687:     }
                    688: 
1.1.1.3 ! root      689:        current_task()->messages_received++;
        !           690: 
1.1       root      691:        *kmsgp = kmsg;
                    692:        *seqnop = seqno;
                    693:        return MACH_MSG_SUCCESS;
                    694: }

unix.superglobalmegacorp.com

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