Annotation of XNU/osfmk/kern/ipc_tt.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: 
                     53: /*
                     54:  * File:       ipc_tt.c
                     55:  * Purpose:
                     56:  *     Task and thread related IPC functions.
                     57:  */
                     58: 
                     59: #include <mach/boolean.h>
                     60: #include <mach_rt.h>
                     61: #include <mach/kern_return.h>
                     62: #include <mach/mach_param.h>
                     63: #include <mach/task_special_ports.h>
                     64: #include <mach/thread_special_ports.h>
                     65: #include <mach/thread_status.h>
                     66: #include <mach/exception_types.h>
                     67: #include <mach/mach_traps.h>
                     68: #include <mach/task_server.h>
                     69: #include <mach/thread_act_server.h>
                     70: #include <mach/mach_host_server.h>
                     71: #include <mach/vm_task_server.h>
                     72: #include <kern/ipc_tt.h>
                     73: #include <kern/thread_act.h>
                     74: #include <kern/misc_protos.h>
                     75: #include <vm/vm_pageout.h>
                     76: 
                     77: /*
                     78:  *     Routine:        ipc_task_init
                     79:  *     Purpose:
                     80:  *             Initialize a task's IPC state.
                     81:  *
                     82:  *             If non-null, some state will be inherited from the parent.
                     83:  *             The parent must be appropriately initialized.
                     84:  *     Conditions:
                     85:  *             Nothing locked.
                     86:  */
                     87: 
                     88: void
                     89: ipc_task_init(
                     90:        task_t          task,
                     91:        task_t          parent)
                     92: {
                     93:        ipc_space_t space;
                     94:        ipc_port_t kport;
                     95:        kern_return_t kr;
                     96:        int i;
                     97: 
                     98: 
                     99:        kr = ipc_space_create(&ipc_table_entries[0], &space);
                    100:        if (kr != KERN_SUCCESS)
                    101:                panic("ipc_task_init");
                    102: 
                    103: 
                    104:        kport = ipc_port_alloc_kernel();
                    105:        if (kport == IP_NULL)
                    106:                panic("ipc_task_init");
                    107: 
                    108:        itk_lock_init(task);
                    109:        task->itk_self = kport;
                    110:        task->itk_sself = ipc_port_make_send(kport);
                    111:        task->itk_space = space;
                    112:        space->is_fast = task->kernel_loaded;
                    113: 
                    114:        if (parent == TASK_NULL) {
                    115:                for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                    116:                        task->exc_actions[i].port = IP_NULL;
                    117:                }/* for */
                    118:                task->exc_actions[EXC_MACH_SYSCALL].port = 
                    119:                        ipc_port_make_send(realhost.host_self);
                    120:                task->itk_bootstrap = IP_NULL;
                    121:                for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
                    122:                        task->itk_registered[i] = IP_NULL;
                    123:        } else {
                    124:                itk_lock(parent);
                    125:                assert(parent->itk_self != IP_NULL);
                    126: 
                    127:                /* inherit registered ports */
                    128: 
                    129:                for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
                    130:                        task->itk_registered[i] =
                    131:                                ipc_port_copy_send(parent->itk_registered[i]);
                    132: 
                    133:                /* inherit exception and bootstrap ports */
                    134: 
                    135:                for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                    136:                    task->exc_actions[i].port =
                    137:                                ipc_port_copy_send(parent->exc_actions[i].port);
                    138:                    task->exc_actions[i].flavor =
                    139:                                parent->exc_actions[i].flavor;
                    140:                    task->exc_actions[i].behavior = 
                    141:                                parent->exc_actions[i].behavior;
                    142:                }/* for */
                    143:                task->itk_bootstrap =
                    144:                        ipc_port_copy_send(parent->itk_bootstrap);
                    145: 
                    146:                itk_unlock(parent);
                    147:        }
                    148: }
                    149: 
                    150: /*
                    151:  *     Routine:        ipc_task_enable
                    152:  *     Purpose:
                    153:  *             Enable a task for IPC access.
                    154:  *     Conditions:
                    155:  *             Nothing locked.
                    156:  */
                    157: 
                    158: void
                    159: ipc_task_enable(
                    160:        task_t          task)
                    161: {
                    162:        ipc_port_t kport;
                    163: 
                    164:        itk_lock(task);
                    165:        kport = task->itk_self;
                    166:        if (kport != IP_NULL)
                    167:                ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
                    168:        itk_unlock(task);
                    169: }
                    170: 
                    171: /*
                    172:  *     Routine:        ipc_task_disable
                    173:  *     Purpose:
                    174:  *             Disable IPC access to a task.
                    175:  *     Conditions:
                    176:  *             Nothing locked.
                    177:  */
                    178: 
                    179: void
                    180: ipc_task_disable(
                    181:        task_t          task)
                    182: {
                    183:        ipc_port_t kport;
                    184: 
                    185:        itk_lock(task);
                    186:        kport = task->itk_self;
                    187:        if (kport != IP_NULL)
                    188:                ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
                    189:        itk_unlock(task);
                    190: }
                    191: 
                    192: /*
                    193:  *     Routine:        ipc_task_terminate
                    194:  *     Purpose:
                    195:  *             Clean up and destroy a task's IPC state.
                    196:  *     Conditions:
                    197:  *             Nothing locked.  The task must be suspended.
                    198:  *             (Or the current thread must be in the task.)
                    199:  */
                    200: 
                    201: void
                    202: ipc_task_terminate(
                    203:        task_t          task)
                    204: {
                    205:        ipc_port_t kport;
                    206:        int i;
                    207: 
                    208:        itk_lock(task);
                    209:        kport = task->itk_self;
                    210: 
                    211:        if (kport == IP_NULL) {
                    212:                /* the task is already terminated (can this happen?) */
                    213:                itk_unlock(task);
                    214:                return;
                    215:        }
                    216: 
                    217:        task->itk_self = IP_NULL;
                    218:        itk_unlock(task);
                    219: 
                    220:        /* release the naked send rights */
                    221: 
                    222:        if (IP_VALID(task->itk_sself))
                    223:                ipc_port_release_send(task->itk_sself);
                    224: 
                    225:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                    226:                if (IP_VALID(task->exc_actions[i].port)) {
                    227:                        ipc_port_release_send(task->exc_actions[i].port);
                    228:                }
                    229:        }/* for */
                    230:        if (IP_VALID(task->itk_bootstrap))
                    231:                ipc_port_release_send(task->itk_bootstrap);
                    232: 
                    233:        for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
                    234:                if (IP_VALID(task->itk_registered[i]))
                    235:                        ipc_port_release_send(task->itk_registered[i]);
                    236: 
                    237:        /* destroy the space, leaving just a reference for it */
                    238: 
                    239:        if (!task->kernel_loaded)
                    240:                ipc_space_destroy(task->itk_space);
                    241: 
                    242:        /* destroy the kernel port */
                    243: 
                    244:        ipc_port_dealloc_kernel(kport);
                    245: }
                    246: 
                    247: /*
                    248:  *     Routine:        ipc_thread_init
                    249:  *     Purpose:
                    250:  *             Initialize a thread's IPC state.
                    251:  *     Conditions:
                    252:  *             Nothing locked.
                    253:  */
                    254: 
                    255: void
                    256: ipc_thread_init(
                    257:        thread_t        thread)
                    258: {
                    259:        ipc_kmsg_queue_init(&thread->ith_messages);
                    260:        thread->ith_mig_reply = MACH_PORT_NULL;
                    261:        thread->ith_rpc_reply = IP_NULL;
                    262: }
                    263: 
                    264: /*
                    265:  *     Routine:        ipc_thread_terminate
                    266:  *     Purpose:
                    267:  *             Clean up and destroy a thread's IPC state.
                    268:  *     Conditions:
                    269:  *             Nothing locked.  The thread must be suspended.
                    270:  *             (Or be the current thread.)
                    271:  */
                    272: 
                    273: void
                    274: ipc_thread_terminate(
                    275:        thread_t        thread)
                    276: {
                    277:        assert(ipc_kmsg_queue_empty(&thread->ith_messages));
                    278: 
                    279:         if (thread->ith_rpc_reply != IP_NULL)
                    280:             ipc_port_dealloc_reply(thread->ith_rpc_reply);
                    281:        thread->ith_rpc_reply = IP_NULL;
                    282: }
                    283: 
                    284: /*
                    285:  *     Routine:        ipc_thr_act_init
                    286:  *     Purpose:
                    287:  *             Initialize an thr_act's IPC state.
                    288:  *     Conditions:
                    289:  *             Nothing locked.
                    290:  */
                    291: 
                    292: void
                    293: ipc_thr_act_init(task_t task, thread_act_t thr_act)
                    294: {
                    295:        ipc_port_t kport; int i;
                    296: 
                    297:        kport = ipc_port_alloc_kernel();
                    298:        if (kport == IP_NULL)
                    299:                panic("ipc_thr_act_init");
                    300: 
                    301:        thr_act->ith_self = kport;
                    302:        thr_act->ith_sself = ipc_port_make_send(kport);
                    303: 
                    304:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
                    305:                thr_act->exc_actions[i].port = IP_NULL;
                    306: 
                    307:        thr_act->exc_actions[EXC_MACH_SYSCALL].port =
                    308:                                        ipc_port_make_send(realhost.host_self);
                    309: 
                    310:        ipc_kobject_set(kport, (ipc_kobject_t) thr_act, IKOT_ACT);
                    311: }
                    312: 
                    313: void
                    314: ipc_thr_act_disable(thread_act_t thr_act)
                    315: {
                    316:        int i;
                    317:        ipc_port_t kport;
                    318: 
                    319:        act_lock(thr_act);
                    320:        kport = thr_act->ith_self;
                    321: 
                    322:        if (kport != IP_NULL)
                    323:                ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
                    324:        act_unlock(thr_act);
                    325: }
                    326: 
                    327: void
                    328: ipc_thr_act_disable_act_locked(thread_act_t thr_act)
                    329: {
                    330:        int i;
                    331:        ipc_port_t kport;
                    332: 
                    333:        kport = thr_act->ith_self;
                    334: 
                    335:        if (kport != IP_NULL)
                    336:                ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
                    337: }
                    338: 
                    339: void
                    340: ipc_thr_act_terminate(thread_act_t thr_act)
                    341: {
                    342:        ipc_port_t kport; int i;
                    343: 
                    344:        act_lock(thr_act);
                    345:        kport = thr_act->ith_self;
                    346: 
                    347:        if (kport == IP_NULL) {
                    348:                /* the thread is already terminated (can this happen?) */
                    349:                act_unlock(thr_act);
                    350:                return;
                    351:        }
                    352: 
                    353:        thr_act->ith_self = IP_NULL;
                    354:        act_unlock(thr_act);
                    355: 
                    356:        /* release the naked send rights */
                    357: 
                    358:        if (IP_VALID(thr_act->ith_sself))
                    359:                ipc_port_release_send(thr_act->ith_sself);
                    360:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                    361:            if (IP_VALID(thr_act->exc_actions[i].port))
                    362:                ipc_port_release_send(thr_act->exc_actions[i].port);
                    363:         }
                    364: 
                    365:        /* destroy the kernel port */
                    366:        ipc_port_dealloc_kernel(kport);
                    367: }
                    368: 
                    369: /*
                    370:  *     Routine:        retrieve_task_self_fast
                    371:  *     Purpose:
                    372:  *             Optimized version of retrieve_task_self,
                    373:  *             that only works for the current task.
                    374:  *
                    375:  *             Return a send right (possibly null/dead)
                    376:  *             for the task's user-visible self port.
                    377:  *     Conditions:
                    378:  *             Nothing locked.
                    379:  */
                    380: 
                    381: ipc_port_t
                    382: retrieve_task_self_fast(
                    383:        register task_t         task)
                    384: {
                    385:        register ipc_port_t port;
                    386: 
                    387:        assert(task == current_task());
                    388: 
                    389:        itk_lock(task);
                    390:        assert(task->itk_self != IP_NULL);
                    391: 
                    392:        if ((port = task->itk_sself) == task->itk_self) {
                    393:                /* no interposing */
                    394: 
                    395:                ip_lock(port);
                    396:                assert(ip_active(port));
                    397:                ip_reference(port);
                    398:                port->ip_srights++;
                    399:                ip_unlock(port);
                    400:        } else
                    401:                port = ipc_port_copy_send(port);
                    402:        itk_unlock(task);
                    403: 
                    404:        return port;
                    405: }
                    406: 
                    407: /*
                    408:  *     Routine:        retrieve_act_self_fast
                    409:  *     Purpose:
                    410:  *             Optimized version of retrieve_thread_self,
                    411:  *             that only works for the current thread.
                    412:  *
                    413:  *             Return a send right (possibly null/dead)
                    414:  *             for the thread's user-visible self port.
                    415:  *     Conditions:
                    416:  *             Nothing locked.
                    417:  */
                    418: 
                    419: ipc_port_t
                    420: retrieve_act_self_fast(thread_act_t thr_act)
                    421: {
                    422:        register ipc_port_t port;
                    423: 
                    424:        assert(thr_act == current_act());
                    425:        act_lock(thr_act);
                    426:        assert(thr_act->ith_self != IP_NULL);
                    427: 
                    428:        if ((port = thr_act->ith_sself) == thr_act->ith_self) {
                    429:                /* no interposing */
                    430: 
                    431:                ip_lock(port);
                    432:                assert(ip_active(port));
                    433:                ip_reference(port);
                    434:                port->ip_srights++;
                    435:                ip_unlock(port);
                    436:        } else
                    437:                port = ipc_port_copy_send(port);
                    438:        act_unlock(thr_act);
                    439: 
                    440:        return port;
                    441: }
                    442: 
                    443: /*
                    444:  *     Routine:        mach_task_self [mach trap]
                    445:  *     Purpose:
                    446:  *             Give the caller send rights for his own task port.
                    447:  *     Conditions:
                    448:  *             Nothing locked.
                    449:  *     Returns:
                    450:  *             MACH_PORT_NULL if there are any resource failures
                    451:  *             or other errors.
                    452:  */
                    453: 
                    454: mach_port_name_t
                    455: mach_task_self(void)
                    456: {
                    457:        task_t task = current_task();
                    458:        ipc_port_t sright;
                    459: 
                    460:        sright = retrieve_task_self_fast(task);
                    461:        return ipc_port_copyout_send(sright, task->itk_space);
                    462: }
                    463: 
                    464: /*
                    465:  *     Routine:        mach_thread_self [mach trap]
                    466:  *     Purpose:
                    467:  *             Give the caller send rights for his own thread port.
                    468:  *     Conditions:
                    469:  *             Nothing locked.
                    470:  *     Returns:
                    471:  *             MACH_PORT_NULL if there are any resource failures
                    472:  *             or other errors.
                    473:  */
                    474: 
                    475: mach_port_name_t
                    476: mach_thread_self(void)
                    477: {
                    478:        thread_act_t  thr_act  = current_act();
                    479:        task_t task = thr_act->task;
                    480:        ipc_port_t sright;
                    481: 
                    482:        sright = retrieve_act_self_fast(thr_act);
                    483:        return ipc_port_copyout_send(sright, task->itk_space);
                    484: }
                    485: 
                    486: /*
                    487:  *     Routine:        mach_reply_port [mach trap]
                    488:  *     Purpose:
                    489:  *             Allocate a port for the caller.
                    490:  *     Conditions:
                    491:  *             Nothing locked.
                    492:  *     Returns:
                    493:  *             MACH_PORT_NULL if there are any resource failures
                    494:  *             or other errors.
                    495:  */
                    496: 
                    497: mach_port_name_t
                    498: mach_reply_port(void)
                    499: {
                    500:        ipc_port_t port;
                    501:        mach_port_name_t name;
                    502:        kern_return_t kr;
                    503: 
                    504:        kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
                    505:        if (kr == KERN_SUCCESS)
                    506:                ip_unlock(port);
                    507:        else
                    508:                name = MACH_PORT_NULL;
                    509: 
                    510:        return name;
                    511: }
                    512: 
                    513: /*
                    514:  *     Routine:        task_get_special_port [kernel call]
                    515:  *     Purpose:
                    516:  *             Clones a send right for one of the task's
                    517:  *             special ports.
                    518:  *     Conditions:
                    519:  *             Nothing locked.
                    520:  *     Returns:
                    521:  *             KERN_SUCCESS            Extracted a send right.
                    522:  *             KERN_INVALID_ARGUMENT   The task is null.
                    523:  *             KERN_FAILURE            The task/space is dead.
                    524:  *             KERN_INVALID_ARGUMENT   Invalid special port.
                    525:  */
                    526: 
                    527: kern_return_t
                    528: task_get_special_port(
                    529:        task_t          task,
                    530:        int             which,
                    531:        ipc_port_t      *portp)
                    532: {
                    533:        ipc_port_t *whichp;
                    534:        ipc_port_t port;
                    535: 
                    536:        if (task == TASK_NULL)
                    537:                return KERN_INVALID_ARGUMENT;
                    538: 
                    539:        switch (which) {
                    540:            case TASK_KERNEL_PORT:
                    541:                whichp = &task->itk_sself;
                    542:                break;
                    543: 
                    544:            case TASK_BOOTSTRAP_PORT:
                    545:                whichp = &task->itk_bootstrap;
                    546:                break;
                    547: 
                    548:             case TASK_WIRED_LEDGER_PORT:
                    549:                 whichp = &task->wired_ledger_port;
                    550:                 break;
                    551: 
                    552:             case TASK_PAGED_LEDGER_PORT:
                    553:                 whichp = &task->paged_ledger_port;
                    554:                 break;
                    555:                     
                    556:            default:
                    557:                return KERN_INVALID_ARGUMENT;
                    558:        }
                    559: 
                    560:        itk_lock(task);
                    561:        if (task->itk_self == IP_NULL) {
                    562:                itk_unlock(task);
                    563:                return KERN_FAILURE;
                    564:        }
                    565: 
                    566:        port = ipc_port_copy_send(*whichp);
                    567:        itk_unlock(task);
                    568: 
                    569:        *portp = port;
                    570:        return KERN_SUCCESS;
                    571: }
                    572: 
                    573: /*
                    574:  *     Routine:        task_set_special_port [kernel call]
                    575:  *     Purpose:
                    576:  *             Changes one of the task's special ports,
                    577:  *             setting it to the supplied send right.
                    578:  *     Conditions:
                    579:  *             Nothing locked.  If successful, consumes
                    580:  *             the supplied send right.
                    581:  *     Returns:
                    582:  *             KERN_SUCCESS            Changed the special port.
                    583:  *             KERN_INVALID_ARGUMENT   The task is null.
                    584:  *             KERN_FAILURE            The task/space is dead.
                    585:  *             KERN_INVALID_ARGUMENT   Invalid special port.
                    586:  */
                    587: 
                    588: kern_return_t
                    589: task_set_special_port(
                    590:        task_t          task,
                    591:        int             which,
                    592:        ipc_port_t      port)
                    593: {
                    594:        ipc_port_t *whichp;
                    595:        ipc_port_t old;
                    596: 
                    597:        if (task == TASK_NULL)
                    598:                return KERN_INVALID_ARGUMENT;
                    599: 
                    600:        switch (which) {
                    601:            case TASK_KERNEL_PORT:
                    602:                whichp = &task->itk_sself;
                    603:                break;
                    604: 
                    605:            case TASK_BOOTSTRAP_PORT:
                    606:                whichp = &task->itk_bootstrap;
                    607:                break;
                    608: 
                    609:             case TASK_WIRED_LEDGER_PORT:
                    610:                 whichp = &task->wired_ledger_port;
                    611:                 break;
                    612: 
                    613:             case TASK_PAGED_LEDGER_PORT:
                    614:                 whichp = &task->paged_ledger_port;
                    615:                 break;
                    616:                     
                    617:            default:
                    618:                return KERN_INVALID_ARGUMENT;
                    619:        }/* switch */
                    620: 
                    621:        itk_lock(task);
                    622:        if (task->itk_self == IP_NULL) {
                    623:                itk_unlock(task);
                    624:                return KERN_FAILURE;
                    625:        }
                    626: 
                    627:        old = *whichp;
                    628:        *whichp = port;
                    629:        itk_unlock(task);
                    630: 
                    631:        if (IP_VALID(old))
                    632:                ipc_port_release_send(old);
                    633:        return KERN_SUCCESS;
                    634: }
                    635: 
                    636: 
                    637: /*
                    638:  *     Routine:        mach_ports_register [kernel call]
                    639:  *     Purpose:
                    640:  *             Stash a handful of port send rights in the task.
                    641:  *             Child tasks will inherit these rights, but they
                    642:  *             must use mach_ports_lookup to acquire them.
                    643:  *
                    644:  *             The rights are supplied in a (wired) kalloc'd segment.
                    645:  *             Rights which aren't supplied are assumed to be null.
                    646:  *     Conditions:
                    647:  *             Nothing locked.  If successful, consumes
                    648:  *             the supplied rights and memory.
                    649:  *     Returns:
                    650:  *             KERN_SUCCESS            Stashed the port rights.
                    651:  *             KERN_INVALID_ARGUMENT   The task is null.
                    652:  *             KERN_INVALID_ARGUMENT   The task is dead.
                    653:  *             KERN_INVALID_ARGUMENT   Too many port rights supplied.
                    654:  */
                    655: 
                    656: kern_return_t
                    657: mach_ports_register(
                    658:        task_t                  task,
                    659:        mach_port_array_t       memory,
                    660:        mach_msg_type_number_t  portsCnt)
                    661: {
                    662:        ipc_port_t ports[TASK_PORT_REGISTER_MAX];
                    663:        int i;
                    664: 
                    665:        if ((task == TASK_NULL) ||
                    666:            (portsCnt > TASK_PORT_REGISTER_MAX))
                    667:                return KERN_INVALID_ARGUMENT;
                    668: 
                    669:        /*
                    670:         *      Pad the port rights with nulls.
                    671:         */
                    672: 
                    673:        for (i = 0; i < portsCnt; i++)
                    674:                ports[i] = memory[i];
                    675:        for (; i < TASK_PORT_REGISTER_MAX; i++)
                    676:                ports[i] = IP_NULL;
                    677: 
                    678:        itk_lock(task);
                    679:        if (task->itk_self == IP_NULL) {
                    680:                itk_unlock(task);
                    681:                return KERN_INVALID_ARGUMENT;
                    682:        }
                    683: 
                    684:        /*
                    685:         *      Replace the old send rights with the new.
                    686:         *      Release the old rights after unlocking.
                    687:         */
                    688: 
                    689:        for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
                    690:                ipc_port_t old;
                    691: 
                    692:                old = task->itk_registered[i];
                    693:                task->itk_registered[i] = ports[i];
                    694:                ports[i] = old;
                    695:        }
                    696: 
                    697:        itk_unlock(task);
                    698: 
                    699:        for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
                    700:                if (IP_VALID(ports[i]))
                    701:                        ipc_port_release_send(ports[i]);
                    702: 
                    703:        /*
                    704:         *      Now that the operation is known to be successful,
                    705:         *      we can free the memory.
                    706:         */
                    707: 
                    708:        if (portsCnt != 0)
                    709:                kfree((vm_offset_t) memory,
                    710:                      (vm_size_t) (portsCnt * sizeof(mach_port_t)));
                    711: 
                    712:        return KERN_SUCCESS;
                    713: }
                    714: 
                    715: /*
                    716:  *     Routine:        mach_ports_lookup [kernel call]
                    717:  *     Purpose:
                    718:  *             Retrieves (clones) the stashed port send rights.
                    719:  *     Conditions:
                    720:  *             Nothing locked.  If successful, the caller gets
                    721:  *             rights and memory.
                    722:  *     Returns:
                    723:  *             KERN_SUCCESS            Retrieved the send rights.
                    724:  *             KERN_INVALID_ARGUMENT   The task is null.
                    725:  *             KERN_INVALID_ARGUMENT   The task is dead.
                    726:  *             KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
                    727:  */
                    728: 
                    729: kern_return_t
                    730: mach_ports_lookup(
                    731:        task_t                  task,
                    732:        mach_port_array_t       *portsp,
                    733:        mach_msg_type_number_t  *portsCnt)
                    734: {
                    735:        vm_offset_t memory;
                    736:        vm_size_t size;
                    737:        ipc_port_t *ports;
                    738:        int i;
                    739: 
                    740:        kern_return_t kr;
                    741:        boolean_t rt = FALSE; /* ### This boolean is FALSE, because there
                    742:                               * currently exists no mechanism to determine
                    743:                               * whether or not the reply port is an RT port
                    744:                               */
                    745:        
                    746:        if (task == TASK_NULL)
                    747:                return KERN_INVALID_ARGUMENT;
                    748: 
                    749:        size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
                    750: 
                    751:        memory = KALLOC(size, rt);
                    752:        if (memory == 0)
                    753:                return KERN_RESOURCE_SHORTAGE;
                    754: 
                    755:        itk_lock(task);
                    756:        if (task->itk_self == IP_NULL) {
                    757:                itk_unlock(task);
                    758: 
                    759:                KFREE(memory, size, rt);
                    760:                return KERN_INVALID_ARGUMENT;
                    761:        }
                    762: 
                    763:        ports = (ipc_port_t *) memory;
                    764: 
                    765:        /*
                    766:         *      Clone port rights.  Because kalloc'd memory
                    767:         *      is wired, we won't fault while holding the task lock.
                    768:         */
                    769: 
                    770:        for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
                    771:                ports[i] = ipc_port_copy_send(task->itk_registered[i]);
                    772: 
                    773:        itk_unlock(task);
                    774: 
                    775:        *portsp = (mach_port_array_t) ports;
                    776:        *portsCnt = TASK_PORT_REGISTER_MAX;
                    777:        return KERN_SUCCESS;
                    778: }
                    779: 
                    780: /*
                    781:  *     Routine: convert_port_to_locked_task
                    782:  *     Purpose:
                    783:  *             Internal helper routine to convert from a port to a locked
                    784:  *             task.  Used by several routines that try to convert from a
                    785:  *             task port to a reference on some task related object.
                    786:  *     Conditions:
                    787:  *             Nothing locked, blocking OK.
                    788:  */
                    789: task_t
                    790: convert_port_to_locked_task(ipc_port_t port)
                    791: {
                    792:        while (IP_VALID(port)) {
                    793:                task_t task;
                    794: 
                    795:                ip_lock(port);
                    796:                if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) {
                    797:                        ip_unlock(port);
                    798:                        return TASK_NULL;
                    799:                }
                    800:                task = (task_t) port->ip_kobject;
                    801:                assert(task != TASK_NULL);
                    802: 
                    803:                /*
                    804:                 * Normal lock ordering puts task_lock() before ip_lock().
                    805:                 * Attempt out-of-order locking here.
                    806:                 */
                    807:                if (task_lock_try(task)) {
                    808:                        ip_unlock(port);
                    809:                        return(task);
                    810:                }
                    811: 
                    812:                ip_unlock(port);
                    813:                mutex_pause();
                    814:        }
                    815:        return TASK_NULL;
                    816: }
                    817: 
                    818: /*
                    819:  *     Routine:        convert_port_to_task
                    820:  *     Purpose:
                    821:  *             Convert from a port to a task.
                    822:  *             Doesn't consume the port ref; produces a task ref,
                    823:  *             which may be null.
                    824:  *     Conditions:
                    825:  *             Nothing locked.
                    826:  */
                    827: task_t
                    828: convert_port_to_task(
                    829:        ipc_port_t      port)
                    830: {
                    831:        task_t task;
                    832: 
                    833:        task = convert_port_to_locked_task(port);
                    834:        if (task) {
                    835:                task->ref_count++;
                    836:                task_unlock(task);
                    837:        }
                    838:        return task;
                    839: }
                    840: 
                    841: /*
                    842:  *     Routine:        convert_port_to_space
                    843:  *     Purpose:
                    844:  *             Convert from a port to a space.
                    845:  *             Doesn't consume the port ref; produces a space ref,
                    846:  *             which may be null.
                    847:  *     Conditions:
                    848:  *             Nothing locked.
                    849:  */
                    850: ipc_space_t
                    851: convert_port_to_space(
                    852:        ipc_port_t      port)
                    853: {
                    854:        ipc_space_t space;
                    855:        task_t task;
                    856: 
                    857:        task = convert_port_to_locked_task(port);
                    858: 
                    859:        if (task == TASK_NULL)
                    860:                return IPC_SPACE_NULL;
                    861: 
                    862:        if (!task->active) {
                    863:                task_unlock(task);
                    864:                return IPC_SPACE_NULL;
                    865:        }
                    866:                
                    867:        space = task->itk_space;
                    868:        is_reference(space);
                    869:        task_unlock(task);
                    870:        return (space);
                    871: }
                    872: 
                    873: upl_t
                    874: convert_port_to_upl(
                    875:        ipc_port_t      port)
                    876: {
                    877:        upl_t upl;
                    878: 
                    879:        ip_lock(port);
                    880:        if (!ip_active(port) || (ip_kotype(port) != IKOT_UPL)) {
                    881:                        ip_unlock(port);
                    882:                        return (upl_t)NULL;
                    883:        }
                    884:        upl = (upl_t) port->ip_kobject;
                    885:        ip_unlock(port);
                    886:        upl_lock(upl);
                    887:        upl->ref_count+=1;
                    888:        upl_unlock(upl);
                    889:        return upl;
                    890: }
                    891: 
                    892: /*
                    893:  *     Routine:        convert_port_entry_to_map
                    894:  *     Purpose:
                    895:  *             Convert from a port specifying an entry or a task
                    896:  *             to a map. Doesn't consume the port ref; produces a map ref,
                    897:  *             which may be null.  Unlike convert_port_to_map, the
                    898:  *             port may be task or a named entry backed.
                    899:  *     Conditions:
                    900:  *             Nothing locked.
                    901:  */
                    902: 
                    903: 
                    904: vm_map_t
                    905: convert_port_entry_to_map(
                    906:        ipc_port_t      port)
                    907: {
                    908:        task_t task;
                    909:        vm_map_t map;
                    910:        vm_named_entry_t        named_entry;
                    911: 
                    912:        if(IP_VALID(port) && (ip_kotype(port) == IKOT_NAMED_ENTRY)) {
                    913:                while(TRUE) {
                    914:                        ip_lock(port);
                    915:                        if(ip_active(port) && (ip_kotype(port) 
                    916:                                                == IKOT_NAMED_ENTRY)) {
                    917:                                named_entry =
                    918:                                         (vm_named_entry_t)port->ip_kobject;
                    919:                                if (!(mutex_try(&(named_entry)->Lock))) {
                    920:                                                ip_unlock(port);
                    921:                                                mutex_pause();
                    922:                                                continue;
                    923:                                }
                    924:                                named_entry->ref_count++;
                    925:                                mutex_unlock(&(named_entry)->Lock);
                    926:                                ip_unlock(port);
                    927:                                if ((named_entry->is_sub_map) &&
                    928:                                        (named_entry->protection 
                    929:                                        & VM_PROT_WRITE)) {
                    930:                                        map = named_entry->backing.map;
                    931:                                } else {
                    932:                                        mach_destroy_memory_entry(port);
                    933:                                        return VM_MAP_NULL;
                    934:                                }
                    935:                                vm_map_reference_swap(map);
                    936:                                mach_destroy_memory_entry(port);
                    937:                                break;
                    938:                        }
                    939:                        else 
                    940:                                return VM_MAP_NULL;
                    941:                }
                    942:        } else {
                    943:                task_t task;
                    944: 
                    945:                task = convert_port_to_locked_task(port);
                    946:                
                    947:                if (task == TASK_NULL)
                    948:                        return VM_MAP_NULL;
                    949: 
                    950:                if (!task->active) {
                    951:                        task_unlock(task);
                    952:                        return VM_MAP_NULL;
                    953:                }
                    954:                
                    955:                map = task->map;
                    956:                vm_map_reference_swap(map);
                    957:                task_unlock(task);
                    958:        }
                    959: 
                    960:        return map;
                    961: }
                    962: 
                    963: /*
                    964:  *     Routine:        convert_port_entry_to_object
                    965:  *     Purpose:
                    966:  *             Convert from a port specifying a named entry to an
                    967:  *             object. Doesn't consume the port ref; produces a map ref,
                    968:  *             which may be null. 
                    969:  *     Conditions:
                    970:  *             Nothing locked.
                    971:  */
                    972: 
                    973: 
                    974: vm_object_t
                    975: convert_port_entry_to_object(
                    976:        ipc_port_t      port)
                    977: {
                    978:        vm_object_t object;
                    979:        vm_named_entry_t        named_entry;
                    980: 
                    981:        if(IP_VALID(port) && (ip_kotype(port) == IKOT_NAMED_ENTRY)) {
                    982:                while(TRUE) {
                    983:                        ip_lock(port);
                    984:                        if(ip_active(port) && (ip_kotype(port) 
                    985:                                                == IKOT_NAMED_ENTRY)) {
                    986:                                named_entry =
                    987:                                         (vm_named_entry_t)port->ip_kobject;
                    988:                                if (!(mutex_try(&(named_entry)->Lock))) {
                    989:                                                ip_unlock(port);
                    990:                                                mutex_pause();
                    991:                                                continue;
                    992:                                }
                    993:                                named_entry->ref_count++;
                    994:                                mutex_unlock(&(named_entry)->Lock);
                    995:                                ip_unlock(port);
                    996:                                if ((!named_entry->is_sub_map) &&
                    997:                                        (named_entry->protection 
                    998:                                        & VM_PROT_WRITE)) {
                    999:                                        object = named_entry->object;
                   1000:                                } else {
                   1001:                                        mach_destroy_memory_entry(port);
                   1002:                                        return (vm_object_t)NULL;
                   1003:                                }
                   1004:                                vm_object_reference(named_entry->object);
                   1005:                                mach_destroy_memory_entry(port);
                   1006:                                break;
                   1007:                        }
                   1008:                        else 
                   1009:                                return (vm_object_t)NULL;
                   1010:                }
                   1011:        } else {
                   1012:                return (vm_object_t)NULL;
                   1013:        }
                   1014: 
                   1015:        return object;
                   1016: }
                   1017: 
                   1018: /*
                   1019:  *     Routine:        convert_port_to_map
                   1020:  *     Purpose:
                   1021:  *             Convert from a port to a map.
                   1022:  *             Doesn't consume the port ref; produces a map ref,
                   1023:  *             which may be null.
                   1024:  *     Conditions:
                   1025:  *             Nothing locked.
                   1026:  */
                   1027: 
                   1028: vm_map_t
                   1029: convert_port_to_map(
                   1030:        ipc_port_t      port)
                   1031: {
                   1032:        task_t task;
                   1033:        vm_map_t map;
                   1034: 
                   1035:        task = convert_port_to_locked_task(port);
                   1036:                
                   1037:        if (task == TASK_NULL)
                   1038:                return VM_MAP_NULL;
                   1039: 
                   1040:        if (!task->active) {
                   1041:                task_unlock(task);
                   1042:                return VM_MAP_NULL;
                   1043:        }
                   1044:                
                   1045:        map = task->map;
                   1046:        vm_map_reference_swap(map);
                   1047:        task_unlock(task);
                   1048:        return map;
                   1049: }
                   1050: 
                   1051: 
                   1052: /*
                   1053:  *     Routine:        convert_port_to_act
                   1054:  *     Purpose:
                   1055:  *             Convert from a port to a thr_act.
                   1056:  *             Doesn't consume the port ref; produces an thr_act ref,
                   1057:  *             which may be null.
                   1058:  *     Conditions:
                   1059:  *             Nothing locked.
                   1060:  */
                   1061: 
                   1062: thread_act_t
                   1063: convert_port_to_act( ipc_port_t port )
                   1064: {
                   1065:        boolean_t r;
                   1066:        thread_act_t thr_act = 0;
                   1067: 
                   1068:        r = FALSE;
                   1069:        while (!r && IP_VALID(port)) {
                   1070:                ip_lock(port);
                   1071:                r = ref_act_port_locked(port, &thr_act);
                   1072:                /* port unlocked */
                   1073:        }
                   1074:        return (thr_act);
                   1075: }
                   1076: 
                   1077: boolean_t
                   1078: ref_act_port_locked( ipc_port_t port, thread_act_t *pthr_act )
                   1079: {
                   1080:        thread_act_t thr_act;
                   1081: 
                   1082:        thr_act = 0;
                   1083:        if (ip_active(port) &&
                   1084:                (ip_kotype(port) == IKOT_ACT)) {
                   1085:                thr_act = (thread_act_t) port->ip_kobject;
                   1086:                assert(thr_act != THR_ACT_NULL);
                   1087: 
                   1088:                /*
                   1089:                 * Normal lock ordering is act_lock(), then ip_lock().
                   1090:                 * Allow out-of-order locking here, using
                   1091:                 * act_reference_act_locked() to accomodate it.
                   1092:                 */
                   1093:                if (!act_lock_try(thr_act)) {
                   1094:                        ip_unlock(port);
                   1095:                        mutex_pause();
                   1096:                        return (FALSE);
                   1097:                }
                   1098:                act_locked_act_reference(thr_act);
                   1099:                act_unlock(thr_act);
                   1100:        }
                   1101:        *pthr_act = thr_act;
                   1102:        ip_unlock(port);
                   1103:        return (TRUE);
                   1104: }
                   1105: 
                   1106: /*
                   1107:  *     Routine:        convert_task_to_port
                   1108:  *     Purpose:
                   1109:  *             Convert from a task to a port.
                   1110:  *             Consumes a task ref; produces a naked send right
                   1111:  *             which may be invalid.  
                   1112:  *     Conditions:
                   1113:  *             Nothing locked.
                   1114:  */
                   1115: 
                   1116: ipc_port_t
                   1117: convert_task_to_port(
                   1118:        task_t          task)
                   1119: {
                   1120:        ipc_port_t port;
                   1121: 
                   1122:        itk_lock(task);
                   1123:        if (task->itk_self != IP_NULL)
                   1124: #if    NORMA_TASK
                   1125:                if (task->map == VM_MAP_NULL)
                   1126:                        /* norma placeholder task */
                   1127:                        port = ipc_port_copy_send(task->itk_self);
                   1128:                else
                   1129: #endif /* NORMA_TASK */
                   1130:                port = ipc_port_make_send(task->itk_self);
                   1131:        else
                   1132:                port = IP_NULL;
                   1133:        itk_unlock(task);
                   1134: 
                   1135:        task_deallocate(task);
                   1136:        return port;
                   1137: }
                   1138: 
                   1139: /*
                   1140:  *     Routine:        convert_act_to_port
                   1141:  *     Purpose:
                   1142:  *             Convert from a thr_act to a port.
                   1143:  *             Consumes an thr_act ref; produces a naked send right
                   1144:  *             which may be invalid.
                   1145:  *     Conditions:
                   1146:  *             Nothing locked.
                   1147:  */
                   1148: 
                   1149: ipc_port_t
                   1150: convert_act_to_port(thr_act)
                   1151:        thread_act_t thr_act;
                   1152: {
                   1153:        ipc_port_t port;
                   1154: 
                   1155:        act_lock(thr_act);
                   1156:        if (thr_act->ith_self != IP_NULL)
                   1157:                port = ipc_port_make_send(thr_act->ith_self);
                   1158:        else
                   1159:                port = IP_NULL;
                   1160:        act_unlock(thr_act);
                   1161: 
                   1162:        act_deallocate(thr_act);
                   1163:        return port;
                   1164: }
                   1165: 
                   1166: /*
                   1167:  *     Routine:        space_deallocate
                   1168:  *     Purpose:
                   1169:  *             Deallocate a space ref produced by convert_port_to_space.
                   1170:  *     Conditions:
                   1171:  *             Nothing locked.
                   1172:  */
                   1173: 
                   1174: void
                   1175: space_deallocate(
                   1176:        ipc_space_t     space)
                   1177: {
                   1178:        if (space != IS_NULL)
                   1179:                is_release(space);
                   1180: }
                   1181: 
                   1182: /*
                   1183:  *     Routine:        thread/task_set_exception_ports [kernel call]
                   1184:  *     Purpose:
                   1185:  *                     Sets the thread/task exception port, flavor and
                   1186:  *                     behavior for the exception types specified by the mask.
                   1187:  *                     There will be one send right per exception per valid
                   1188:  *                     port.
                   1189:  *     Conditions:
                   1190:  *             Nothing locked.  If successful, consumes
                   1191:  *             the supplied send right.
                   1192:  *     Returns:
                   1193:  *             KERN_SUCCESS            Changed the special port.
                   1194:  *             KERN_INVALID_ARGUMENT   The thread is null,
                   1195:  *                                     Illegal mask bit set.
                   1196:  *                                     Illegal exception behavior
                   1197:  *             KERN_FAILURE            The thread is dead.
                   1198:  */
                   1199: 
                   1200: kern_return_t
                   1201: thread_set_exception_ports(
                   1202:        thread_act_t                    thr_act,
                   1203:        exception_mask_t                exception_mask,
                   1204:        ipc_port_t                      new_port,
                   1205:        exception_behavior_t            new_behavior,
                   1206:        thread_state_flavor_t           new_flavor)
                   1207: {
                   1208:        register int    i;
                   1209:        ipc_port_t      old_port[EXC_TYPES_COUNT];
                   1210: 
                   1211:        if (!thr_act)
                   1212:                return KERN_INVALID_ARGUMENT;
                   1213: 
                   1214:        if (exception_mask & ~EXC_MASK_ALL)
                   1215:                return KERN_INVALID_ARGUMENT;
                   1216: 
                   1217:        if (IP_VALID(new_port)) {
                   1218:                switch (new_behavior) {
                   1219:                case EXCEPTION_DEFAULT:
                   1220:                case EXCEPTION_STATE:
                   1221:                case EXCEPTION_STATE_IDENTITY:
                   1222:                        break;
                   1223:                default:
                   1224:                        return KERN_INVALID_ARGUMENT;
                   1225:                }
                   1226:        }
                   1227:        /* Cannot easily check "flavor", but that just means that the flavor
                   1228:         * in the generated exception message might be garbage. GIGO */
                   1229: 
                   1230:        act_lock(thr_act);
                   1231:        if (!thr_act->active) {
                   1232:                act_unlock(thr_act);
                   1233:                return KERN_FAILURE;
                   1234:        }
                   1235: 
                   1236:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                   1237:                if (exception_mask & (1 << i)) {
                   1238:                        old_port[i] = thr_act->exc_actions[i].port;
                   1239:                        thr_act->exc_actions[i].port =
                   1240:                                ipc_port_copy_send(new_port);
                   1241:                        thr_act->exc_actions[i].behavior = new_behavior;
                   1242:                        thr_act->exc_actions[i].flavor = new_flavor;
                   1243:                } else
                   1244:                        old_port[i] = IP_NULL;
                   1245:        }/* for */
                   1246:        /*
                   1247:         * Consume send rights without any lock held.
                   1248:         */
                   1249:        act_unlock(thr_act);
                   1250:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
                   1251:                if (IP_VALID(old_port[i]))
                   1252:                        ipc_port_release_send(old_port[i]);
                   1253:        if (IP_VALID(new_port))          /* consume send right */
                   1254:                ipc_port_release_send(new_port);
                   1255: 
                   1256:         return KERN_SUCCESS;
                   1257: }/* thread_set_exception_port */
                   1258: 
                   1259: kern_return_t
                   1260: task_set_exception_ports(
                   1261:        task_t                          task,
                   1262:        exception_mask_t                exception_mask,
                   1263:        ipc_port_t                      new_port,
                   1264:        exception_behavior_t            new_behavior,
                   1265:        thread_state_flavor_t           new_flavor)
                   1266: {
                   1267:        register int    i;
                   1268:        ipc_port_t      old_port[EXC_TYPES_COUNT];
                   1269: 
                   1270:        if (task == TASK_NULL) {
                   1271:                return KERN_INVALID_ARGUMENT;
                   1272:        }
                   1273: 
                   1274:        if (exception_mask & ~EXC_MASK_ALL) {
                   1275:                return KERN_INVALID_ARGUMENT;
                   1276:        }
                   1277: 
                   1278:        if (IP_VALID(new_port)) {
                   1279:                switch (new_behavior) {
                   1280:                case EXCEPTION_DEFAULT:
                   1281:                case EXCEPTION_STATE:
                   1282:                case EXCEPTION_STATE_IDENTITY:
                   1283:                        break;
                   1284:                default:
                   1285:                        return KERN_INVALID_ARGUMENT;
                   1286:                }
                   1287:        }
                   1288:        /* Cannot easily check "new_flavor", but that just means that
                   1289:         * the flavor in the generated exception message might be garbage:
                   1290:         * GIGO */
                   1291: 
                   1292:         itk_lock(task);
                   1293:         if (task->itk_self == IP_NULL) {
                   1294:                 itk_unlock(task);
                   1295:                 return KERN_FAILURE;
                   1296:         }
                   1297: 
                   1298:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                   1299:                if (exception_mask & (1 << i)) {
                   1300:                        old_port[i] = task->exc_actions[i].port;
                   1301:                        task->exc_actions[i].port =
                   1302:                                ipc_port_copy_send(new_port);
                   1303:                        task->exc_actions[i].behavior = new_behavior;
                   1304:                        task->exc_actions[i].flavor = new_flavor;
                   1305:                } else
                   1306:                        old_port[i] = IP_NULL;
                   1307:        }/* for */
                   1308: 
                   1309:        /*
                   1310:         * Consume send rights without any lock held.
                   1311:         */
                   1312:         itk_unlock(task);
                   1313:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
                   1314:                if (IP_VALID(old_port[i]))
                   1315:                        ipc_port_release_send(old_port[i]);
                   1316:        if (IP_VALID(new_port))          /* consume send right */
                   1317:                ipc_port_release_send(new_port);
                   1318: 
                   1319:         return KERN_SUCCESS;
                   1320: }/* task_set_exception_port */
                   1321: 
                   1322: /*
                   1323:  *     Routine:        thread/task_swap_exception_ports [kernel call]
                   1324:  *     Purpose:
                   1325:  *                     Sets the thread/task exception port, flavor and
                   1326:  *                     behavior for the exception types specified by the
                   1327:  *                     mask.
                   1328:  *
                   1329:  *                     The old ports, behavior and flavors are returned
                   1330:  *                     Count specifies the array sizes on input and
                   1331:  *                     the number of returned ports etc. on output.  The
                   1332:  *                     arrays must be large enough to hold all the returned
                   1333:  *                     data, MIG returnes an error otherwise.  The masks
                   1334:  *                     array specifies the corresponding exception type(s).
                   1335:  *
                   1336:  *     Conditions:
                   1337:  *             Nothing locked.  If successful, consumes
                   1338:  *             the supplied send right.
                   1339:  *
                   1340:  *             Returns upto [in} CountCnt elements.
                   1341:  *     Returns:
                   1342:  *             KERN_SUCCESS            Changed the special port.
                   1343:  *             KERN_INVALID_ARGUMENT   The thread is null,
                   1344:  *                                     Illegal mask bit set.
                   1345:  *                                     Illegal exception behavior
                   1346:  *             KERN_FAILURE            The thread is dead.
                   1347:  */
                   1348: 
                   1349: kern_return_t
                   1350: thread_swap_exception_ports(
                   1351:        thread_act_t                    thr_act,
                   1352:        exception_mask_t                exception_mask,
                   1353:        ipc_port_t                      new_port,
                   1354:        exception_behavior_t            new_behavior,
                   1355:        thread_state_flavor_t           new_flavor,
                   1356:        exception_mask_array_t          masks,
                   1357:        mach_msg_type_number_t          * CountCnt,
                   1358:        exception_port_array_t          ports,
                   1359:        exception_behavior_array_t      behaviors,
                   1360:        thread_state_flavor_array_t     flavors )
                   1361: {
                   1362:        register int    i,
                   1363:                        j,
                   1364:                        count;
                   1365:        ipc_port_t      old_port[EXC_TYPES_COUNT];
                   1366: 
                   1367:        if (!thr_act)
                   1368:                return KERN_INVALID_ARGUMENT;
                   1369: 
                   1370:        if (exception_mask & ~EXC_MASK_ALL) {
                   1371:                return KERN_INVALID_ARGUMENT;
                   1372:        }
                   1373: 
                   1374:        if (IP_VALID(new_port)) {
                   1375:                switch (new_behavior) {
                   1376:                case EXCEPTION_DEFAULT:
                   1377:                case EXCEPTION_STATE:
                   1378:                case EXCEPTION_STATE_IDENTITY:
                   1379:                        break;
                   1380:                default:
                   1381:                        return KERN_INVALID_ARGUMENT;
                   1382:                }
                   1383:        }
                   1384:        /* Cannot easily check "new_flavor", but that just means that
                   1385:         * the flavor in the generated exception message might be garbage:
                   1386:         * GIGO */
                   1387: 
                   1388:        act_lock(thr_act);
                   1389:        if (!thr_act->active) {
                   1390:                act_unlock(thr_act);
                   1391:                return KERN_FAILURE;
                   1392:        }
                   1393: 
                   1394:        count = 0;
                   1395: 
                   1396:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                   1397:                if (exception_mask & (1 << i)) {
                   1398:                        for (j = 0; j < count; j++) {
                   1399: /*
                   1400:  *                             search for an identical entry, if found
                   1401:  *                             set corresponding mask for this exception.
                   1402:  */
                   1403:                                if (thr_act->exc_actions[i].port == ports[j] &&
                   1404:                                  thr_act->exc_actions[i].behavior ==behaviors[j]
                   1405:                                  && thr_act->exc_actions[i].flavor ==flavors[j])
                   1406:                                {
                   1407:                                        masks[j] |= (1 << i);
                   1408:                                        break;
                   1409:                                }
                   1410:                        }/* for */
                   1411:                        if (j == count) {
                   1412:                                masks[j] = (1 << i);
                   1413:                                ports[j] =
                   1414:                                ipc_port_copy_send(thr_act->exc_actions[i].port);
                   1415: 
                   1416:                                behaviors[j] = thr_act->exc_actions[i].behavior;
                   1417:                                flavors[j] = thr_act->exc_actions[i].flavor;
                   1418:                                count++;
                   1419:                        }
                   1420: 
                   1421:                        old_port[i] = thr_act->exc_actions[i].port;
                   1422:                        thr_act->exc_actions[i].port =
                   1423:                                ipc_port_copy_send(new_port);
                   1424:                        thr_act->exc_actions[i].behavior = new_behavior;
                   1425:                        thr_act->exc_actions[i].flavor = new_flavor;
                   1426:                        if (count > *CountCnt) {
                   1427:                                break;
                   1428:                        }
                   1429:                } else
                   1430:                        old_port[i] = IP_NULL;
                   1431:        }/* for */
                   1432: 
                   1433:        /*
                   1434:         * Consume send rights without any lock held.
                   1435:         */
                   1436:        act_unlock(thr_act);
                   1437:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
                   1438:                if (IP_VALID(old_port[i]))
                   1439:                        ipc_port_release_send(old_port[i]);
                   1440:        if (IP_VALID(new_port))          /* consume send right */
                   1441:                ipc_port_release_send(new_port);
                   1442:        *CountCnt = count;
                   1443:        return KERN_SUCCESS;
                   1444: }/* thread_swap_exception_ports */
                   1445: 
                   1446: kern_return_t
                   1447: task_swap_exception_ports(
                   1448:        task_t                          task,
                   1449:        exception_mask_t                exception_mask,
                   1450:        ipc_port_t                      new_port,
                   1451:        exception_behavior_t            new_behavior,
                   1452:        thread_state_flavor_t           new_flavor,
                   1453:        exception_mask_array_t          masks,
                   1454:        mach_msg_type_number_t          * CountCnt,
                   1455:        exception_port_array_t          ports,
                   1456:        exception_behavior_array_t      behaviors,
                   1457:        thread_state_flavor_array_t     flavors         )
                   1458: {
                   1459:        register int    i,
                   1460:                        j,
                   1461:                        count;
                   1462:        ipc_port_t      old_port[EXC_TYPES_COUNT];
                   1463: 
                   1464:        if (task == TASK_NULL)
                   1465:                return KERN_INVALID_ARGUMENT;
                   1466: 
                   1467:        if (exception_mask & ~EXC_MASK_ALL) {
                   1468:                return KERN_INVALID_ARGUMENT;
                   1469:        }
                   1470: 
                   1471:        if (IP_VALID(new_port)) {
                   1472:                switch (new_behavior) {
                   1473:                case EXCEPTION_DEFAULT:
                   1474:                case EXCEPTION_STATE:
                   1475:                case EXCEPTION_STATE_IDENTITY:
                   1476:                        break;
                   1477:                default:
                   1478:                        return KERN_INVALID_ARGUMENT;
                   1479:                }
                   1480:        }
                   1481:        /* Cannot easily check "new_flavor", but that just means that
                   1482:         * the flavor in the generated exception message might be garbage:
                   1483:         * GIGO */
                   1484: 
                   1485:        itk_lock(task);
                   1486:        if (task->itk_self == IP_NULL) {
                   1487:                itk_unlock(task);
                   1488:                return KERN_FAILURE;
                   1489:        }
                   1490: 
                   1491:        count = 0;
                   1492: 
                   1493:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                   1494:                if (exception_mask & (1 << i)) {
                   1495:                        for (j = 0; j < count; j++) {
                   1496: /*
                   1497:  *                             search for an identical entry, if found
                   1498:  *                             set corresponding mask for this exception.
                   1499:  */
                   1500:                                if (task->exc_actions[i].port == ports[j] &&
                   1501:                                  task->exc_actions[i].behavior == behaviors[j]
                   1502:                                  && task->exc_actions[i].flavor == flavors[j])
                   1503:                                {
                   1504:                                        masks[j] |= (1 << i);
                   1505:                                        break;
                   1506:                                }
                   1507:                        }/* for */
                   1508:                        if (j == count) {
                   1509:                                masks[j] = (1 << i);
                   1510:                                ports[j] =
                   1511:                                ipc_port_copy_send(task->exc_actions[i].port);
                   1512:                                behaviors[j] = task->exc_actions[i].behavior;
                   1513:                                flavors[j] = task->exc_actions[i].flavor;
                   1514:                                count++;
                   1515:                        }
                   1516:                        old_port[i] = task->exc_actions[i].port;
                   1517:                        task->exc_actions[i].port =
                   1518:                                ipc_port_copy_send(new_port);
                   1519:                        task->exc_actions[i].behavior = new_behavior;
                   1520:                        task->exc_actions[i].flavor = new_flavor;
                   1521:                        if (count > *CountCnt) {
                   1522:                                break;
                   1523:                        }
                   1524:                } else
                   1525:                        old_port[i] = IP_NULL;
                   1526:        }/* for */
                   1527: 
                   1528: 
                   1529:        /*
                   1530:         * Consume send rights without any lock held.
                   1531:         */
                   1532:        itk_unlock(task);
                   1533:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
                   1534:                if (IP_VALID(old_port[i]))
                   1535:                        ipc_port_release_send(old_port[i]);
                   1536:        if (IP_VALID(new_port))          /* consume send right */
                   1537:                ipc_port_release_send(new_port);
                   1538:        *CountCnt = count;
                   1539: 
                   1540:        return KERN_SUCCESS;
                   1541: }/* task_swap_exception_ports */
                   1542: 
                   1543: /*
                   1544:  *     Routine:        thread/task_get_exception_ports [kernel call]
                   1545:  *     Purpose:
                   1546:  *             Clones a send right for each of the thread/task's exception
                   1547:  *             ports specified in the mask and returns the behaviour
                   1548:  *             and flavor of said port.
                   1549:  *
                   1550:  *             Returns upto [in} CountCnt elements.
                   1551:  *
                   1552:  *     Conditions:
                   1553:  *             Nothing locked.
                   1554:  *     Returns:
                   1555:  *             KERN_SUCCESS            Extracted a send right.
                   1556:  *             KERN_INVALID_ARGUMENT   The thread is null,
                   1557:  *                                     Invalid special port,
                   1558:  *                                     Illegal mask bit set.
                   1559:  *             KERN_FAILURE            The thread is dead.
                   1560:  */
                   1561: 
                   1562: kern_return_t
                   1563: thread_get_exception_ports(
                   1564:        thread_act_t                    thr_act,
                   1565:        exception_mask_t                exception_mask,
                   1566:        exception_mask_array_t          masks,
                   1567:        mach_msg_type_number_t          * CountCnt,
                   1568:        exception_port_array_t          ports,
                   1569:        exception_behavior_array_t      behaviors,
                   1570:        thread_state_flavor_array_t     flavors         )
                   1571: {
                   1572:        register int    i,
                   1573:                        j,
                   1574:                        count;
                   1575: 
                   1576:        if (!thr_act)
                   1577:                return KERN_INVALID_ARGUMENT;
                   1578: 
                   1579:        if (exception_mask & ~EXC_MASK_ALL) {
                   1580:                return KERN_INVALID_ARGUMENT;
                   1581:        }
                   1582: 
                   1583:        act_lock(thr_act);
                   1584:        if (!thr_act->active) {
                   1585:                act_unlock(thr_act);
                   1586:                return KERN_FAILURE;
                   1587:        }
                   1588: 
                   1589:        count = 0;
                   1590: 
                   1591:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                   1592:                if (exception_mask & (1 << i)) {
                   1593:                        for (j = 0; j < count; j++) {
                   1594: /*
                   1595:  *                             search for an identical entry, if found
                   1596:  *                             set corresponding mask for this exception.
                   1597:  */
                   1598:                                if (thr_act->exc_actions[i].port == ports[j] &&
                   1599:                                  thr_act->exc_actions[i].behavior ==behaviors[j]
                   1600:                                  && thr_act->exc_actions[i].flavor == flavors[j])
                   1601:                                {
                   1602:                                        masks[j] |= (1 << i);
                   1603:                                        break;
                   1604:                                }
                   1605:                        }/* for */
                   1606:                        if (j == count) {
                   1607:                                masks[j] = (1 << i);
                   1608:                                ports[j] =
                   1609:                                ipc_port_copy_send(thr_act->exc_actions[i].port);
                   1610:                                behaviors[j] = thr_act->exc_actions[i].behavior;
                   1611:                                flavors[j] = thr_act->exc_actions[i].flavor;
                   1612:                                count++;
                   1613:                                if (count >= *CountCnt) {
                   1614:                                        break;
                   1615:                                }
                   1616:                        }
                   1617:                }
                   1618:        }/* for */
                   1619: 
                   1620:        act_unlock(thr_act);
                   1621: 
                   1622:        *CountCnt = count;
                   1623:        return KERN_SUCCESS;
                   1624: }/* thread_get_exception_ports */
                   1625: 
                   1626: kern_return_t
                   1627: task_get_exception_ports(
                   1628:        task_t                          task,
                   1629:        exception_mask_t                exception_mask,
                   1630:        exception_mask_array_t          masks,
                   1631:        mach_msg_type_number_t          * CountCnt,
                   1632:        exception_port_array_t          ports,
                   1633:        exception_behavior_array_t      behaviors,
                   1634:        thread_state_flavor_array_t     flavors         )
                   1635: {
                   1636:        register int    i,
                   1637:                        j,
                   1638:                        count;
                   1639: 
                   1640:        if (task == TASK_NULL)
                   1641:                return KERN_INVALID_ARGUMENT;
                   1642: 
                   1643:        if (exception_mask & ~EXC_MASK_ALL) {
                   1644:                return KERN_INVALID_ARGUMENT;
                   1645:        }
                   1646: 
                   1647:        itk_lock(task);
                   1648:        if (task->itk_self == IP_NULL) {
                   1649:                itk_unlock(task);
                   1650:                return KERN_FAILURE;
                   1651:        }
                   1652: 
                   1653:        count = 0;
                   1654: 
                   1655:        for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
                   1656:                if (exception_mask & (1 << i)) {
                   1657:                        for (j = 0; j < count; j++) {
                   1658: /*
                   1659:  *                             search for an identical entry, if found
                   1660:  *                             set corresponding mask for this exception.
                   1661:  */
                   1662:                                if (task->exc_actions[i].port == ports[j] &&
                   1663:                                  task->exc_actions[i].behavior == behaviors[j]
                   1664:                                  && task->exc_actions[i].flavor == flavors[j])
                   1665:                                {
                   1666:                                        masks[j] |= (1 << i);
                   1667:                                        break;
                   1668:                                }
                   1669:                        }/* for */
                   1670:                        if (j == count) {
                   1671:                                masks[j] = (1 << i);
                   1672:                                ports[j] =
                   1673:                                  ipc_port_copy_send(task->exc_actions[i].port);
                   1674:                                behaviors[j] = task->exc_actions[i].behavior;
                   1675:                                flavors[j] = task->exc_actions[i].flavor;
                   1676:                                count++;
                   1677:                                if (count > *CountCnt) {
                   1678:                                        break;
                   1679:                                }
                   1680:                        }
                   1681:                }
                   1682:        }/* for */
                   1683: 
                   1684:        itk_unlock(task);
                   1685: 
                   1686:        *CountCnt = count;
                   1687:        return KERN_SUCCESS;
                   1688: }/* task_get_exception_ports */

unix.superglobalmegacorp.com

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