Annotation of Gnu-Mach/kern/exception.c, revision 1.1.1.1

1.1       root        1: /* 
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1993,1992,1991,1990,1989,1988,1987 Carnegie Mellon University.
                      4:  * All Rights Reserved.
                      5:  * 
                      6:  * Permission to use, copy, modify and distribute this software and its
                      7:  * documentation is hereby granted, provided that both the copyright
                      8:  * notice and this permission notice appear in all copies of the
                      9:  * software, derivative works or modified versions, and any portions
                     10:  * thereof, and that both notices appear in supporting documentation.
                     11:  * 
                     12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     15:  * 
                     16:  * Carnegie Mellon requests users of this software to return to
                     17:  * 
                     18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
                     22:  * 
                     23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: 
                     27: #include <norma_ipc.h>
                     28: #include <mach_kdb.h>
                     29: 
                     30: #include <mach/boolean.h>
                     31: #include <mach/kern_return.h>
                     32: #include <mach/message.h>
                     33: #include <mach/port.h>
                     34: #include <mach/mig_errors.h>
                     35: #include <ipc/port.h>
                     36: #include <ipc/ipc_entry.h>
                     37: #include <ipc/ipc_object.h>
                     38: #include <ipc/ipc_space.h>
                     39: #include <ipc/ipc_port.h>
                     40: #include <ipc/ipc_pset.h>
                     41: #include <ipc/mach_msg.h>
                     42: #include <ipc/ipc_machdep.h>
                     43: #include <kern/counters.h>
                     44: #include <kern/ipc_tt.h>
                     45: #include <kern/task.h>
                     46: #include <kern/thread.h>
                     47: #include <kern/processor.h>
                     48: #include <kern/sched.h>
                     49: #include <kern/sched_prim.h>
                     50: #include <mach/machine/vm_types.h>
                     51: 
                     52: 
                     53: 
                     54: extern void exception();
                     55: extern void exception_try_task();
                     56: extern void exception_no_server();
                     57: 
                     58: extern void exception_raise();
                     59: extern kern_return_t exception_parse_reply();
                     60: extern void exception_raise_continue();
                     61: extern void exception_raise_continue_slow();
                     62: extern void exception_raise_continue_fast();
                     63: 
                     64: #if    MACH_KDB
                     65: extern void thread_kdb_return();
                     66: extern void db_printf();
                     67: 
                     68: boolean_t debug_user_with_kdb = FALSE;
                     69: #endif /* MACH_KDB */
                     70: 
                     71: #ifdef KEEP_STACKS
                     72: /*
                     73:  *     Some obsolete architectures don't support kernel stack discarding
                     74:  *     or the thread_exception_return, thread_syscall_return continuations.
                     75:  *     For these architectures, the NOTREACHED comments below are incorrect.
                     76:  *     The exception function is expected to return.
                     77:  *     So the return statements along the slow paths are important.
                     78:  */
                     79: #endif KEEP_STACKS
                     80: 
                     81: /*
                     82:  *     Routine:        exception
                     83:  *     Purpose:
                     84:  *             The current thread caught an exception.
                     85:  *             We make an up-call to the thread's exception server.
                     86:  *     Conditions:
                     87:  *             Nothing locked and no resources held.
                     88:  *             Called from an exception context, so
                     89:  *             thread_exception_return and thread_kdb_return
                     90:  *             are possible.
                     91:  *     Returns:
                     92:  *             Doesn't return.
                     93:  */
                     94: 
                     95: void
                     96: exception(_exception, code, subcode)
                     97:        integer_t _exception, code, subcode;
                     98: {
                     99:        register ipc_thread_t self = current_thread();
                    100:        register ipc_port_t exc_port;
                    101: 
                    102:        if (_exception == KERN_SUCCESS)
                    103:                panic("exception");
                    104: 
                    105:        /*
                    106:         *      Optimized version of retrieve_thread_exception.
                    107:         */
                    108: 
                    109:        ith_lock(self);
                    110:        assert(self->ith_self != IP_NULL);
                    111:        exc_port = self->ith_exception;
                    112:        if (!IP_VALID(exc_port)) {
                    113:                ith_unlock(self);
                    114:                exception_try_task(_exception, code, subcode);
                    115:                /*NOTREACHED*/
                    116:                return;
                    117:        }
                    118: 
                    119:        ip_lock(exc_port);
                    120:        ith_unlock(self);
                    121:        if (!ip_active(exc_port)) {
                    122:                ip_unlock(exc_port);
                    123:                exception_try_task(_exception, code, subcode);
                    124:                /*NOTREACHED*/
                    125:                return;
                    126:        }
                    127: 
                    128:        /*
                    129:         *      Make a naked send right for the exception port.
                    130:         */
                    131: 
                    132:        ip_reference(exc_port);
                    133:        exc_port->ip_srights++;
                    134:        ip_unlock(exc_port);
                    135: 
                    136:        /*
                    137:         *      If this exception port doesn't work,
                    138:         *      we will want to try the task's exception port.
                    139:         *      Indicate this by saving the exception state.
                    140:         */
                    141: 
                    142:        self->ith_exc = _exception;
                    143:        self->ith_exc_code = code;
                    144:        self->ith_exc_subcode = subcode;
                    145: 
                    146:        exception_raise(exc_port,
                    147:                        retrieve_thread_self_fast(self),
                    148:                        retrieve_task_self_fast(self->task),
                    149:                        _exception, code, subcode);
                    150:        /*NOTREACHED*/
                    151: }
                    152: 
                    153: /*
                    154:  *     Routine:        exception_try_task
                    155:  *     Purpose:
                    156:  *             The current thread caught an exception.
                    157:  *             We make an up-call to the task's exception server.
                    158:  *     Conditions:
                    159:  *             Nothing locked and no resources held.
                    160:  *             Called from an exception context, so
                    161:  *             thread_exception_return and thread_kdb_return
                    162:  *             are possible.
                    163:  *     Returns:
                    164:  *             Doesn't return.
                    165:  */
                    166: 
                    167: void
                    168: exception_try_task(_exception, code, subcode)
                    169:        integer_t _exception, code, subcode;
                    170: {
                    171:        ipc_thread_t self = current_thread();
                    172:        register task_t task = self->task;
                    173:        register ipc_port_t exc_port;
                    174: 
                    175:        /*
                    176:         *      Optimized version of retrieve_task_exception.
                    177:         */
                    178: 
                    179:        itk_lock(task);
                    180:        assert(task->itk_self != IP_NULL);
                    181:        exc_port = task->itk_exception;
                    182:        if (!IP_VALID(exc_port)) {
                    183:                itk_unlock(task);
                    184:                exception_no_server();
                    185:                /*NOTREACHED*/
                    186:                return;
                    187:        }
                    188: 
                    189:        ip_lock(exc_port);
                    190:        itk_unlock(task);
                    191:        if (!ip_active(exc_port)) {
                    192:                ip_unlock(exc_port);
                    193:                exception_no_server();
                    194:                /*NOTREACHED*/
                    195:                return;
                    196:        }
                    197: 
                    198:        /*
                    199:         *      Make a naked send right for the exception port.
                    200:         */
                    201: 
                    202:        ip_reference(exc_port);
                    203:        exc_port->ip_srights++;
                    204:        ip_unlock(exc_port);
                    205: 
                    206:        /*
                    207:         *      This is the thread's last chance.
                    208:         *      Clear the saved exception state.
                    209:         */
                    210: 
                    211:        self->ith_exc = KERN_SUCCESS;
                    212: 
                    213:        exception_raise(exc_port,
                    214:                        retrieve_thread_self_fast(self),
                    215:                        retrieve_task_self_fast(task),
                    216:                        _exception, code, subcode);
                    217:        /*NOTREACHED*/
                    218: }
                    219: 
                    220: /*
                    221:  *     Routine:        exception_no_server
                    222:  *     Purpose:
                    223:  *             The current thread took an exception,
                    224:  *             and no exception server took responsibility
                    225:  *             for the exception.  So good bye, charlie.
                    226:  *     Conditions:
                    227:  *             Nothing locked and no resources held.
                    228:  *             Called from an exception context, so
                    229:  *             thread_kdb_return is possible.
                    230:  *     Returns:
                    231:  *             Doesn't return.
                    232:  */
                    233: 
                    234: void
                    235: exception_no_server()
                    236: {
                    237:        register ipc_thread_t self = current_thread();
                    238: 
                    239:        /*
                    240:         *      If this thread is being terminated, cooperate.
                    241:         */
                    242: 
                    243:        while (thread_should_halt(self))
                    244:                thread_halt_self();
                    245: 
                    246: 
                    247:        if (thread_suspend (self) == KERN_SUCCESS)
                    248:          thread_exception_return ();
                    249: 
                    250: #if    MACH_KDB
                    251:        if (debug_user_with_kdb) {
                    252:                /*
                    253:                 *      Debug the exception with kdb.
                    254:                 *      If kdb handles the exception,
                    255:                 *      then thread_kdb_return won't return.
                    256:                 */
                    257: 
                    258:                db_printf("No exception server, calling kdb...\n");
                    259:                thread_kdb_return();
                    260:        }
                    261: #endif MACH_KDB
                    262: 
                    263:        /*
                    264:         *      All else failed; terminate task.
                    265:         */
                    266: 
                    267:        (void) task_terminate(self->task);
                    268:        thread_halt_self();
                    269:        /*NOTREACHED*/
                    270: }
                    271: 
                    272: #define MACH_EXCEPTION_ID              2400    /* from mach/exc.defs */
                    273: #define MACH_EXCEPTION_REPLY_ID                (MACH_EXCEPTION_ID + 100)
                    274: 
                    275: struct mach_exception {
                    276:        mach_msg_header_t       Head;
                    277:        mach_msg_type_t         threadType;
                    278:        mach_port_t             thread;
                    279:        mach_msg_type_t         taskType;
                    280:        mach_port_t             task;
                    281:        mach_msg_type_t         exceptionType;
                    282:        integer_t               exception;
                    283:        mach_msg_type_t         codeType;
                    284:        integer_t               code;
                    285:        mach_msg_type_t         subcodeType;
                    286:        integer_t               subcode;
                    287: };
                    288: 
                    289: #define        INTEGER_T_SIZE_IN_BITS  (8 * sizeof(integer_t))
                    290: #define        INTEGER_T_TYPE          MACH_MSG_TYPE_INTEGER_T
                    291:                                        /* in mach/machine/vm_types.h */
                    292: 
                    293: mach_msg_type_t exc_port_proto = {
                    294:        /* msgt_name = */               MACH_MSG_TYPE_PORT_SEND,
                    295:        /* msgt_size = */               PORT_T_SIZE_IN_BITS,
                    296:        /* msgt_number = */             1,
                    297:        /* msgt_inline = */             TRUE,
                    298:        /* msgt_longform = */           FALSE,
                    299:        /* msgt_deallocate = */         FALSE,
                    300:        /* msgt_unused = */             0
                    301: };
                    302: 
                    303: mach_msg_type_t exc_code_proto = {
                    304:        /* msgt_name = */               INTEGER_T_TYPE,
                    305:        /* msgt_size = */               INTEGER_T_SIZE_IN_BITS,
                    306:        /* msgt_number = */             1,
                    307:        /* msgt_inline = */             TRUE,
                    308:        /* msgt_longform = */           FALSE,
                    309:        /* msgt_deallocate = */         FALSE,
                    310:        /* msgt_unused = */             0
                    311: };
                    312: 
                    313: /*
                    314:  *     Routine:        exception_raise
                    315:  *     Purpose:
                    316:  *             Make an exception_raise up-call to an exception server.
                    317:  *
                    318:  *             dest_port must be a valid naked send right.
                    319:  *             thread_port and task_port are naked send rights.
                    320:  *             All three are always consumed.
                    321:  *
                    322:  *             self->ith_exc, self->ith_exc_code, self->ith_exc_subcode
                    323:  *             must be appropriately initialized.
                    324:  *     Conditions:
                    325:  *             Nothing locked.  We are being called in an exception context,
                    326:  *             so thread_exception_return may be called.
                    327:  *     Returns:
                    328:  *             Doesn't return.
                    329:  */
                    330: 
                    331: int exception_raise_misses = 0;
                    332: 
                    333: void
                    334: exception_raise(dest_port, thread_port, task_port,
                    335:                _exception, code, subcode)
                    336:        ipc_port_t dest_port;
                    337:        ipc_port_t thread_port;
                    338:        ipc_port_t task_port;
                    339:        integer_t _exception, code, subcode;
                    340: {
                    341:        ipc_thread_t self = current_thread();
                    342:        ipc_thread_t receiver;
                    343:        ipc_port_t reply_port;
                    344:        ipc_mqueue_t dest_mqueue;
                    345:        ipc_mqueue_t reply_mqueue;
                    346:        ipc_kmsg_t kmsg;
                    347:        mach_msg_return_t mr;
                    348: 
                    349:        assert(IP_VALID(dest_port));
                    350: 
                    351:        /*
                    352:         *      We will eventually need a message buffer.
                    353:         *      Grab the buffer now, while nothing is locked.
                    354:         *      This buffer will get handed to the exception server,
                    355:         *      and it will give the buffer back with its reply.
                    356:         */
                    357: 
                    358:        kmsg = ikm_cache();
                    359:        if (kmsg != IKM_NULL) {
                    360:                ikm_cache() = IKM_NULL;
                    361:                ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
                    362:        } else {
                    363:                kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
                    364:                if (kmsg == IKM_NULL)
                    365:                        panic("exception_raise");
                    366:                ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
                    367:        }
                    368: 
                    369:        /*
                    370:         *      We need a reply port for the RPC.
                    371:         *      Check first for a cached port.
                    372:         */
                    373: 
                    374:        ith_lock(self);
                    375:        assert(self->ith_self != IP_NULL);
                    376: 
                    377:        reply_port = self->ith_rpc_reply;
                    378:        if (reply_port == IP_NULL) {
                    379:                ith_unlock(self);
                    380:                reply_port = ipc_port_alloc_reply();
                    381:                ith_lock(self);
                    382:                if ((reply_port == IP_NULL) ||
                    383:                    (self->ith_rpc_reply != IP_NULL))
                    384:                        panic("exception_raise");
                    385:                self->ith_rpc_reply = reply_port;
                    386:        }
                    387: 
                    388:        ip_lock(reply_port);
                    389:        assert(ip_active(reply_port));
                    390:        ith_unlock(self);
                    391: 
                    392:        /*
                    393:         *      Make a naked send-once right for the reply port,
                    394:         *      to hand to the exception server.
                    395:         *      Make an extra reference for the reply port,
                    396:         *      to receive on.  This protects us against
                    397:         *      mach_msg_abort_rpc.
                    398:         */
                    399: 
                    400:        reply_port->ip_sorights++;
                    401:        ip_reference(reply_port);
                    402: 
                    403:        ip_reference(reply_port);
                    404:        self->ith_port = reply_port;
                    405: 
                    406:        reply_mqueue = &reply_port->ip_messages;
                    407:        imq_lock(reply_mqueue);
                    408:        assert(ipc_kmsg_queue_empty(&reply_mqueue->imq_messages));
                    409:        ip_unlock(reply_port);
                    410: 
                    411:        /*
                    412:         *      Make sure we can queue to the destination port.
                    413:         */
                    414: 
                    415:        if (!ip_lock_try(dest_port)) {
                    416:                imq_unlock(reply_mqueue);
                    417:                goto slow_exception_raise;
                    418:        }
                    419: 
                    420:        if (!ip_active(dest_port) ||
                    421: #if    NORMA_IPC
                    422:            IP_NORMA_IS_PROXY(dest_port) ||
                    423: #endif NORMA_IPC
                    424:            (dest_port->ip_receiver == ipc_space_kernel)) {
                    425:                imq_unlock(reply_mqueue);
                    426:                ip_unlock(dest_port);
                    427:                goto slow_exception_raise;
                    428:        }
                    429: 
                    430:        /*
                    431:         *      Find the destination message queue.
                    432:         */
                    433: 
                    434:     {
                    435:        register ipc_pset_t dest_pset;
                    436: 
                    437:        dest_pset = dest_port->ip_pset;
                    438:        if (dest_pset == IPS_NULL)
                    439:                dest_mqueue = &dest_port->ip_messages;
                    440:        else
                    441:                dest_mqueue = &dest_pset->ips_messages;
                    442:     }
                    443: 
                    444:        if (!imq_lock_try(dest_mqueue)) {
                    445:                imq_unlock(reply_mqueue);
                    446:                ip_unlock(dest_port);
                    447:                goto slow_exception_raise;
                    448:        }
                    449: 
                    450:        /*
                    451:         *      Safe to unlock dest_port, because we hold
                    452:         *      dest_mqueue locked.  We never bother changing
                    453:         *      dest_port->ip_msgcount.
                    454:         */
                    455: 
                    456:        ip_unlock(dest_port);
                    457: 
                    458:        receiver = ipc_thread_queue_first(&dest_mqueue->imq_threads);
                    459:        if ((receiver == ITH_NULL) ||
                    460:            !((receiver->swap_func == (void (*)()) mach_msg_continue) ||
                    461:              ((receiver->swap_func ==
                    462:                                (void (*)()) mach_msg_receive_continue) &&
                    463:               (sizeof(struct mach_exception) <= receiver->ith_msize) &&
                    464:               ((receiver->ith_option & MACH_RCV_NOTIFY) == 0))) ||
                    465:            !thread_handoff(self, exception_raise_continue, receiver)) {
                    466:                imq_unlock(reply_mqueue);
                    467:                imq_unlock(dest_mqueue);
                    468:                goto slow_exception_raise;
                    469:        }
                    470:        counter(c_exception_raise_block++);
                    471: 
                    472:        assert(current_thread() == receiver);
                    473: 
                    474:        /*
                    475:         *      We need to finish preparing self for its
                    476:         *      time asleep in reply_mqueue.  self is left
                    477:         *      holding the extra ref for reply_port.
                    478:         */
                    479: 
                    480:        ipc_thread_enqueue_macro(&reply_mqueue->imq_threads, self);
                    481:        self->ith_state = MACH_RCV_IN_PROGRESS;
                    482:        self->ith_msize = MACH_MSG_SIZE_MAX;
                    483:        imq_unlock(reply_mqueue);
                    484: 
                    485:        /*
                    486:         *      Finish extracting receiver from dest_mqueue.
                    487:         */
                    488: 
                    489:        ipc_thread_rmqueue_first_macro(
                    490:                &dest_mqueue->imq_threads, receiver);
                    491:        imq_unlock(dest_mqueue);
                    492: 
                    493:        /*
                    494:         *      Release the receiver's reference for his object.
                    495:         */
                    496:     {
                    497:        register ipc_object_t object = receiver->ith_object;
                    498: 
                    499:        io_lock(object);
                    500:        io_release(object);
                    501:        io_check_unlock(object);
                    502:     }
                    503: 
                    504:     {
                    505:        register struct mach_exception *exc =
                    506:                        (struct mach_exception *) &kmsg->ikm_header;
                    507:        ipc_space_t space = receiver->task->itk_space;
                    508: 
                    509:        /*
                    510:         *      We are running as the receiver now.  We hold
                    511:         *      the following resources, which must be consumed:
                    512:         *              kmsg, send-once right for reply_port
                    513:         *              send rights for dest_port, thread_port, task_port
                    514:         *      Synthesize a kmsg for copyout to the receiver.
                    515:         */
                    516: 
                    517:        exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
                    518:                                              MACH_MSG_TYPE_PORT_SEND) |
                    519:                               MACH_MSGH_BITS_COMPLEX);
                    520:        exc->Head.msgh_size = sizeof *exc;
                    521:      /* exc->Head.msgh_remote_port later */
                    522:      /* exc->Head.msgh_local_port later */
                    523:        exc->Head.msgh_seqno = 0;
                    524:        exc->Head.msgh_id = MACH_EXCEPTION_ID;
                    525:        exc->threadType = exc_port_proto;
                    526:      /* exc->thread later */
                    527:        exc->taskType = exc_port_proto;
                    528:      /* exc->task later */
                    529:        exc->exceptionType = exc_code_proto;
                    530:        exc->exception = _exception;
                    531:        exc->codeType = exc_code_proto;
                    532:        exc->code = code;
                    533:        exc->subcodeType = exc_code_proto;
                    534:        exc->subcode = subcode;
                    535: 
                    536:        /*
                    537:         *      Check that the receiver can handle the message.
                    538:         */
                    539: 
                    540:        if (receiver->ith_rcv_size < sizeof(struct mach_exception)) {
                    541:                /*
                    542:                 *      ipc_kmsg_destroy is a handy way to consume
                    543:                 *      the resources we hold, but it requires setup.
                    544:                 */
                    545: 
                    546:                exc->Head.msgh_bits =
                    547:                        (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    548:                                        MACH_MSG_TYPE_PORT_SEND_ONCE) |
                    549:                         MACH_MSGH_BITS_COMPLEX);
                    550:                exc->Head.msgh_remote_port = (mach_port_t) dest_port;
                    551:                exc->Head.msgh_local_port = (mach_port_t) reply_port;
                    552:                exc->thread = (mach_port_t) thread_port;
                    553:                exc->task = (mach_port_t) task_port;
                    554: 
                    555:                ipc_kmsg_destroy(kmsg);
                    556:                thread_syscall_return(MACH_RCV_TOO_LARGE);
                    557:                /*NOTREACHED*/
                    558:        }
                    559: 
                    560:        is_write_lock(space);
                    561:        assert(space->is_active);
                    562: 
                    563:        /*
                    564:         *      To do an atomic copyout, need simultaneous
                    565:         *      locks on both ports and the space.
                    566:         */
                    567: 
                    568:        ip_lock(dest_port);
                    569:        if (!ip_active(dest_port) ||
                    570:            !ip_lock_try(reply_port)) {
                    571:            abort_copyout:
                    572:                ip_unlock(dest_port);
                    573:                is_write_unlock(space);
                    574: 
                    575:                /*
                    576:                 *      Oh well, we have to do the header the slow way.
                    577:                 *      First make it look like it's in-transit.
                    578:                 */
                    579: 
                    580:                exc->Head.msgh_bits =
                    581:                        (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    582:                                        MACH_MSG_TYPE_PORT_SEND_ONCE) |
                    583:                         MACH_MSGH_BITS_COMPLEX);
                    584:                exc->Head.msgh_remote_port = (mach_port_t) dest_port;
                    585:                exc->Head.msgh_local_port = (mach_port_t) reply_port;
                    586: 
                    587:                mr = ipc_kmsg_copyout_header(&exc->Head, space,
                    588:                                             MACH_PORT_NULL);
                    589:                if (mr == MACH_MSG_SUCCESS)
                    590:                        goto copyout_body;
                    591: 
                    592:                /*
                    593:                 *      Ack!  Prepare for ipc_kmsg_copyout_dest.
                    594:                 *      It will consume thread_port and task_port.
                    595:                 */
                    596: 
                    597:                exc->thread = (mach_port_t) thread_port;
                    598:                exc->task = (mach_port_t) task_port;
                    599: 
                    600:                ipc_kmsg_copyout_dest(kmsg, space);
                    601:                (void) ipc_kmsg_put(receiver->ith_msg, kmsg,
                    602:                                    sizeof(mach_msg_header_t));
                    603:                thread_syscall_return(mr);
                    604:                /*NOTREACHED*/
                    605:        }
                    606: 
                    607:        if (!ip_active(reply_port)) {
                    608:                ip_unlock(reply_port);
                    609:                goto abort_copyout;
                    610:        }
                    611: 
                    612:        assert(reply_port->ip_sorights > 0);
                    613:        ip_unlock(reply_port);
                    614: 
                    615:     {
                    616:        register ipc_entry_t table;
                    617:        register ipc_entry_t entry;
                    618:        register mach_port_index_t index;
                    619: 
                    620:        /* optimized ipc_entry_get */
                    621: 
                    622:        table = space->is_table;
                    623:        index = table->ie_next;
                    624: 
                    625:        if (index == 0)
                    626:                goto abort_copyout;
                    627: 
                    628:        entry = &table[index];
                    629:        table->ie_next = entry->ie_next;
                    630:        entry->ie_request = 0;
                    631: 
                    632:     {
                    633:        register mach_port_gen_t gen;
                    634: 
                    635:        assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
                    636:        gen = entry->ie_bits + IE_BITS_GEN_ONE;
                    637: 
                    638:        exc->Head.msgh_remote_port = MACH_PORT_MAKE(index, gen);
                    639: 
                    640:        /* optimized ipc_right_copyout */
                    641: 
                    642:        entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
                    643:     }
                    644: 
                    645:        entry->ie_object = (ipc_object_t) reply_port;
                    646:        is_write_unlock(space);
                    647:     }
                    648: 
                    649:        /* optimized ipc_object_copyout_dest */
                    650: 
                    651:        assert(dest_port->ip_srights > 0);
                    652:        ip_release(dest_port);
                    653: 
                    654:        exc->Head.msgh_local_port =
                    655:                ((dest_port->ip_receiver == space) ?
                    656:                 dest_port->ip_receiver_name : MACH_PORT_NULL);
                    657: 
                    658:        if ((--dest_port->ip_srights == 0) &&
                    659:            (dest_port->ip_nsrequest != IP_NULL)) {
                    660:                ipc_port_t nsrequest;
                    661:                mach_port_mscount_t mscount;
                    662: 
                    663:                /* a rather rare case */
                    664: 
                    665:                nsrequest = dest_port->ip_nsrequest;
                    666:                mscount = dest_port->ip_mscount;
                    667:                dest_port->ip_nsrequest = IP_NULL;
                    668:                ip_unlock(dest_port);
                    669: 
                    670:                ipc_notify_no_senders(nsrequest, mscount);
                    671:        } else
                    672:                ip_unlock(dest_port);
                    673: 
                    674:     copyout_body:
                    675:        /*
                    676:         *      Optimized version of ipc_kmsg_copyout_body,
                    677:         *      to handle the two ports in the body.
                    678:         */
                    679: 
                    680:        mr = (ipc_kmsg_copyout_object(space, (ipc_object_t) thread_port,
                    681:                                      MACH_MSG_TYPE_PORT_SEND, &exc->thread) |
                    682:              ipc_kmsg_copyout_object(space, (ipc_object_t) task_port,
                    683:                                      MACH_MSG_TYPE_PORT_SEND, &exc->task));
                    684:        if (mr != MACH_MSG_SUCCESS) {
                    685:                (void) ipc_kmsg_put(receiver->ith_msg, kmsg,
                    686:                                    kmsg->ikm_header.msgh_size);
                    687:                thread_syscall_return(mr | MACH_RCV_BODY_ERROR);
                    688:                /*NOTREACHED*/
                    689:        }
                    690:     }
                    691: 
                    692:        /*
                    693:         *      Optimized version of ipc_kmsg_put.
                    694:         *      We must check ikm_cache after copyoutmsg.
                    695:         */
                    696: 
                    697:        ikm_check_initialized(kmsg, kmsg->ikm_size);
                    698:        assert(kmsg->ikm_size == IKM_SAVED_KMSG_SIZE);
                    699: 
                    700:        if (copyoutmsg((vm_offset_t) &kmsg->ikm_header, (vm_offset_t)receiver->ith_msg,
                    701:                       sizeof(struct mach_exception)) ||
                    702:            (ikm_cache() != IKM_NULL)) {
                    703:                mr = ipc_kmsg_put(receiver->ith_msg, kmsg,
                    704:                                  kmsg->ikm_header.msgh_size);
                    705:                thread_syscall_return(mr);
                    706:                /*NOTREACHED*/
                    707:        }
                    708: 
                    709:        ikm_cache() = kmsg;
                    710:        thread_syscall_return(MACH_MSG_SUCCESS);
                    711:        /*NOTREACHED*/
                    712: #ifndef        __GNUC__
                    713:        return; /* help for the compiler */
                    714: #endif
                    715: 
                    716:     slow_exception_raise: {
                    717:        register struct mach_exception *exc =
                    718:                        (struct mach_exception *) &kmsg->ikm_header;
                    719:        ipc_kmsg_t reply_kmsg;
                    720:        mach_port_seqno_t reply_seqno;
                    721: 
                    722:        exception_raise_misses++;
                    723: 
                    724:        /*
                    725:         *      We hold the following resources, which must be consumed:
                    726:         *              kmsg, send-once right and ref for reply_port
                    727:         *              send rights for dest_port, thread_port, task_port
                    728:         *      Synthesize a kmsg to send.
                    729:         */
                    730: 
                    731:        exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
                    732:                                              MACH_MSG_TYPE_PORT_SEND_ONCE) |
                    733:                               MACH_MSGH_BITS_COMPLEX);
                    734:        exc->Head.msgh_size = sizeof *exc;
                    735:        exc->Head.msgh_remote_port = (mach_port_t) dest_port;
                    736:        exc->Head.msgh_local_port = (mach_port_t) reply_port;
                    737:        exc->Head.msgh_seqno = 0;
                    738:        exc->Head.msgh_id = MACH_EXCEPTION_ID;
                    739:        exc->threadType = exc_port_proto;
                    740:        exc->thread = (mach_port_t) thread_port;
                    741:        exc->taskType = exc_port_proto;
                    742:        exc->task = (mach_port_t) task_port;
                    743:        exc->exceptionType = exc_code_proto;
                    744:        exc->exception = _exception;
                    745:        exc->codeType = exc_code_proto;
                    746:        exc->code = code;
                    747:        exc->subcodeType = exc_code_proto;
                    748:        exc->subcode = subcode;
                    749: 
                    750:        ipc_mqueue_send_always(kmsg);
                    751: 
                    752:        /*
                    753:         *      We are left with a ref for reply_port,
                    754:         *      which we use to receive the reply message.
                    755:         */
                    756: 
                    757:        ip_lock(reply_port);
                    758:        if (!ip_active(reply_port)) {
                    759:                ip_unlock(reply_port);
                    760:                exception_raise_continue_slow(MACH_RCV_PORT_DIED, IKM_NULL, /*dummy*/0);
                    761:                /*NOTREACHED*/
                    762:                return;
                    763:        }
                    764: 
                    765:        imq_lock(reply_mqueue);
                    766:        ip_unlock(reply_port);
                    767: 
                    768:        mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
                    769:                                MACH_MSG_SIZE_MAX,
                    770:                                MACH_MSG_TIMEOUT_NONE,
                    771:                                FALSE, exception_raise_continue,
                    772:                                &reply_kmsg, &reply_seqno);
                    773:        /* reply_mqueue is unlocked */
                    774: 
                    775:        exception_raise_continue_slow(mr, reply_kmsg, reply_seqno);
                    776:        /*NOTREACHED*/
                    777:     }
                    778: }
                    779: 
                    780: mach_msg_type_t exc_RetCode_proto = {
                    781:        /* msgt_name = */               MACH_MSG_TYPE_INTEGER_32,
                    782:        /* msgt_size = */               32,
                    783:        /* msgt_number = */             1,
                    784:        /* msgt_inline = */             TRUE,
                    785:        /* msgt_longform = */           FALSE,
                    786:        /* msgt_deallocate = */         FALSE,
                    787:        /* msgt_unused = */             0
                    788: };
                    789: 
                    790: /*
                    791:  *     Routine:        exception_parse_reply
                    792:  *     Purpose:
                    793:  *             Parse and consume an exception reply message.
                    794:  *     Conditions:
                    795:  *             The destination port right has already been consumed.
                    796:  *             The message buffer and anything else in it is consumed.
                    797:  *     Returns:
                    798:  *             The reply return code.
                    799:  */
                    800: 
                    801: kern_return_t
                    802: exception_parse_reply(kmsg)
                    803:        ipc_kmsg_t kmsg;
                    804: {
                    805:        register mig_reply_header_t *msg =
                    806:                        (mig_reply_header_t *) &kmsg->ikm_header;
                    807:        kern_return_t kr;
                    808: 
                    809:        if ((msg->Head.msgh_bits !=
                    810:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0)) ||
                    811:            (msg->Head.msgh_size != sizeof *msg) ||
                    812:            (msg->Head.msgh_id != MACH_EXCEPTION_REPLY_ID) ||
                    813:            (* (int *) &msg->RetCodeType != * (int *) &exc_RetCode_proto)) {
                    814:                /*
                    815:                 *      Bozo user sent us a misformatted reply.
                    816:                 */
                    817: 
                    818:                kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    819:                ipc_kmsg_destroy(kmsg);
                    820:                return MIG_REPLY_MISMATCH;
                    821:        }
                    822: 
                    823:        kr = msg->RetCode;
                    824: 
                    825:        if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
                    826:            (ikm_cache() == IKM_NULL))
                    827:                ikm_cache() = kmsg;
                    828:        else
                    829:                ikm_free(kmsg);
                    830: 
                    831:        return kr;
                    832: }
                    833: 
                    834: /*
                    835:  *     Routine:        exception_raise_continue
                    836:  *     Purpose:
                    837:  *             Continue after blocking for an exception.
                    838:  *     Conditions:
                    839:  *             Nothing locked.  We are running on a new kernel stack,
                    840:  *             with the exception state saved in the thread.  From here
                    841:  *             control goes back to user space.
                    842:  *     Returns:
                    843:  *             Doesn't return.
                    844:  */
                    845: 
                    846: void
                    847: exception_raise_continue()
                    848: {
                    849:        ipc_thread_t self = current_thread();
                    850:        ipc_port_t reply_port = self->ith_port;
                    851:        ipc_mqueue_t reply_mqueue = &reply_port->ip_messages;
                    852:        ipc_kmsg_t kmsg;
                    853:        mach_port_seqno_t seqno;
                    854:        mach_msg_return_t mr;
                    855: 
                    856:        mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
                    857:                                MACH_MSG_SIZE_MAX,
                    858:                                MACH_MSG_TIMEOUT_NONE,
                    859:                                TRUE, exception_raise_continue,
                    860:                                &kmsg, &seqno);
                    861:        /* reply_mqueue is unlocked */
                    862: 
                    863:        exception_raise_continue_slow(mr, kmsg, seqno);
                    864:        /*NOTREACHED*/
                    865: }
                    866: 
                    867: /*
                    868:  *     Routine:        exception_raise_continue_slow
                    869:  *     Purpose:
                    870:  *             Continue after finishing an ipc_mqueue_receive
                    871:  *             for an exception reply message.
                    872:  *     Conditions:
                    873:  *             Nothing locked.  We hold a ref for reply_port.
                    874:  *     Returns:
                    875:  *             Doesn't return.
                    876:  */
                    877: 
                    878: void
                    879: exception_raise_continue_slow(mr, kmsg, seqno)
                    880:        mach_msg_return_t mr;
                    881:        ipc_kmsg_t kmsg;
                    882:        mach_port_seqno_t seqno;
                    883: {
                    884:        ipc_thread_t self = current_thread();
                    885:        ipc_port_t reply_port = self->ith_port;
                    886:        ipc_mqueue_t reply_mqueue = &reply_port->ip_messages;
                    887: 
                    888:        while (mr == MACH_RCV_INTERRUPTED) {
                    889:                /*
                    890:                 *      Somebody is trying to force this thread
                    891:                 *      to a clean point.  We must cooperate
                    892:                 *      and then resume the receive.
                    893:                 */
                    894: 
                    895:                while (thread_should_halt(self)) {
                    896:                        /* don't terminate while holding a reference */
                    897:                        if (self->ast & AST_TERMINATE)
                    898:                                ipc_port_release(reply_port);
                    899:                        thread_halt_self();
                    900:                }
                    901: 
                    902:                ip_lock(reply_port);
                    903:                if (!ip_active(reply_port)) {
                    904:                        ip_unlock(reply_port);
                    905:                        mr = MACH_RCV_PORT_DIED;
                    906:                        break;
                    907:                }
                    908: 
                    909:                imq_lock(reply_mqueue);
                    910:                ip_unlock(reply_port);
                    911: 
                    912:                mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE,
                    913:                                        MACH_MSG_SIZE_MAX,
                    914:                                        MACH_MSG_TIMEOUT_NONE,
                    915:                                        FALSE, exception_raise_continue,
                    916:                                        &kmsg, &seqno);
                    917:                /* reply_mqueue is unlocked */
                    918:        }
                    919:        ipc_port_release(reply_port);
                    920: 
                    921:        assert((mr == MACH_MSG_SUCCESS) ||
                    922:               (mr == MACH_RCV_PORT_DIED));
                    923: 
                    924:        if (mr == MACH_MSG_SUCCESS) {
                    925:                /*
                    926:                 *      Consume the reply message.
                    927:                 */
                    928: 
                    929:                ipc_port_release_sonce(reply_port);
                    930:                mr = exception_parse_reply(kmsg);
                    931:        }
                    932: 
                    933:        if ((mr == KERN_SUCCESS) ||
                    934:            (mr == MACH_RCV_PORT_DIED)) {
                    935:                thread_exception_return();
                    936:                /*NOTREACHED*/
                    937:                return;
                    938:        }
                    939: 
                    940:        if (self->ith_exc != KERN_SUCCESS) {
                    941:                exception_try_task(self->ith_exc,
                    942:                                   self->ith_exc_code,
                    943:                                   self->ith_exc_subcode);
                    944:                /*NOTREACHED*/
                    945:                return;
                    946:        }
                    947: 
                    948:        exception_no_server();
                    949:        /*NOTREACHED*/
                    950: }
                    951: 
                    952: /*
                    953:  *     Routine:        exception_raise_continue_fast
                    954:  *     Purpose:
                    955:  *             Special-purpose fast continuation for exceptions.
                    956:  *     Conditions:
                    957:  *             reply_port is locked and alive.
                    958:  *             kmsg is our reply message.
                    959:  *     Returns:
                    960:  *             Doesn't return.
                    961:  */
                    962: 
                    963: void
                    964: exception_raise_continue_fast(reply_port, kmsg)
                    965:        ipc_port_t reply_port;
                    966:        ipc_kmsg_t kmsg;
                    967: {
                    968:        ipc_thread_t self = current_thread();
                    969:        kern_return_t kr;
                    970: 
                    971:        assert(ip_active(reply_port));
                    972:        assert(reply_port == self->ith_port);
                    973:        assert(reply_port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port);
                    974:        assert(MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) ==
                    975:                                                MACH_MSG_TYPE_PORT_SEND_ONCE);
                    976: 
                    977:        /*
                    978:         *      Release the send-once right (from the message header)
                    979:         *      and the saved reference (from self->ith_port).
                    980:         */
                    981: 
                    982:        reply_port->ip_sorights--;
                    983:        ip_release(reply_port);
                    984:        ip_release(reply_port);
                    985:        ip_unlock(reply_port);
                    986: 
                    987:        /*
                    988:         *      Consume the reply message.
                    989:         */
                    990: 
                    991:        kr = exception_parse_reply(kmsg);
                    992:        if (kr == KERN_SUCCESS) {
                    993:                thread_exception_return();
                    994:                /*NOTREACHED*/
                    995:                return; /* help for the compiler */
                    996:        }
                    997: 
                    998:        if (self->ith_exc != KERN_SUCCESS) {
                    999:                exception_try_task(self->ith_exc,
                   1000:                                   self->ith_exc_code,
                   1001:                                   self->ith_exc_subcode);
                   1002:                /*NOTREACHED*/
                   1003:        }
                   1004: 
                   1005:        exception_no_server();
                   1006:        /*NOTREACHED*/
                   1007: }

unix.superglobalmegacorp.com

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