Annotation of XNU/osfmk/kern/task.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_FREE_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989,1988 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:  *     File:   kern/task.c
                     52:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young, David Golub,
                     53:  *             David Black
                     54:  *
                     55:  *     Task management primitives implementation.
                     56:  */
                     57: /*
                     58:  * Copyright (c) 1993 The University of Utah and
                     59:  * the Computer Systems Laboratory (CSL).  All rights reserved.
                     60:  *
                     61:  * Permission to use, copy, modify and distribute this software and its
                     62:  * documentation is hereby granted, provided that both the copyright
                     63:  * notice and this permission notice appear in all copies of the
                     64:  * software, derivative works or modified versions, and any portions
                     65:  * thereof, and that both notices appear in supporting documentation.
                     66:  *
                     67:  * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
                     68:  * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF
                     69:  * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     70:  *
                     71:  * CSL requests users of this software to return to [email protected] any
                     72:  * improvements that they make and grant CSL redistribution rights.
                     73:  *
                     74:  */
                     75: 
                     76: #include <mach_kdb.h>
                     77: #include <mach_host.h>
                     78: #include <mach_prof.h>
                     79: #include <fast_tas.h>
                     80: #include <task_swapper.h>
                     81: #include <platforms.h>
                     82: 
                     83: #include <mach/boolean.h>
                     84: #include <mach/machine/vm_types.h>
                     85: #include <mach/vm_param.h>
                     86: #include <mach/task_info.h>
                     87: #include <mach/task_special_ports.h>
                     88: #include <mach/mach_types.h>
                     89: #include <mach/machine/rpc.h>
                     90: #include <ipc/ipc_space.h>
                     91: #include <ipc/ipc_entry.h>
                     92: #include <kern/mach_param.h>
                     93: #include <kern/misc_protos.h>
                     94: #include <kern/task.h>
                     95: #include <kern/thread.h>
                     96: #include <kern/zalloc.h>
                     97: #include <kern/kalloc.h>
                     98: #include <kern/rtmalloc.h>
                     99: #include <kern/processor.h>
                    100: #include <kern/sched_prim.h>   /* for thread_wakeup */
                    101: #include <kern/sf.h>
                    102: #include <kern/mk_sp.h>        /*** ??? fix so this can be removed ***/
                    103: #include <kern/ipc_tt.h>
                    104: #include <kern/ledger.h>
                    105: #include <kern/host.h>
                    106: #include <vm/vm_kern.h>                /* for kernel_map, ipc_kernel_map */
                    107: #include <kern/profile.h>
                    108: #include <kern/assert.h>
                    109: #include <kern/sync_lock.h>
                    110: #include <kern/sync_sema.h>
                    111: #if    MACH_KDB
                    112: #include <ddb/db_sym.h>
                    113: #endif /* MACH_KDB */
                    114: 
                    115: #if    TASK_SWAPPER
                    116: #include <kern/task_swap.h>
                    117: #endif /* TASK_SWAPPER */
                    118: 
                    119: /*
                    120:  * Exported interfaces
                    121:  */
                    122: 
                    123: #include <mach/task_server.h>
                    124: #include <mach/mach_host_server.h>
                    125: #include <mach/host_security_server.h>
                    126: 
                    127: security_token_t DEFAULT_USER_SECURITY_TOKEN = { {930624, 610120} };
                    128: 
                    129: task_t kernel_task;
                    130: zone_t task_zone;
                    131: 
                    132: /* Forwards */
                    133: 
                    134: kern_return_t  task_hold_locked(
                    135:                        task_t          task);
                    136: void           task_wait_locked(
                    137:                        task_t          task);
                    138: kern_return_t  task_release(
                    139:                        task_t          task);
                    140: void           task_collect_scan(void);
                    141: void           task_act_iterate(
                    142:                        task_t           task,
                    143:                        kern_return_t   (*func)(thread_act_t inc));
                    144: void           task_free(
                    145:                        task_t          task );
                    146: void           task_synchronizer_destroy_all(
                    147:                        task_t          task);
                    148: void           task_subsystem_destroy_all(
                    149:                        task_t          task);
                    150: 
                    151: kern_return_t  task_set_ledger(
                    152:                        task_t          task,
                    153:                        ledger_t        wired,
                    154:                        ledger_t        paged);
                    155: 
                    156: void
                    157: task_init(void)
                    158: {
                    159:        task_zone = zinit(
                    160:                        sizeof(struct task),
                    161:                        TASK_MAX * sizeof(struct task),
                    162:                        TASK_CHUNK * sizeof(struct task),
                    163:                        "tasks");
                    164: 
                    165:        eml_init();
                    166: 
                    167:        /*
                    168:         * Create the kernel task as the first task.
                    169:         * Task_create_local must assign to kernel_task as a side effect,
                    170:         * for other initialization. (:-()
                    171:         */
                    172:        if (task_create_local(
                    173:                        TASK_NULL, FALSE, FALSE, &kernel_task) != KERN_SUCCESS)
                    174:                panic("task_init\n");
                    175:        vm_map_deallocate(kernel_task->map);
                    176:        kernel_task->map = kernel_map;
                    177: 
                    178: #if    MACH_ASSERT
                    179:        if (watchacts & WA_TASK)
                    180:            printf("task_init: kernel_task = %x map=%x\n",
                    181:                                kernel_task, kernel_map);
                    182: #endif /* MACH_ASSERT */
                    183: }
                    184: 
                    185: #if    MACH_HOST
                    186: void
                    187: task_freeze(
                    188:        task_t task)
                    189: {
                    190:        task_lock(task);
                    191:        /*
                    192:         *      If may_assign is false, task is already being assigned,
                    193:         *      wait for that to finish.
                    194:         */
                    195:        while (task->may_assign == FALSE) {
                    196:                task->assign_active = TRUE;
                    197:                thread_sleep_mutex((event_t) &task->assign_active,
                    198:                                        &task->lock, THREAD_INTERRUPTIBLE);
                    199:                task_lock(task);
                    200:        }
                    201:        task->may_assign = FALSE;
                    202:        task_unlock(task);
                    203: 
                    204:        return;
                    205: }
                    206: 
                    207: void
                    208: task_unfreeze(
                    209:        task_t task)
                    210: {
                    211:        task_lock(task);
                    212:        assert(task->may_assign == FALSE);
                    213:        task->may_assign = TRUE;
                    214:        if (task->assign_active == TRUE) {
                    215:                task->assign_active = FALSE;
                    216:                thread_wakeup((event_t)&task->assign_active);
                    217:        }
                    218:        task_unlock(task);
                    219: 
                    220:        return;
                    221: }
                    222: #endif /* MACH_HOST */
                    223: 
                    224: /*
                    225:  * Create a task running in the kernel address space.  It may
                    226:  * have its own map of size mem_size and may have ipc privileges.
                    227:  */
                    228: kern_return_t
                    229: kernel_task_create(
                    230:        task_t                  parent_task,
                    231:        vm_offset_t             map_base,
                    232:        vm_size_t               map_size,
                    233:        task_t                  *child_task)
                    234: {
                    235:        kern_return_t           result;
                    236:        task_t                  new_task;
                    237:        vm_map_t                old_map;
                    238: 
                    239:        /*
                    240:         * Create the task.
                    241:         */
                    242:        result = task_create_local(parent_task, FALSE, TRUE, &new_task);
                    243:        if (result != KERN_SUCCESS)
                    244:                return (result);
                    245: 
                    246:        /*
                    247:         * Task_create_local creates the task with a user-space map.
                    248:         * We attempt to replace the map and free it afterwards; else
                    249:         * task_deallocate will free it (can NOT set map to null before
                    250:         * task_deallocate, this impersonates a norma placeholder task).
                    251:         * _Mark the memory as pageable_ -- this is what we
                    252:         * want for images (like servers) loaded into the kernel.
                    253:         */
                    254:        if (map_size == 0) {
                    255:                vm_map_deallocate(new_task->map);
                    256:                new_task->map = kernel_map;
                    257:                *child_task = new_task;
                    258:        } else {
                    259:                old_map = new_task->map;
                    260:                if ((result = kmem_suballoc(kernel_map, &map_base,
                    261:                                            map_size, TRUE, FALSE,
                    262:                                            &new_task->map)) != KERN_SUCCESS) {
                    263:                        /*
                    264:                         * New task created with ref count of 2 -- decrement by
                    265:                         * one to force task deletion.
                    266:                         */
                    267:                        printf("kmem_suballoc(%x,%x,%x,1,0,&new) Fails\n",
                    268:                               kernel_map, map_base, map_size);
                    269:                        --new_task->ref_count;
                    270:                        task_deallocate(new_task);
                    271:                        return (result);
                    272:                }
                    273:                vm_map_deallocate(old_map);
                    274:                *child_task = new_task;
                    275:        }
                    276:        return (KERN_SUCCESS);
                    277: }
                    278: 
                    279: kern_return_t
                    280: task_create(
                    281:        task_t                  parent_task,
                    282:         ledger_port_array_t    ledger_ports,
                    283:         mach_msg_type_number_t num_ledger_ports,
                    284:        boolean_t               inherit_memory,
                    285:        task_t                  *child_task)            /* OUT */
                    286: {
                    287:        if (parent_task == TASK_NULL)
                    288:                return(KERN_INVALID_ARGUMENT);
                    289: 
                    290:        return task_create_local(
                    291:                        parent_task, inherit_memory, FALSE, child_task);
                    292: }
                    293: 
                    294: kern_return_t
                    295: host_security_create_task_token(
                    296:         host_security_t                host_security,
                    297:        task_t                  parent_task,
                    298:         security_token_t       sec_token,
                    299:         ledger_port_array_t    ledger_ports,
                    300:         mach_msg_type_number_t num_ledger_ports,
                    301:        boolean_t               inherit_memory,
                    302:        task_t                  *child_task)            /* OUT */
                    303: {
                    304:         kern_return_t          result;
                    305:         
                    306:        if (parent_task == TASK_NULL)
                    307:                return(KERN_INVALID_ARGUMENT);
                    308: 
                    309:        if (host_security == HOST_NULL)
                    310:                return(KERN_INVALID_SECURITY);
                    311: 
                    312:        result = task_create_local(
                    313:                        parent_task, inherit_memory, FALSE, child_task);
                    314: 
                    315:         if (result != KERN_SUCCESS)
                    316:                 return(result);
                    317:        result = host_security_set_task_token(host_security,
                    318:                                              *child_task,
                    319:                                              sec_token);
                    320:        return(result);
                    321: }
                    322: 
                    323: kern_return_t
                    324: task_create_local(
                    325:        task_t          parent_task,
                    326:        boolean_t       inherit_memory,
                    327:        boolean_t       kernel_loaded,
                    328:        task_t          *child_task)            /* OUT */
                    329: {
                    330:        task_t          new_task;
                    331:        processor_set_t pset;
                    332: 
                    333:        new_task = (task_t) zalloc(task_zone);
                    334: 
                    335:        if (new_task == TASK_NULL)
                    336:                return(KERN_RESOURCE_SHORTAGE);
                    337: 
                    338:        /* one ref for just being alive; one for our caller */
                    339:        new_task->ref_count = 2;
                    340: 
                    341:        if (inherit_memory)
                    342:                new_task->map = vm_map_fork(parent_task->map);
                    343:        else
                    344:                new_task->map = vm_map_create(pmap_create(0),
                    345:                                        round_page(VM_MIN_ADDRESS),
                    346:                                        trunc_page(VM_MAX_ADDRESS), TRUE);
                    347: 
                    348:        mutex_init(&new_task->lock, ETAP_THREAD_TASK_NEW);
                    349:        queue_init(&new_task->subsystem_list);
                    350:        queue_init(&new_task->thr_acts);
                    351:        mutex_init(&new_task->act_list_lock, ETAP_THREAD_ACT_LIST);
                    352:        new_task->suspend_count = 0;
                    353:        new_task->thr_act_count = 0;
                    354:        new_task->user_stop_count = 0;
                    355:        new_task->active = TRUE;
                    356:        new_task->kernel_loaded = kernel_loaded;
                    357:        new_task->user_data = 0;
                    358:        new_task->faults = 0;
                    359:        new_task->cow_faults = 0;
                    360:        new_task->pageins = 0;
                    361:        new_task->messages_sent = 0;
                    362:        new_task->messages_received = 0;
                    363:        new_task->syscalls_mach = 0;
                    364:        new_task->syscalls_unix=0;
                    365:        new_task->csw=0;
                    366: 
                    367: #ifdef MACH_BSD
                    368:        new_task->bsd_info = 0;
                    369: #endif /* MACH_BSD */
                    370: 
                    371:        new_task->res_act_count = 0;    /* used unconditionally */
                    372: #if    TASK_SWAPPER
                    373:        new_task->swap_state = TASK_SW_IN;
                    374:        new_task->swap_flags = 0;
                    375:        new_task->swap_ast_waiting = 0;
                    376:        new_task->swap_stamp = sched_tick;
                    377:        new_task->swap_rss = 0;
                    378:        new_task->swap_nswap = 0;
                    379: #endif /* TASK_SWAPPER */
                    380: 
                    381:        queue_init(&new_task->semaphore_list);
                    382:        queue_init(&new_task->lock_set_list);
                    383:        new_task->semaphores_owned = 0;
                    384:        new_task->lock_sets_owned = 0;
                    385: 
                    386: #if    MACH_HOST
                    387:        new_task->may_assign = TRUE;
                    388:        new_task->assign_active = FALSE;
                    389: #endif /* MACH_HOST */
                    390:        eml_task_reference(new_task, parent_task);
                    391: 
                    392:        ipc_task_init(new_task, parent_task);
                    393: 
                    394:        new_task->total_user_time.seconds = 0;
                    395:        new_task->total_user_time.microseconds = 0;
                    396:        new_task->total_system_time.seconds = 0;
                    397:        new_task->total_system_time.microseconds = 0;
                    398: 
                    399:        task_prof_init(new_task);
                    400: 
                    401:        if (parent_task != TASK_NULL) {
                    402: #if    MACH_HOST
                    403:                /*
                    404:                 * Freeze the parent, so that parent_task->processor_set
                    405:                 * cannot change.
                    406:                 */
                    407:                task_freeze(parent_task);
                    408: #endif /* MACH_HOST */
                    409:                pset = parent_task->processor_set;
                    410:                if (!pset->active)
                    411:                        pset = &default_pset;
                    412:                new_task->policy = parent_task->policy;
                    413: 
                    414:                /* allocate space for scheduling attributes */
                    415:                new_task->sp_attributes = (sp_attributes_t)kalloc(
                    416:                        sched_policy[new_task->policy].sched_attributes_size);
                    417: 
                    418:                if (new_task->sp_attributes == SP_ATTRIBUTES_NULL) {
                    419:                        zfree(task_zone, (vm_offset_t) new_task);
                    420: 
                    421:                        return(KERN_RESOURCE_SHORTAGE);
                    422:                }
                    423: 
                    424:                /* initialize scheduling attributes */
                    425:                bcopy((char *)parent_task->sp_attributes,
                    426:                      (char *)new_task->sp_attributes,
                    427:                      sched_policy[new_task->policy].sched_attributes_size);
                    428: 
                    429:                new_task->sec_token = parent_task->sec_token;
                    430:                 new_task->wired_ledger_port = ledger_copy(
                    431:                        convert_port_to_ledger(parent_task->wired_ledger_port));
                    432:                 new_task->paged_ledger_port = ledger_copy(
                    433:                        convert_port_to_ledger(parent_task->paged_ledger_port));
                    434:        }
                    435:        else {
                    436:                pset = &default_pset;
                    437:                /*** ??? fix me, so that I am policy independent ***/
                    438:                if (kernel_task == TASK_NULL)
                    439:                        new_task->policy = POLICY_FIFO;
                    440:                else
                    441:                        new_task->policy = POLICY_TIMESHARE;
                    442: 
                    443:                /* allocate space for scheduling attributes */
                    444:                new_task->sp_attributes =
                    445:                                        (sp_attributes_t)kalloc(sizeof(mk_sp_attribute_struct_t));
                    446: 
                    447:                if (new_task->sp_attributes == SP_ATTRIBUTES_NULL) {
                    448:                        zfree(task_zone, (vm_offset_t) new_task);
                    449: 
                    450:                        return(KERN_RESOURCE_SHORTAGE);
                    451:                }
                    452: 
                    453:                /* initialize scheduling attributes */
                    454:                {
                    455:                        /*** ??? fix me ***/
                    456:                        mk_sp_attributes_t      sched_attribute;
                    457: 
                    458:                        sched_attribute = (mk_sp_attributes_t)new_task->sp_attributes;
                    459:                        if (kernel_task == TASK_NULL) {
                    460:                                sched_attribute->policy_id = POLICY_FIFO;
                    461:                                sched_attribute->priority = BASEPRI_SYSTEM;
                    462:                                sched_attribute->max_priority = BASEPRI_SYSTEM;
                    463:                        }
                    464:                        else {
                    465:                                sched_attribute->policy_id = POLICY_TIMESHARE;
                    466:                                sched_attribute->priority = BASEPRI_USER;
                    467:                                sched_attribute->max_priority = BASEPRI_USER;
                    468:                        }
                    469: 
                    470:                        sched_attribute->sched_data = 0;
                    471:                        sched_attribute->unconsumed_quantum = 0;
                    472:                }
                    473: 
                    474:                new_task->sec_token = DEFAULT_USER_SECURITY_TOKEN;
                    475:                new_task->wired_ledger_port = ledger_copy(root_wired_ledger);
                    476:                new_task->paged_ledger_port = ledger_copy(root_paged_ledger);
                    477:        }
                    478:        pset_lock(pset);
                    479:        pset_add_task(pset, new_task);
                    480:        pset_unlock(pset);
                    481: #if    MACH_HOST
                    482:        if (parent_task != TASK_NULL)
                    483:                task_unfreeze(parent_task);
                    484: #endif /* MACH_HOST */
                    485: 
                    486: #if    FAST_TAS
                    487:        if (inherit_memory) {
                    488:                new_task->fast_tas_base = parent_task->fast_tas_base;
                    489:                new_task->fast_tas_end  = parent_task->fast_tas_end;
                    490:        } else {
                    491:                new_task->fast_tas_base = (vm_offset_t)0;
                    492:                new_task->fast_tas_end  = (vm_offset_t)0;
                    493:        }
                    494: #endif /* FAST_TAS */
                    495: 
                    496:        ipc_task_enable(new_task);
                    497: 
                    498: #if    TASK_SWAPPER
                    499:        task_swapout_eligible(new_task);
                    500: #endif /* TASK_SWAPPER */
                    501: 
                    502: #if    MACH_ASSERT
                    503:        if (watchacts & WA_TASK)
                    504:            printf("*** task_create_local(par=%x inh=%x) == 0x%x\n",
                    505:                        parent_task, inherit_memory, new_task);
                    506: #endif /* MACH_ASSERT */
                    507: 
                    508:        *child_task = new_task;
                    509:        return(KERN_SUCCESS);
                    510: }
                    511: 
                    512: /*
                    513:  *     task_free:
                    514:  *
                    515:  *     Called by task_deallocate when the task's reference count drops to zero.
                    516:  *     Task is locked.
                    517:  */
                    518: void
                    519: task_free(
                    520:        task_t          task)
                    521: {
                    522:        processor_set_t pset;
                    523: 
                    524: #if    MACH_ASSERT
                    525:        assert(task != 0);
                    526:        if (watchacts & (WA_EXIT|WA_TASK))
                    527:            printf("task_free(%x(%d)) map ref %d\n", task, task->ref_count,
                    528:                        task->map->ref_count);
                    529: #endif /* MACH_ASSERT */
                    530: 
                    531: #if    TASK_SWAPPER
                    532:        /* task_terminate guarantees that this task is off the list */
                    533:        assert((task->swap_state & TASK_SW_ELIGIBLE) == 0);
                    534: #endif /* TASK_SWAPPER */
                    535: 
                    536:        eml_task_deallocate(task);
                    537: 
                    538:        /*
                    539:         * Temporarily restore the reference we dropped above, then
                    540:         * freeze the task so that the task->processor_set field
                    541:         * cannot change. In the !MACH_HOST case, the logic can be
                    542:         * simplified, since the default_pset is the only pset.
                    543:         */
                    544:        ++task->ref_count;
                    545:        task_unlock(task);
                    546: #if    MACH_HOST
                    547:        task_freeze(task);
                    548: #endif /* MACH_HOST */
                    549:        
                    550:        pset = task->processor_set;
                    551:        pset_lock(pset);
                    552:        task_lock(task);
                    553:        if (--task->ref_count > 0) {
                    554:                /*
                    555:                 * A new reference appeared (probably from the pset).
                    556:                 * Back out. Must unfreeze inline since we'already
                    557:                 * dropped our reference.
                    558:                 */
                    559: #if    MACH_HOST
                    560:                assert(task->may_assign == FALSE);
                    561:                task->may_assign = TRUE;
                    562:                if (task->assign_active == TRUE) {
                    563:                        task->assign_active = FALSE;
                    564:                        thread_wakeup((event_t)&task->assign_active);
                    565:                }
                    566: #endif /* MACH_HOST */
                    567:                task_unlock(task);
                    568:                pset_unlock(pset);
                    569:                return;
                    570:        }
                    571:        ipc_port_release_send(task->wired_ledger_port);
                    572:        ipc_port_release_send(task->paged_ledger_port);
                    573:        pset_remove_task(pset,task);
                    574:        task_unlock(task);
                    575:        pset_unlock(pset);
                    576:        pset_deallocate(pset);
                    577:        if (task->kernel_loaded)
                    578:            vm_map_remove(kernel_map, task->map->min_offset,
                    579:                          task->map->max_offset, VM_MAP_NO_FLAGS);
                    580:        vm_map_deallocate(task->map);
                    581:        is_release(task->itk_space);
                    582:        task_prof_deallocate(task);
                    583:        kfree((vm_offset_t)task->sp_attributes,
                    584:              sched_policy[task->policy].sched_attributes_size);
                    585:        zfree(task_zone, (vm_offset_t) task);
                    586: }
                    587: 
                    588: /*
                    589:  * task_act_iterate
                    590:  *
                    591:  * Ignores returncodes from called function.
                    592:  * Already locked: Task
                    593:  */
                    594: void
                    595: task_act_iterate(
                    596:        task_t          task,
                    597:        kern_return_t   (*func)(thread_act_t inc))
                    598: {
                    599:        thread_act_t    inc, ninc;
                    600: #if    MACH_ASSERT
                    601:        int c1 = task->thr_act_count, c2 = 0;
                    602:        if (watchacts & WA_TASK)
                    603:            printf("\ttask_act_iterate(task=%x, func=%x)\n", task, func);
                    604: #endif /* MACH_ASSERT */
                    605: 
                    606:        /* During iteration, find the next act _before_ calling the function,
                    607:           because the function might remove the act from the task.  */
                    608:        for (inc  = (thread_act_t)queue_first(&task->thr_acts);
                    609:             inc != (thread_act_t)&task->thr_acts;
                    610:             inc  = ninc) {
                    611:                ninc = (thread_act_t)queue_next(&inc->thr_acts);
                    612: #if MACH_ASSERT
                    613:                c2++;
                    614: #endif
                    615:                (void) (*func)(inc);
                    616:        }
                    617: 
                    618: #if MACH_ASSERT
                    619:        if (c1 != c2) {
                    620:                printf("task_act_iterate: thr_act_count %d not %d\n", c1, c2);
                    621:                /* Recount in case above (*func)() changed list */
                    622:                for (c2 = 0, inc  = (thread_act_t)queue_first(&task->thr_acts);
                    623:                             inc != (thread_act_t)&task->thr_acts; inc  = ninc) {
                    624:                    ninc = (thread_act_t)queue_next(&inc->thr_acts);
                    625:                    c2++;
                    626:                }
                    627:                printf("\t reset thr_act_count to %d\n",
                    628:                                        task->thr_act_count = c2);
                    629:        }
                    630: #endif
                    631: }
                    632: 
                    633: void
                    634: task_deallocate(
                    635:        task_t          task)
                    636: {
                    637:        if (task != TASK_NULL) {
                    638:                int     c;
                    639: 
                    640:                task_lock(task);
                    641:                c = --task->ref_count;
                    642:                if (c == 0)
                    643:                    task_free(task);    /* unlocks task */
                    644:                else
                    645:                    task_unlock(task);
                    646:        }
                    647: }
                    648: 
                    649: void
                    650: task_reference(
                    651:        task_t          task)
                    652: {
                    653:        if (task != TASK_NULL) {
                    654:                task_lock(task);
                    655:                task->ref_count++;
                    656:                task_unlock(task);
                    657:        }
                    658: }
                    659: 
                    660: /*
                    661:  *     task_terminate:
                    662:  *
                    663:  *     Terminate the specified task.  See comments on thread_terminate
                    664:  *     (kern/thread.c) about problems with terminating the "current task."
                    665:  */
                    666: 
                    667: kern_return_t
                    668: task_terminate(
                    669:        task_t          task)
                    670: {
                    671:        if (task == TASK_NULL)
                    672:                return(KERN_INVALID_ARGUMENT);
                    673:        if (task->bsd_info)
                    674:                return(KERN_FAILURE);
                    675:        return (task_terminate_internal(task));
                    676: }
                    677: 
                    678: kern_return_t
                    679: task_terminate_internal(
                    680:        task_t          task)
                    681: {
                    682:        register thread_t       thread, cur_thread;
                    683:        register queue_head_t   *list;
                    684:        register task_t         cur_task;
                    685:        thread_act_t            thr_act, next_thr_act, cur_thr_act;
                    686:        spl_t                   s;
                    687: 
                    688:        assert(task != kernel_task);
                    689: 
                    690:        list = &task->thr_acts;
                    691:        cur_task = current_task();
                    692:        cur_thr_act = current_thread()->top_act;
                    693: 
                    694: #if    TASK_SWAPPER
                    695:        /*
                    696:         *      If task is not resident (swapped out, or being swapped
                    697:         *      out), we want to bring it back in (this can block).
                    698:         *      NOTE: The only way that this can happen in the current
                    699:         *      system is if the task is swapped while it has a thread
                    700:         *      in exit(), and the thread does not hit a clean point
                    701:         *      to swap itself before getting here.  
                    702:         *      Terminating other tasks is another way to this code, but
                    703:         *      it is not yet fully supported.
                    704:         *      The task_swapin is unconditional.  It used to be done
                    705:         *      only if the task is not resident.  Swapping in a
                    706:         *      resident task will prevent it from being swapped out 
                    707:         *      while it terminates.
                    708:         */
                    709:        task_swapin(task, TRUE);        /* TRUE means make it unswappable */
                    710: #endif /* TASK_SWAPPER */
                    711: 
                    712:        /*
                    713:         *      Deactivate task so that it can't be terminated again,
                    714:         *      and so lengthy operations in progress will abort.
                    715:         *
                    716:         *      If the current thread is in this task, remove it from
                    717:         *      the task's thread list to keep the thread-termination
                    718:         *      loop simple.
                    719:         */
                    720:        if (task == cur_task) {
                    721:                task_lock(task);
                    722:                if (!task->active) {
                    723:                        /*
                    724:                         *      Task is already being terminated.
                    725:                         */
                    726:                        task_unlock(task);
                    727:                        thread_block((void (*)(void)) 0);
                    728:                        return(KERN_FAILURE);
                    729:                }
                    730: 
                    731:                task_hold_locked(task);
                    732: 
                    733:                task->active = FALSE;
                    734: 
                    735:                /*
                    736:                 *      Make sure current thread is not being terminated.
                    737:                 */
                    738:                mutex_lock(&task->act_list_lock);
                    739:                cur_thread = act_lock_thread(cur_thr_act);
                    740:                if (!cur_thr_act->active) {
                    741:                        act_unlock_thread(cur_thr_act);
                    742:                        mutex_unlock(&task->act_list_lock);
                    743:                        task_unlock(task);
                    744:                        task_release(task);
                    745:                        thread_terminate(cur_thr_act);
                    746:                        return(KERN_FAILURE);
                    747:                }
                    748: 
                    749:                /*
                    750:                 * make sure that this thread is the last one in the list
                    751:                 */
                    752:                queue_remove(list, cur_thr_act, thread_act_t, thr_acts);
                    753:                queue_enter(list, cur_thr_act, thread_act_t, thr_acts);
                    754:                act_unlock_thread(cur_thr_act);
                    755:                mutex_unlock(&task->act_list_lock);
                    756: 
                    757:                /*
                    758:                 *      Shut down this thread's ipc now because it must
                    759:                 *      be left alone to terminate the task.
                    760:                 */
                    761:                ipc_thr_act_disable(cur_thr_act);
                    762:                ipc_thr_act_terminate(cur_thr_act);
                    763:        }
                    764:        else {
                    765:                /*
                    766:                 *      Lock both current and victim task to check for
                    767:                 *      potential deadlock.
                    768:                 */
                    769:                if (task < cur_task) {
                    770:                        task_lock(task);
                    771:                        task_lock(cur_task);
                    772:                }
                    773:                else {
                    774:                        task_lock(cur_task);
                    775:                        task_lock(task);
                    776:                }
                    777:                /*
                    778:                 *      Check if current thread_act or task is being terminated.
                    779:                 */
                    780:                cur_thread = act_lock_thread(cur_thr_act);
                    781:                if ((!cur_task->active) || (!cur_thr_act->active)) {
                    782:                        /*
                    783:                         * Current task or thread is being terminated.
                    784:                         */
                    785:                        act_unlock_thread(cur_thr_act);
                    786:                        task_unlock(task);
                    787:                        task_unlock(cur_task);
                    788:                        return(KERN_FAILURE);
                    789:                }
                    790:                act_unlock_thread(cur_thr_act);
                    791:                task_unlock(cur_task);
                    792: 
                    793:                if (!task->active) {
                    794:                        /*
                    795:                         *      Task is already being terminated.
                    796:                         */
                    797:                        task_unlock(task);
                    798:                        thread_block((void (*)(void)) 0);
                    799:                        return(KERN_FAILURE);
                    800:                }
                    801:                task_hold_locked(task);
                    802:                task->active = FALSE;
                    803:        }
                    804: 
                    805:        /*
                    806:         *      Prevent further execution of the task.  ipc_task_disable
                    807:         *      prevents further task operations via the task port.
                    808:         *      If this is the current task, the current thread will
                    809:         *      be left running.
                    810:         */
                    811:        ipc_task_disable(task);
                    812:        task_wait_locked(task);
                    813: 
                    814:        /*
                    815:         *      Terminate each thread in the task.  Depending on the
                    816:         *      state of the thread, this can mean a number of things.
                    817:         *      However, we just call thread_terminate(), which
                    818:         *      takes care of all cases (see that code for details).
                    819:         *
                    820:         *      The task_port is closed down, so no more thread_create
                    821:         *      operations can be done.  Thread_terminate closes the
                    822:         *      thread port for each thread; when that is done, the
                    823:         *      thread will eventually disappear.  Thus the loop will
                    824:         *      terminate.
                    825:         *      Need to call thread_block() inside loop because some
                    826:          *      other thread (e.g., the reaper) may have to run to get rid
                    827:          *      of all references to the thread; it won't vanish from
                    828:          *      the task's thread list until the last one is gone.
                    829:          */
                    830:        thr_act = (thread_act_t)queue_first(&task->thr_acts);
                    831:        while ( thr_act!= (thread_act_t)&task->thr_acts) {
                    832:                act_reference(thr_act);
                    833:                next_thr_act =  (thread_act_t)queue_next(&thr_act->thr_acts);
                    834:                task_unlock(task);
                    835:                thread_terminate(thr_act);
                    836:                act_deallocate(thr_act);
                    837:                task_lock(task);
                    838:                thr_act = next_thr_act;
                    839:        }
                    840: 
                    841:        task_unlock(task);
                    842: 
                    843:        /*
                    844:         *      Destroy all synchronizers owned by the task.
                    845:         */
                    846:        task_synchronizer_destroy_all(task);
                    847: 
                    848:        /*
                    849:         *      Shut down IPC.
                    850:         */
                    851:        ipc_task_terminate(task);
                    852: 
                    853:        /*
                    854:         *      Deallocate all subsystems owned by the task.
                    855:         */
                    856:        task_subsystem_destroy_all(task);
                    857: 
                    858:        /*
                    859:         * If the current thread is a member of the task
                    860:         * being terminated, then the last reference to
                    861:         * the task will not be dropped until the thread
                    862:         * is finally reaped.  To avoid incurring the
                    863:         * expense of removing the address space regions
                    864:         * at reap time, we do it explictly here.
                    865:         */
                    866:        (void) vm_map_remove(task->map,
                    867:                                                        task->map->min_offset,
                    868:                                                        task->map->max_offset, VM_MAP_NO_FLAGS);
                    869: 
                    870:        /*
                    871:         *      Deallocate the task's reference to itself.
                    872:         */
                    873:        task_deallocate(task);
                    874: 
                    875:        return(KERN_SUCCESS);
                    876: }
                    877: 
                    878: /*
                    879:  * Wait for all threads in task to terminate (except current).
                    880:  * We rely on the fact that all the other threads cache references
                    881:  * to the task's VM map, and when we are alone in the task the
                    882:  * reference count on the map should reach two (one for the task
                    883:  * itself and one for the current act).
                    884:  */
                    885: void
                    886: task_halt_wait(
                    887:        register task_t         task)
                    888: {
                    889:        vm_map_t map = task->map;
                    890: 
                    891:        assert(current_thread()->top_act->task == task);
                    892: 
                    893:        /*
                    894:         *      Wait for the current thread to become the only thread in
                    895:         *      this task.
                    896:         */
                    897:        /*
                    898:         * Now wait for the map users to settle down.
                    899:         */
                    900:        mutex_lock(&map->s_lock);
                    901:        while (map->ref_count > 2) {
                    902:                assert_wait(&map->ref_count, THREAD_UNINT);
                    903:                mutex_unlock(&map->s_lock);
                    904:                thread_block(0);
                    905:                mutex_lock(&map->s_lock);
                    906:        }
                    907:        mutex_unlock(&map->s_lock);
                    908: }
                    909: 
                    910: /*
                    911:  * task_halt - Shut the current task down (except for the current thread) in
                    912:  *             preparation for dramatic changes to the task (probably exec).
                    913:  *             We hold the task, terminate all other threads in the task and
                    914:  *             wait for them to terminate, clean up the portspace, and when
                    915:  *             all done, let the current thread go.
                    916:  */
                    917: kern_return_t
                    918: task_halt(
                    919:        task_t          task)
                    920: {
                    921:        register thread_t       thread, cur_thread;
                    922:        register queue_head_t   *list;
                    923:        register task_t         cur_task;
                    924:        thread_act_t            thr_act, cur_thr_act;
                    925:        spl_t                   s;
                    926: 
                    927:        assert(task != kernel_task);
                    928: 
                    929:        cur_task = current_task();
                    930:        if (task != cur_task) {
                    931:                return(KERN_INVALID_ARGUMENT);
                    932:        }
                    933: 
                    934: #if    TASK_SWAPPER
                    935:        /*
                    936:         *      If task is not resident (swapped out, or being swapped
                    937:         *      out), we want to bring it back in (this can block).
                    938:         *      NOTE: The only way that this can happen in the current
                    939:         *      system is if the task is swapped while it has a thread
                    940:         *      in exit(), and the thread does not hit a clean point
                    941:         *      to swap itself before getting here.  
                    942:         *      Terminating other tasks is another way to this code, but
                    943:         *      it is not yet fully supported.
                    944:         *      The task_swapin is unconditional.  It used to be done
                    945:         *      only if the task is not resident.  Swapping in a
                    946:         *      resident task will prevent it from being swapped out 
                    947:         *      while it terminates.
                    948:         */
                    949:        task_swapin(task, TRUE);        /* TRUE means make it unswappable */
                    950: #endif /* TASK_SWAPPER */
                    951: 
                    952:        /*
                    953:         *      Deactivate task so that it can't be terminated again,
                    954:         *      and so lengthy operations in progress will abort.
                    955:         *
                    956:         *      If the current thread is in this task, remove it from
                    957:         *      the task's thread list to keep the thread-termination
                    958:         *      loop simple.
                    959:         */
                    960:        task_lock(task);
                    961:        if (!task->active) {
                    962:                /*
                    963:                 *      Task is already being terminated.
                    964:                 */
                    965:                task_unlock(task);
                    966:                thread_block((void (*)(void)) 0);
                    967:                return(KERN_FAILURE);
                    968:        }
                    969:        task_hold_locked(task);
                    970: 
                    971:        /*
                    972:         *      Make sure current thread is not being terminated.
                    973:         */
                    974:        cur_thr_act = current_thread()->top_act;
                    975:        mutex_lock(&task->act_list_lock);
                    976:        cur_thread = act_lock_thread(cur_thr_act);
                    977:        if (!cur_thr_act->active) {
                    978:                act_unlock_thread(cur_thr_act);
                    979:                mutex_unlock(&task->act_list_lock);
                    980:                task_unlock(task);
                    981:                task_release(task);
                    982:                thread_terminate(cur_thr_act);
                    983:                return(KERN_FAILURE);
                    984:        }
                    985: 
                    986:        task->active = FALSE;
                    987: 
                    988:        /*
                    989:         *      Make sure that this thread is the last one in the list
                    990:         */
                    991:        list = &task->thr_acts;
                    992:        queue_remove(list, cur_thr_act, thread_act_t, thr_acts);
                    993:        queue_enter(list, cur_thr_act, thread_act_t, thr_acts);
                    994:        act_unlock_thread(cur_thr_act);
                    995:        mutex_unlock(&task->act_list_lock);
                    996: 
                    997:        /*
                    998:         *      Wait for threads to get to clean points.
                    999:         */
                   1000:        task_wait_locked(task);
                   1001: 
                   1002:        /*
                   1003:         *      Now that each thread in the task is at a clean point (and the
                   1004:         *      task is temporarily marked inactive so no new threads can be
                   1005:         *      created), we terminate each of those other threads.
                   1006:          */
                   1007:        for (thr_act  = (thread_act_t)queue_first(&task->thr_acts);
                   1008:             thr_act != (thread_act_t)cur_thr_act;
                   1009:             thr_act  = (thread_act_t)queue_next(&thr_act->thr_acts)) {
                   1010:                 act_reference(thr_act);
                   1011:                 task_unlock(task);
                   1012:                 thread_terminate(thr_act);
                   1013:                 act_deallocate(thr_act);
                   1014:                 task_lock(task);
                   1015:        }
                   1016:        task_unlock(task);
                   1017: 
                   1018:        /*
                   1019:         * Wait for the the other threads to exit.
                   1020:         */
                   1021:        task_halt_wait(task);
                   1022: 
                   1023:        /*
                   1024:         * Put it back as active and release the hold on the task
                   1025:         */
                   1026:        task_lock(task);
                   1027:        task->active = TRUE;
                   1028:         task_unlock(task);
                   1029:        task_release(task);
                   1030:        return(KERN_SUCCESS);
                   1031: }
                   1032: 
                   1033: /*
                   1034:  * Clean up a task for possible reuse (like after exec).
                   1035:  */
                   1036: void
                   1037: task_ipc_cleanup(
                   1038:           task_t task)
                   1039: {
                   1040:        /*
                   1041:         * Remove all the port rights from the task's IPC port space.
                   1042:         */
                   1043:        ipc_space_clean(task->itk_space);
                   1044: 
                   1045:        /*
                   1046:         *      Destroy all synchronizers owned by the task.
                   1047:         */
                   1048:        task_synchronizer_destroy_all(task);
                   1049: 
                   1050:        /*
                   1051:         *      Deallocate all subsystems owned by the task.
                   1052:         */
                   1053:        task_subsystem_destroy_all(task);
                   1054: 
                   1055: }
                   1056: 
                   1057: /*
                   1058:  *     task_hold_locked:
                   1059:  *
                   1060:  *     Suspend execution of the specified task.
                   1061:  *     This is a recursive-style suspension of the task, a count of
                   1062:  *     suspends is maintained.
                   1063:  *
                   1064:  *     CONDITIONS: the task is locked.
                   1065:  */
                   1066: kern_return_t
                   1067: task_hold_locked(
                   1068:        register task_t task)
                   1069: {
                   1070:        register queue_head_t   *list;
                   1071:        register thread_act_t   thr_act, cur_thr_act;
                   1072: 
                   1073:        cur_thr_act = current_act();
                   1074: 
                   1075:        if (!task->active) {
                   1076:                return(KERN_FAILURE);
                   1077:        }
                   1078: 
                   1079:        task->suspend_count++;
                   1080: 
                   1081:        /*
                   1082:         *      Iterate through all the thread_act's and hold them.
                   1083:         *      Do not hold the current thread_act if it is within the
                   1084:         *      task.
                   1085:         */
                   1086:        list = &task->thr_acts;
                   1087:        thr_act = (thread_act_t) queue_first(list);
                   1088:        while (!queue_end(list, (queue_entry_t) thr_act)) {
                   1089:                (void)act_lock_thread(thr_act);
                   1090:                thread_hold(thr_act);
                   1091:                act_unlock_thread(thr_act);
                   1092:                thr_act = (thread_act_t) queue_next(&thr_act->thr_acts);
                   1093:        }
                   1094:        return(KERN_SUCCESS);
                   1095: }
                   1096: 
                   1097: kern_return_t
                   1098: task_release(
                   1099:        register task_t task)
                   1100: {
                   1101:        register queue_head_t   *list;
                   1102:        register thread_act_t   thr_act, next;
                   1103: 
                   1104:        task_lock(task);
                   1105:        if (!task->active) {
                   1106:                task_unlock(task);
                   1107:                return(KERN_FAILURE);
                   1108:        }
                   1109: 
                   1110:        task->suspend_count--;
                   1111: 
                   1112:        /*
                   1113:         *      Iterate through all the thread_act's and release them.
                   1114:         */
                   1115:        list = &task->thr_acts;
                   1116:        thr_act = (thread_act_t) queue_first(list);
                   1117:        while (!queue_end(list, (queue_entry_t) thr_act)) {
                   1118:                next = (thread_act_t) queue_next(&thr_act->thr_acts);
                   1119:                (void)act_lock_thread(thr_act);
                   1120:                thread_release(thr_act);
                   1121:                act_unlock_thread(thr_act);
                   1122:                thr_act = next;
                   1123:        }
                   1124:        task_unlock(task);
                   1125:        return(KERN_SUCCESS);
                   1126: }
                   1127: 
                   1128: kern_return_t
                   1129: task_threads(
                   1130:        task_t                  task,
                   1131:        thread_act_array_t      *thr_act_list,
                   1132:        mach_msg_type_number_t  *count)
                   1133: {
                   1134:        unsigned int            actual; /* this many thr_acts */
                   1135:        thread_act_t            thr_act;
                   1136:        thread_act_t            *thr_acts;
                   1137:        thread_t                thread;
                   1138:        int                     i, j;
                   1139:        boolean_t rt = FALSE; /* ### This boolean is FALSE, because there
                   1140:                               * currently exists no mechanism to determine
                   1141:                               * whether or not the reply port is an RT port
                   1142:                               */
                   1143: 
                   1144: 
                   1145:        vm_size_t size, size_needed;
                   1146:        vm_offset_t addr;
                   1147: 
                   1148:        if (task == TASK_NULL)
                   1149:                return KERN_INVALID_ARGUMENT;
                   1150: 
                   1151:        size = 0; addr = 0;
                   1152: 
                   1153:        for (;;) {
                   1154:                task_lock(task);
                   1155:                if (!task->active) {
                   1156:                        task_unlock(task);
                   1157:                        if (size != 0)
                   1158:                                KFREE(addr, size, rt);
                   1159:                        return KERN_FAILURE;
                   1160:                }
                   1161: 
                   1162:                actual = task->thr_act_count;
                   1163: 
                   1164:                /* do we have the memory we need? */
                   1165:                size_needed = actual * sizeof(mach_port_t);
                   1166:                if (size_needed <= size)
                   1167:                        break;
                   1168: 
                   1169:                /* unlock the task and allocate more memory */
                   1170:                task_unlock(task);
                   1171: 
                   1172:                if (size != 0)
                   1173:                        KFREE(addr, size, rt);
                   1174: 
                   1175:                assert(size_needed > 0);
                   1176:                size = size_needed;
                   1177: 
                   1178:                addr = KALLOC(size, rt);
                   1179:                if (addr == 0)
                   1180:                        return KERN_RESOURCE_SHORTAGE;
                   1181:        }
                   1182: 
                   1183:        /* OK, have memory and the task is locked & active */
                   1184:        thr_acts = (thread_act_t *) addr;
                   1185: 
                   1186:        for (i = j = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts);
                   1187:             i < actual;
                   1188:             i++, thr_act = (thread_act_t) queue_next(&thr_act->thr_acts)) {
                   1189:                act_reference(thr_act);
                   1190:                thr_acts[j++] = thr_act;
                   1191:        }
                   1192:        assert(queue_end(&task->thr_acts, (queue_entry_t) thr_act));
                   1193:        actual = j;
                   1194: 
                   1195:        /* can unlock task now that we've got the thr_act refs */
                   1196:        task_unlock(task);
                   1197: 
                   1198:        if (actual == 0) {
                   1199:                /* no thr_acts, so return null pointer and deallocate memory */
                   1200: 
                   1201:                *thr_act_list = 0;
                   1202:                *count = 0;
                   1203: 
                   1204:                if (size != 0)
                   1205:                        KFREE(addr, size, rt);
                   1206:        } else {
                   1207:                /* if we allocated too much, must copy */
                   1208: 
                   1209:                if (size_needed < size) {
                   1210:                        vm_offset_t newaddr;
                   1211: 
                   1212:                        newaddr = KALLOC(size_needed, rt);
                   1213:                        if (newaddr == 0) {
                   1214:                                for (i = 0; i < actual; i++)
                   1215:                                        act_deallocate(thr_acts[i]);
                   1216:                                KFREE(addr, size, rt);
                   1217:                                return KERN_RESOURCE_SHORTAGE;
                   1218:                        }
                   1219: 
                   1220:                        bcopy((char *) addr, (char *) newaddr, size_needed);
                   1221:                        KFREE(addr, size, rt);
                   1222:                        thr_acts = (thread_act_t *) newaddr;
                   1223:                }
                   1224: 
                   1225:                *thr_act_list = thr_acts;
                   1226:                *count = actual;
                   1227: 
                   1228:                /* do the conversion that Mig should handle */
                   1229: 
                   1230:                for (i = 0; i < actual; i++)
                   1231:                        ((ipc_port_t *) thr_acts)[i] =
                   1232:                                convert_act_to_port(thr_acts[i]);
                   1233:        }
                   1234: 
                   1235:        return KERN_SUCCESS;
                   1236: }
                   1237: 
                   1238: kern_return_t
                   1239: task_suspend(
                   1240:        register task_t         task)
                   1241: {
                   1242:        if (task == TASK_NULL)
                   1243:                return (KERN_INVALID_ARGUMENT);
                   1244: 
                   1245:        task_lock(task);
                   1246:        if (!task->active) {
                   1247:                task_unlock(task);
                   1248:                return (KERN_FAILURE);
                   1249:        }
                   1250:        if ((task->user_stop_count)++ > 0) {
                   1251:                /*
                   1252:                 *      If the stop count was positive, the task is
                   1253:                 *      already stopped and we can exit.
                   1254:                 */
                   1255:                task_unlock(task);
                   1256:                return (KERN_SUCCESS);
                   1257:        }
                   1258: 
                   1259:        /*
                   1260:         *      Hold all of the threads in the task, and wait for
                   1261:         *      them to stop.  If the current thread is within
                   1262:         *      this task, hold it separately so that all of the
                   1263:         *      other threads can stop first.
                   1264:         */
                   1265:        if (task_hold_locked(task) != KERN_SUCCESS) {
                   1266:                task_unlock(task);
                   1267:                return (KERN_FAILURE);
                   1268:        }
                   1269: 
                   1270:        task_wait_locked(task);
                   1271:        task_unlock(task);
                   1272:        return (KERN_SUCCESS);
                   1273: }
                   1274: 
                   1275: /*
                   1276:  * Wait for all threads in task to stop.  Called with task locked.
                   1277:  */
                   1278: void
                   1279: task_wait_locked(
                   1280:        register task_t         task)
                   1281: {
                   1282:        register queue_head_t   *list;
                   1283:        register thread_act_t   thr_act, refd_thr_act;
                   1284:        register thread_t       thread, cur_thr;
                   1285: 
                   1286:        cur_thr = current_thread();
                   1287:        /*
                   1288:         *      Iterate through all the thread's and wait for them to
                   1289:         *      stop.  Do not wait for the current thread if it is within
                   1290:         *      the task.
                   1291:         */
                   1292:        list = &task->thr_acts;
                   1293:        refd_thr_act = THR_ACT_NULL;
                   1294:        for (;;) {
                   1295:                thr_act = (thread_act_t) queue_first(list);
                   1296:                while (!queue_end(list, (queue_entry_t) thr_act)) {
                   1297:                        thread = act_lock_thread(thr_act);
                   1298:                        if (refd_thr_act != THR_ACT_NULL) {
                   1299:                                act_deallocate(refd_thr_act);
                   1300:                                refd_thr_act = THR_ACT_NULL;
                   1301:                        }
                   1302:                        if (thread != THREAD_NULL &&
                   1303:                                        thr_act == thread->top_act &&
                   1304:                                                        thread != cur_thr) {
                   1305:                                refd_thr_act = thr_act;
                   1306:                                act_locked_act_reference(thr_act);
                   1307:                                act_unlock_thread(thr_act);
                   1308:                                task_unlock(task);
                   1309:                                (void)thread_wait(thread);
                   1310:                                task_lock(task);
                   1311:                                thread = act_lock_thread(thr_act);
                   1312:                                if (!thr_act->active) {
                   1313:                                        act_unlock_thread(thr_act);
                   1314:                                        /* drop reference to act immediately */
                   1315:                                        task_unlock(task);
                   1316:                                        act_deallocate(refd_thr_act);
                   1317:                                        refd_thr_act = THR_ACT_NULL;
                   1318:                                        task_lock(task);
                   1319:                                        break;
                   1320:                                }
                   1321:                        }
                   1322:                        act_unlock_thread(thr_act);
                   1323:                        thr_act = (thread_act_t)queue_next(&thr_act->thr_acts);
                   1324:                }
                   1325:                if (queue_end(list, (queue_entry_t)thr_act))
                   1326:                        break;
                   1327:        }
                   1328:        if (refd_thr_act != THR_ACT_NULL) {
                   1329:                act_deallocate(refd_thr_act);
                   1330:                refd_thr_act = THR_ACT_NULL;
                   1331:        }
                   1332: }
                   1333: 
                   1334: kern_return_t 
                   1335: task_resume(register task_t task)
                   1336: {
                   1337:        register boolean_t      release;
                   1338: 
                   1339:        if (task == TASK_NULL)
                   1340:                return(KERN_INVALID_ARGUMENT);
                   1341: 
                   1342:        release = FALSE;
                   1343:        task_lock(task);
                   1344:        if (!task->active) {
                   1345:                task_unlock(task);
                   1346:                return(KERN_FAILURE);
                   1347:        }
                   1348:        if (task->user_stop_count > 0) {
                   1349:                if (--(task->user_stop_count) == 0)
                   1350:                        release = TRUE;
                   1351:        }
                   1352:        else {
                   1353:                task_unlock(task);
                   1354:                return(KERN_FAILURE);
                   1355:        }
                   1356:        task_unlock(task);
                   1357: 
                   1358:        /*
                   1359:         *      Release the task if necessary.
                   1360:         */
                   1361:        if (release)
                   1362:                return(task_release(task));
                   1363: 
                   1364:        return(KERN_SUCCESS);
                   1365: }
                   1366: 
                   1367: kern_return_t
                   1368: host_security_set_task_token(
                   1369:         host_security_t  host_security,
                   1370:         task_t          task,
                   1371:         security_token_t sec_token)
                   1372: {
                   1373:        if (task == TASK_NULL)
                   1374:                return(KERN_INVALID_ARGUMENT);
                   1375: 
                   1376:        if (host_security == HOST_NULL)
                   1377:                return(KERN_INVALID_SECURITY);
                   1378: 
                   1379:         task_lock(task);
                   1380:         task->sec_token = sec_token;
                   1381:         task_unlock(task);
                   1382: 
                   1383:         return(KERN_SUCCESS);
                   1384: }
                   1385: 
                   1386: /*
                   1387:  * Utility routine to set a ledger
                   1388:  */
                   1389: kern_return_t
                   1390: task_set_ledger(
                   1391:         task_t         task,
                   1392:         ledger_t       wired,
                   1393:         ledger_t       paged)
                   1394: {
                   1395:        if (task == TASK_NULL)
                   1396:                return(KERN_INVALID_ARGUMENT);
                   1397: 
                   1398:         task_lock(task);
                   1399:         if (wired) {
                   1400:                 ipc_port_release_send(task->wired_ledger_port);
                   1401:                 task->wired_ledger_port = ledger_copy(wired);
                   1402:         }                
                   1403:         if (paged) {
                   1404:                 ipc_port_release_send(task->paged_ledger_port);
                   1405:                 task->paged_ledger_port = ledger_copy(paged);
                   1406:         }                
                   1407:         task_unlock(task);
                   1408: 
                   1409:         return(KERN_SUCCESS);
                   1410: }
                   1411: 
                   1412: /*
                   1413:  * This routine was added, pretty much exclusively, for registering the
                   1414:  * RPC glue vector for in-kernel short circuited tasks.  Rather than
                   1415:  * removing it completely, I have only disabled that feature (which was
                   1416:  * the only feature at the time).  It just appears that we are going to
                   1417:  * want to add some user data to tasks in the future (i.e. bsd info,
                   1418:  * task names, etc...), so I left it in the formal task interface.
                   1419:  */
                   1420: kern_return_t
                   1421: task_set_info(
                   1422:        task_t          task,
                   1423:        task_flavor_t   flavor,
                   1424:        task_info_t     task_info_in,           /* pointer to IN array */
                   1425:        mach_msg_type_number_t  task_info_count)
                   1426: {
                   1427:        vm_map_t                map;
                   1428: 
                   1429:        if (task == TASK_NULL)
                   1430:                return(KERN_INVALID_ARGUMENT);
                   1431: 
                   1432:        switch (flavor) {
                   1433:            default:
                   1434:                return (KERN_INVALID_ARGUMENT);
                   1435:        }
                   1436:        return (KERN_SUCCESS);
                   1437: }
                   1438: 
                   1439: kern_return_t
                   1440: task_info(
                   1441:        task_t                  task,
                   1442:        task_flavor_t           flavor,
                   1443:        task_info_t             task_info_out,
                   1444:        mach_msg_type_number_t  *task_info_count)
                   1445: {
                   1446:        thread_t        thread;
                   1447:        vm_map_t        map;
                   1448: 
                   1449:        if (task == TASK_NULL)
                   1450:                return(KERN_INVALID_ARGUMENT);
                   1451: 
                   1452:        switch (flavor) {
                   1453: 
                   1454:            case TASK_BASIC_INFO:
                   1455:            {
                   1456:                register task_basic_info_t      basic_info;
                   1457: 
                   1458:                if (*task_info_count < TASK_BASIC_INFO_COUNT) {
                   1459:                    return(KERN_INVALID_ARGUMENT);
                   1460:                }
                   1461: 
                   1462:                basic_info = (task_basic_info_t) task_info_out;
                   1463: 
                   1464:                map = (task == kernel_task) ? kernel_map : task->map;
                   1465: 
                   1466:                basic_info->virtual_size  = map->size;
                   1467:                basic_info->resident_size = pmap_resident_count(map->pmap)
                   1468:                                                   * PAGE_SIZE;
                   1469: 
                   1470:                task_lock(task);
                   1471:                basic_info->policy = task->policy;
                   1472:                basic_info->suspend_count = task->user_stop_count;
                   1473:                basic_info->user_time.seconds
                   1474:                                = task->total_user_time.seconds;
                   1475:                basic_info->user_time.microseconds
                   1476:                                = task->total_user_time.microseconds;
                   1477:                basic_info->system_time.seconds
                   1478:                                = task->total_system_time.seconds;
                   1479:                basic_info->system_time.microseconds 
                   1480:                                = task->total_system_time.microseconds;
                   1481:                task_unlock(task);
                   1482: 
                   1483:                *task_info_count = TASK_BASIC_INFO_COUNT;
                   1484:                break;
                   1485:            }
                   1486: 
                   1487:            case TASK_THREAD_TIMES_INFO:
                   1488:            {
                   1489:                register task_thread_times_info_t times_info;
                   1490:                register thread_t       thread;
                   1491:                register thread_act_t   thr_act;
                   1492: 
                   1493:                if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
                   1494:                    return (KERN_INVALID_ARGUMENT);
                   1495:                }
                   1496: 
                   1497:                times_info = (task_thread_times_info_t) task_info_out;
                   1498:                times_info->user_time.seconds = 0;
                   1499:                times_info->user_time.microseconds = 0;
                   1500:                times_info->system_time.seconds = 0;
                   1501:                times_info->system_time.microseconds = 0;
                   1502: 
                   1503:                task_lock(task);
                   1504:                queue_iterate(&task->thr_acts, thr_act,
                   1505:                              thread_act_t, thr_acts)
                   1506:                {
                   1507:                    time_value_t user_time, system_time;
                   1508:                    spl_t        s;
                   1509: 
                   1510:                    thread = act_lock_thread(thr_act);
                   1511: 
                   1512:                    /* Skip empty threads and threads that have migrated
                   1513:                     * into this task:
                   1514:                     */
                   1515:                    if (thr_act->pool_port) {
                   1516:                        act_unlock_thread(thr_act);
                   1517:                        continue;
                   1518:                    }
                   1519:                    assert(thread);  /* Must have thread, if no thread_pool*/
                   1520:                    s = splsched();
                   1521:                    thread_lock(thread);
                   1522: 
                   1523:                    thread_read_times(thread, &user_time, &system_time);
                   1524: 
                   1525:                    thread_unlock(thread);
                   1526:                    splx(s);
                   1527:                    act_unlock_thread(thr_act);
                   1528: 
                   1529:                    time_value_add(&times_info->user_time, &user_time);
                   1530:                    time_value_add(&times_info->system_time, &system_time);
                   1531:                }
                   1532:                task_unlock(task);
                   1533: 
                   1534:                *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
                   1535:                break;
                   1536:            }
                   1537: 
                   1538:            case TASK_SCHED_FIFO_INFO:
                   1539:            {
                   1540:                register policy_fifo_base_t     fifo_base;
                   1541: 
                   1542:                if (*task_info_count < POLICY_FIFO_BASE_COUNT)
                   1543:                        return(KERN_INVALID_ARGUMENT);
                   1544: 
                   1545:                fifo_base = (policy_fifo_base_t) task_info_out;
                   1546: 
                   1547:                task_lock(task);
                   1548:                if (task->policy != POLICY_FIFO) {
                   1549:                        task_unlock(task);
                   1550:                        return(KERN_INVALID_POLICY);
                   1551:                }
                   1552:                /*** ??? fix me ***/
                   1553:                assert(task->sp_attributes != SP_ATTRIBUTES_NULL);
                   1554:                fifo_base->base_priority =
                   1555:                        ((mk_sp_attributes_t)task->sp_attributes)->priority;
                   1556:                task_unlock(task);
                   1557: 
                   1558:                *task_info_count = POLICY_FIFO_BASE_COUNT;
                   1559:                break;
                   1560:            }
                   1561: 
                   1562:            case TASK_SCHED_RR_INFO:
                   1563:            {
                   1564:                register policy_rr_base_t       rr_base;
                   1565: 
                   1566:                if (*task_info_count < POLICY_RR_BASE_COUNT)
                   1567:                        return(KERN_INVALID_ARGUMENT);
                   1568: 
                   1569:                rr_base = (policy_rr_base_t) task_info_out;
                   1570: 
                   1571:                task_lock(task);
                   1572:                if (task->policy != POLICY_RR) {
                   1573:                        task_unlock(task);
                   1574:                        return(KERN_INVALID_POLICY);
                   1575:                }
                   1576:                /*** ??? fix me ***/
                   1577:                assert(task->sp_attributes != SP_ATTRIBUTES_NULL);
                   1578:                rr_base->base_priority =
                   1579:                        ((mk_sp_attributes_t)task->sp_attributes)->priority;
                   1580:                rr_base->quantum =
                   1581:                        (((mk_sp_attributes_t)task->sp_attributes)->sched_data
                   1582:                                                        * tick) / 1000;
                   1583:                task_unlock(task);
                   1584: 
                   1585:                *task_info_count = POLICY_RR_BASE_COUNT;
                   1586:                break;
                   1587:            }
                   1588: 
                   1589:            case TASK_SCHED_TIMESHARE_INFO:
                   1590:            {
                   1591:                register policy_timeshare_base_t        ts_base;
                   1592: 
                   1593:                if (*task_info_count < POLICY_TIMESHARE_BASE_COUNT)
                   1594:                        return(KERN_INVALID_ARGUMENT);
                   1595: 
                   1596:                ts_base = (policy_timeshare_base_t) task_info_out;
                   1597: 
                   1598:                task_lock(task);
                   1599:                if (task->policy != POLICY_TIMESHARE) {
                   1600:                        task_unlock(task);
                   1601:                        return(KERN_INVALID_POLICY);
                   1602:                }
                   1603:                /*** ??? fix me ***/
                   1604:                assert(task->sp_attributes != SP_ATTRIBUTES_NULL);
                   1605:                ts_base->base_priority =
                   1606:                        ((mk_sp_attributes_t)task->sp_attributes)->priority;
                   1607:                task_unlock(task);
                   1608: 
                   1609:                *task_info_count = POLICY_TIMESHARE_BASE_COUNT;
                   1610:                break;
                   1611:            }
                   1612: 
                   1613:             case TASK_SECURITY_TOKEN:
                   1614:            {
                   1615:                 register security_token_t      *sec_token_p;
                   1616: 
                   1617:                if (*task_info_count < TASK_SECURITY_TOKEN_COUNT) {
                   1618:                    return(KERN_INVALID_ARGUMENT);
                   1619:                }
                   1620: 
                   1621:                sec_token_p = (security_token_t *) task_info_out;
                   1622: 
                   1623:                task_lock(task);
                   1624:                *sec_token_p = task->sec_token;
                   1625:                task_unlock(task);
                   1626: 
                   1627:                *task_info_count = TASK_SECURITY_TOKEN_COUNT;
                   1628:                 break;
                   1629:             }
                   1630:             
                   1631:            case TASK_SCHED_INFO:
                   1632:            {
                   1633:                        int             count = sched_policy[task->policy].sched_attributes_size;
                   1634: 
                   1635:                        if (*task_info_count < (((count-1)/sizeof(int)) + 1))
                   1636:                                return(KERN_INVALID_ARGUMENT);
                   1637: 
                   1638:                        task_lock(task);
                   1639: 
                   1640:                        bcopy((char *)task->sp_attributes,
                   1641:                                  (char *)task_info_out,
                   1642:                                  count);
                   1643: 
                   1644:                        task_unlock(task);
                   1645: 
                   1646:                        *task_info_count = count;
                   1647:                        break;
                   1648:            }
                   1649: 
                   1650:            case TASK_EVENTS_INFO:
                   1651:            {
                   1652:                register task_events_info_t     events_info;
                   1653: 
                   1654:                if (*task_info_count < TASK_EVENTS_INFO_COUNT) {
                   1655:                    return(KERN_INVALID_ARGUMENT);
                   1656:                }
                   1657: 
                   1658:                events_info = (task_events_info_t) task_info_out;
                   1659: 
                   1660:                task_lock(task);
                   1661:                events_info->faults = task->faults;
                   1662:                events_info->pageins = task->pageins;
                   1663:                events_info->cow_faults = task->cow_faults;
                   1664:                events_info->messages_sent = task->messages_sent;
                   1665:                events_info->messages_received = task->messages_received;
                   1666:                events_info->syscalls_mach = task->syscalls_mach;
                   1667:                events_info->syscalls_unix = task->syscalls_unix;
                   1668:                events_info->csw = task->csw;
                   1669:                task_unlock(task);
                   1670: 
                   1671:                *task_info_count = TASK_EVENTS_INFO_COUNT;
                   1672:                break;
                   1673:            }
                   1674: 
                   1675:            default:
                   1676:                return (KERN_INVALID_ARGUMENT);
                   1677:        }
                   1678: 
                   1679:        return(KERN_SUCCESS);
                   1680: }
                   1681: 
                   1682: #if    MACH_HOST
                   1683: 
                   1684: /*
                   1685:  *     task_assign:
                   1686:  *
                   1687:  *     Change the assigned processor set for the task
                   1688:  */
                   1689: kern_return_t
                   1690: task_assign(
                   1691:        task_t                          task,
                   1692:        processor_set_t                 new_pset,
                   1693:        boolean_t                       assign_threads)
                   1694: {
                   1695:        kern_return_t                   ret = KERN_SUCCESS;
                   1696:        register thread_t               thread, prev_thread;
                   1697:        register queue_head_t           *list;
                   1698:        register processor_set_t        pset;
                   1699:        int                             max_priority;
                   1700: 
                   1701:        if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) {
                   1702:                return(KERN_INVALID_ARGUMENT);
                   1703:        }
                   1704: 
                   1705:        task_lock(task);
                   1706: 
                   1707:        /*
                   1708:         *      If may_assign is false, task is already being assigned,
                   1709:         *      wait for that to finish.
                   1710:         */
                   1711:        while (task->may_assign == FALSE) {
                   1712:                task->assign_active = TRUE;
                   1713:                assert_wait((event_t)&task->assign_active, THREAD_ABORTSAFE);
                   1714:                task_unlock(task);
                   1715:                thread_block((void (*)(void)) 0);
                   1716:                task_lock(task);
                   1717:        }
                   1718: 
                   1719:        /*
                   1720:         *      Do assignment.  If new pset is dead, redirect to default.
                   1721:         */
                   1722:        pset = task->processor_set;
                   1723:        pset_lock(pset);
                   1724:        pset_remove_task(pset,task);
                   1725:        pset_unlock(pset);
                   1726:        pset_deallocate(pset);
                   1727: 
                   1728:        pset_lock(new_pset);
                   1729:        if (!new_pset->active) {
                   1730:            pset_unlock(new_pset);
                   1731:            new_pset = &default_pset;
                   1732:            pset_lock(new_pset);
                   1733:        }
                   1734: 
                   1735:         /*
                   1736:          *      Reset policy and priorities if needed.
                   1737:          *
                   1738:          *      There are three rules for tasks under assignment:
                   1739:          *
                   1740:          *      (1) If the new pset has the old policy enabled, keep the
                   1741:          *          old policy. Otherwise, use the default policy for the pset.
                   1742:          *      (2) The new limits will be the pset limits for the new policy.
                   1743:          *      (3) The new base will be the same as the old base unless either
                   1744:          *              (a) the new policy changed to the pset default policy;
                   1745:          *                  in this case, the new base is the default policy
                   1746:          *                  base,
                   1747:          *          or
                   1748:          *              (b) the new limits are different from the old limits;
                   1749:          *                  in this case, the new base is the new limits.
                   1750:          */
                   1751:         max_priority = pset_max_priority(new_pset, task->policy);
                   1752:         if ((task->policy & new_pset->policies) == 0) {
                   1753:                 task->policy = new_pset->policy_default;
                   1754:                task->sched_data = pset_sched_data(new_pset, task->policy);
                   1755:                 task->priority = pset_base_priority(new_pset, task->policy);
                   1756:                max_priority = pset_max_priority(new_pset, task->policy);
                   1757:         }
                   1758:         else if (task->max_priority != max_priority) {
                   1759:                 task->priority = max_priority;
                   1760:         }
                   1761: 
                   1762:         task->max_priority = max_priority;
                   1763: 
                   1764:        pset_add_task(new_pset,task);
                   1765:        pset_unlock(new_pset);
                   1766: 
                   1767:        if (assign_threads == FALSE) {
                   1768:                task_unlock(task);
                   1769:                return(KERN_SUCCESS);
                   1770:        }
                   1771: 
                   1772:        /*
                   1773:         *      Now freeze this assignment while we get the threads
                   1774:         *      to catch up to it.
                   1775:         */
                   1776:        task->may_assign = FALSE;
                   1777: 
                   1778:        /*
                   1779:         *      If current thread is in task, freeze its assignment.
                   1780:         */
                   1781:        if (current_act()->task == task) {
                   1782:                task_unlock(task);
                   1783:                thread_freeze(current_thread());
                   1784:                task_lock(task);
                   1785:        }
                   1786: 
                   1787:        /*
                   1788:         *      Iterate down the thread list reassigning all the threads.
                   1789:         *      ("Base" threads only, please; psets belong to them)
                   1790:         *      New threads pick up task's new processor set automatically.
                   1791:         *      Do current thread last because new pset may be empty.
                   1792:         */
                   1793:        {   thread_act_t        thr_act;
                   1794:            int i;
                   1795: 
                   1796:            prev_thread = THREAD_NULL;
                   1797:            for (i = 0, thr_act = (thread_act_t) queue_first(&task->thr_acts);
                   1798:                i < task->thr_act_count;
                   1799:                i++, thr_act = (thread_act_t)queue_next(&thr_act->thr_acts)) {
                   1800: 
                   1801:                    thread = act_lock_thread(thr_act);
                   1802:                    if (thr_act->pool_port) {
                   1803:                        act_unlock_thread(thr_act);
                   1804:                        continue;
                   1805:                    }
                   1806:                    if (!(task->active)) {
                   1807:                        ret = KERN_FAILURE;
                   1808:                        act_unlock_thread(thr_act);
                   1809:                        break;
                   1810:                    }
                   1811:                    assert(thread);
                   1812:                    if (thread == current_thread())
                   1813:                        act_unlock_thread(thr_act);
                   1814:                    else {
                   1815:                        thread_reference(thread);
                   1816:                        task_unlock(task);
                   1817:                        if (prev_thread != THREAD_NULL)
                   1818:                            thread_deallocate(prev_thread); /* may block */
                   1819:                        assert(thread->top_act);
                   1820:                        assert(thread->top_act->thread == thread);
                   1821:                        /*
                   1822:                         * Inline thread_assign() here to avoid silly double
                   1823:                         * conversion.
                   1824:                         */
                   1825:                        thread_freeze(thread);
                   1826:                        thread_doassign(thread, new_pset, TRUE);
                   1827:                        /*
                   1828:                         * All thread-related locks released at this point.
                   1829:                         */
                   1830:                        prev_thread = thread;
                   1831:                        task_lock(task);
                   1832:                    }
                   1833:            }
                   1834:            assert(queue_end(&task->thr_acts, (queue_entry_t)thr_act));
                   1835:        }
                   1836: 
                   1837:        /*
                   1838:         *      Done, wakeup anyone waiting for us.
                   1839:         */
                   1840:        task->may_assign = TRUE;
                   1841:        if (task->assign_active) {
                   1842:                task->assign_active = FALSE;
                   1843:                thread_wakeup((event_t)&task->assign_active);
                   1844:        }
                   1845:        task_unlock(task);
                   1846:        if (prev_thread != THREAD_NULL)
                   1847:                thread_deallocate(prev_thread);         /* may block */
                   1848: 
                   1849:        /*
                   1850:         *      Finish assignment of current thread.
                   1851:         */
                   1852:        if (current_act()->task == task) {
                   1853:                thread = act_lock_thread(current_act());
                   1854:                thread_doassign(thread, new_pset, TRUE);
                   1855:                /*
                   1856:                 * All thread-related locks released at this point.
                   1857:                 */
                   1858:        }
                   1859: 
                   1860:        return(ret);
                   1861: }
                   1862: #else  /* MACH_HOST */
                   1863: /*
                   1864:  *     task_assign:
                   1865:  *
                   1866:  *     Change the assigned processor set for the task
                   1867:  */
                   1868: kern_return_t
                   1869: task_assign(
                   1870:        task_t          task,
                   1871:        processor_set_t new_pset,
                   1872:        boolean_t       assign_threads)
                   1873: {
                   1874: #ifdef lint
                   1875:        task++; new_pset++; assign_threads++;
                   1876: #endif /* lint */
                   1877:        return(KERN_FAILURE);
                   1878: }
                   1879: #endif /* MACH_HOST */
                   1880:        
                   1881: 
                   1882: /*
                   1883:  *     task_assign_default:
                   1884:  *
                   1885:  *     Version of task_assign to assign to default processor set.
                   1886:  */
                   1887: kern_return_t
                   1888: task_assign_default(
                   1889:        task_t          task,
                   1890:        boolean_t       assign_threads)
                   1891: {
                   1892:     return (task_assign(task, &default_pset, assign_threads));
                   1893: }
                   1894: 
                   1895: /*
                   1896:  *     task_get_assignment
                   1897:  *
                   1898:  *     Return name of processor set that task is assigned to.
                   1899:  */
                   1900: kern_return_t
                   1901: task_get_assignment(
                   1902:        task_t          task,
                   1903:        processor_set_t *pset)
                   1904: {
                   1905:        if (!task->active)
                   1906:                return(KERN_FAILURE);
                   1907: 
                   1908:        *pset = task->processor_set;
                   1909:        pset_reference(*pset);
                   1910:        return(KERN_SUCCESS);
                   1911: }
                   1912: 
                   1913: 
                   1914: /*
                   1915:  *     task_policy
                   1916:  *
                   1917:  *     Set scheduling policy and parameters, both base and limit, for
                   1918:  *     the given task. Policy must be a policy which is enabled for the
                   1919:  *     processor set. Change contained threads if requested. 
                   1920:  */
                   1921: kern_return_t
                   1922: task_policy(
                   1923:        task_t                                  task,
                   1924:        policy_t                                policy_id,
                   1925:        policy_base_t                   base,
                   1926:        mach_msg_type_number_t  count,
                   1927:        boolean_t                               set_limit,
                   1928:        boolean_t                               change)
                   1929: {
                   1930:        policy_limit_t                  limit;
                   1931:        int                                             limcount;
                   1932:        processor_set_t                 pset;
                   1933:        kern_return_t                   result = KERN_SUCCESS;
                   1934:        sched_policy_t                  *policy;
                   1935: 
                   1936:        if (    task == TASK_NULL                                                                       ||
                   1937:                        (pset = task->processor_set) == PROCESSOR_SET_NULL              )
                   1938:                return(KERN_INVALID_ARGUMENT);
                   1939: 
                   1940:        if (invalid_policy(policy_id) || (pset->policies & policy_id) == 0)
                   1941:                return(KERN_INVALID_POLICY);
                   1942: 
                   1943:        /* call policy-specific routine */
                   1944:        policy = &sched_policy[policy_id];
                   1945:        result = policy->sp_ops.
                   1946:                                        sp_task_policy(policy, task, policy_id,
                   1947:                                                        base, count, set_limit, change, &limit, &limcount);
                   1948: 
                   1949:        if (result != KERN_SUCCESS) 
                   1950:                return(result);
                   1951: 
                   1952:        result = task_set_policy(task, pset, policy_id,
                   1953:                                                                base, count, limit, limcount, change);
                   1954:        
                   1955:        return(result);
                   1956: }
                   1957: 
                   1958: /*
                   1959:  *     task_set_policy
                   1960:  *
                   1961:  *     Set scheduling policy and parameters, both base and limit, for 
                   1962:  *     the given task. Policy can be any policy implemented by the
                   1963:  *     processor set, whether enabled or not. Change contained threads
                   1964:  *     if requested.
                   1965:  */
                   1966: kern_return_t
                   1967: task_set_policy(
                   1968:        task_t                                  task,
                   1969:        processor_set_t                 pset,
                   1970:        policy_t                                policy_id,
                   1971:        policy_base_t                   base,
                   1972:        mach_msg_type_number_t  base_count,
                   1973:        policy_limit_t                  limit,
                   1974:        mach_msg_type_number_t  limit_count,
                   1975:        boolean_t                               change)
                   1976: {
                   1977:        kern_return_t                   result = KERN_SUCCESS;
                   1978:        sched_policy_t                  *policy;
                   1979: 
                   1980:        if (task == TASK_NULL || pset == PROCESSOR_SET_NULL)
                   1981:                return(KERN_INVALID_ARGUMENT);
                   1982: 
                   1983:        if (pset != task->processor_set)
                   1984:                return(KERN_FAILURE);
                   1985: 
                   1986:        task_lock(task);
                   1987: 
                   1988:        /* call policy-specific routine */
                   1989:        policy = &sched_policy[policy_id];
                   1990:        result = policy->sp_ops.
                   1991:                                        sp_task_set_policy(policy, task, pset, policy_id,
                   1992:                                                                base, base_count, limit, limit_count, change);
                   1993: 
                   1994:        if (result != KERN_SUCCESS) {
                   1995:                task_unlock(task);
                   1996:                return(result);
                   1997:        }
                   1998: 
                   1999:        if (change) {
                   2000:                register thread_act_t   thr_act;
                   2001:                register queue_head_t   *list;
                   2002: 
                   2003:                list = &task->thr_acts;
                   2004:                thr_act = (thread_act_t) queue_first(list);
                   2005:                while (!queue_end(list, (queue_entry_t) thr_act)) {
                   2006:                        /*** ??? fix to call policy-dependent routine ***/
                   2007:                        thread_set_policy(thr_act, pset, policy_id,
                   2008:                                                          base, base_count,
                   2009:                                                          limit, limit_count);
                   2010:                        thr_act = (thread_act_t)queue_next(&thr_act->thr_acts);
                   2011:                }
                   2012:        }
                   2013: 
                   2014:        task_unlock(task);
                   2015:        return(result);
                   2016: }
                   2017: 
                   2018: /*
                   2019:  *     task_set_sched
                   2020:  *
                   2021:  *      Set scheduling policy and parameters for the given task.
                   2022:  *      Policy must be a policy which is enabled for the
                   2023:  *      processor set. Change contained threads if requested.
                   2024:  *      (This should replace `task_policy()' with the addition
                   2025:  *      of the MK Scheduling Framework to the kernel.)
                   2026:  */
                   2027: kern_return_t
                   2028: task_set_sched(
                   2029:        task_t                                  task,
                   2030:        policy_t                                policy_id,
                   2031:        sched_attr_t                    sched_attr,
                   2032:        mach_msg_type_number_t  sched_attrCnt,
                   2033:        boolean_t                               set_limit,
                   2034:        boolean_t                               change)
                   2035: {
                   2036:        processor_set_t                 pset;
                   2037:        sched_policy_t                  *policy;
                   2038: 
                   2039:        if (    task == TASK_NULL                                                                       ||
                   2040:                        (pset = task->processor_set) == PROCESSOR_SET_NULL              )
                   2041:                return(KERN_INVALID_ARGUMENT);
                   2042: 
                   2043:        if (invalid_policy(policy_id) || (pset->policies & policy_id) == 0)
                   2044:                return(KERN_INVALID_POLICY);
                   2045: 
                   2046:        /* call policy-specific routine */
                   2047:        policy = &sched_policy[policy_id];
                   2048:        return (policy->sp_ops.sp_task_set_sched(policy, task, policy_id,
                   2049:                                                                sched_attr, sched_attrCnt, set_limit, change));
                   2050: }
                   2051: 
                   2052: 
                   2053: /*
                   2054:  *     task_get_sched
                   2055:  *
                   2056:  *      Get scheduling policy and parameters for the given task.
                   2057:  *      (This was added as part of the MK Scheduling Framework.)
                   2058:  */
                   2059: kern_return_t
                   2060: task_get_sched(
                   2061:        task_t                                  task,
                   2062:        policy_t                                policy_id,
                   2063:        sched_attr_t                    sched_attr,
                   2064:        mach_msg_type_number_t  sched_attrCnt,
                   2065:        int                                             sched_attr_size)
                   2066: {
                   2067:        processor_set_t                 pset;
                   2068:        sched_policy_t                  *policy;
                   2069: 
                   2070:        if (    task == TASK_NULL                                                                       ||
                   2071:                        (pset = task->processor_set) == PROCESSOR_SET_NULL              )
                   2072:                return(KERN_INVALID_ARGUMENT);
                   2073: 
                   2074:        /* call policy-specific routine */
                   2075:        policy = &sched_policy[task->policy];
                   2076:        return (policy->sp_ops.sp_task_get_sched(policy, task, policy_id,
                   2077:                                                                sched_attr, sched_attrCnt, sched_attr_size));
                   2078: }
                   2079: 
                   2080: 
                   2081: /*
                   2082:  *     task_collect_scan:
                   2083:  *
                   2084:  *     Attempt to free resources owned by tasks.
                   2085:  */
                   2086: 
                   2087: void
                   2088: task_collect_scan(void)
                   2089: {
                   2090:        register task_t         task, prev_task;
                   2091:        processor_set_t         pset, prev_pset;
                   2092: 
                   2093:        prev_task = TASK_NULL;
                   2094:        prev_pset = PROCESSOR_SET_NULL;
                   2095: 
                   2096:        mutex_lock(&all_psets_lock);
                   2097:        pset = (processor_set_t) queue_first(&all_psets);
                   2098:        while (!queue_end(&all_psets, (queue_entry_t) pset)) {
                   2099:                pset_lock(pset);
                   2100:                task = (task_t) queue_first(&pset->tasks);
                   2101:                while (!queue_end(&pset->tasks, (queue_entry_t) task)) {
                   2102:                        task_reference(task);
                   2103:                        pset->ref_count++;
                   2104:                        pset_unlock(pset);
                   2105:                        mutex_unlock(&all_psets_lock);
                   2106: 
                   2107:                        pmap_collect(task->map->pmap);
                   2108: 
                   2109:                        if (prev_task != TASK_NULL)
                   2110:                                task_deallocate(prev_task);
                   2111:                        prev_task = task;
                   2112: 
                   2113:                        if (prev_pset != PROCESSOR_SET_NULL)
                   2114:                                pset_deallocate(prev_pset);
                   2115:                        prev_pset = pset;
                   2116: 
                   2117:                        mutex_lock(&all_psets_lock);
                   2118:                        pset_lock(pset);
                   2119:                        task = (task_t) queue_next(&task->pset_tasks);
                   2120:                }
                   2121:                pset_unlock(pset);
                   2122:                pset = (processor_set_t) queue_next(&pset->all_psets);
                   2123:        }
                   2124:        mutex_unlock(&all_psets_lock);
                   2125: 
                   2126:        if (prev_task != TASK_NULL)
                   2127:                task_deallocate(prev_task);
                   2128:        if (prev_pset != PROCESSOR_SET_NULL)
                   2129:                pset_deallocate(prev_pset);
                   2130: }
                   2131: 
                   2132: boolean_t task_collect_allowed = TRUE;
                   2133: unsigned task_collect_last_tick = 0;
                   2134: unsigned task_collect_max_rate = 0;            /* in ticks */
                   2135: 
                   2136: /*
                   2137:  *     consider_task_collect:
                   2138:  *
                   2139:  *     Called by the pageout daemon when the system needs more free pages.
                   2140:  */
                   2141: 
                   2142: void
                   2143: consider_task_collect(void)
                   2144: {
                   2145:        /*
                   2146:         *      By default, don't attempt task collection more frequently
                   2147:         *      than once a second (a scheduler tick).
                   2148:         */
                   2149: 
                   2150:        if (task_collect_max_rate == 0)
                   2151:                task_collect_max_rate = 2;              /* sched_tick is a 1 second resolution 2 here insures at least 1 second interval */
                   2152: 
                   2153:        if (task_collect_allowed &&
                   2154:            (sched_tick > (task_collect_last_tick + task_collect_max_rate))) {
                   2155:                task_collect_last_tick = sched_tick;
                   2156:                task_collect_scan();
                   2157:        }
                   2158: }
                   2159: 
                   2160: kern_return_t
                   2161: task_set_ras_pc(
                   2162:        task_t          task,
                   2163:        vm_offset_t     pc,
                   2164:        vm_offset_t     endpc)
                   2165: {
                   2166: #if    FAST_TAS
                   2167:        extern int fast_tas_debug;
                   2168:  
                   2169:        if (fast_tas_debug) {
                   2170:                printf("task 0x%x: setting fast_tas to [0x%x, 0x%x]\n",
                   2171:                       task, pc, endpc);
                   2172:        }
                   2173:        task_lock(task);
                   2174:        task->fast_tas_base = pc;
                   2175:        task->fast_tas_end =  endpc;
                   2176:        task_unlock(task);
                   2177:        return KERN_SUCCESS;
                   2178:  
                   2179: #else  /* FAST_TAS */
                   2180: #ifdef lint
                   2181:        task++;
                   2182:        pc++;
                   2183:        endpc++;
                   2184: #endif /* lint */
                   2185:  
                   2186:        return KERN_FAILURE;
                   2187:  
                   2188: #endif /* FAST_TAS */
                   2189: }
                   2190: 
                   2191: void
                   2192: task_synchronizer_destroy_all(task_t task)
                   2193: {
                   2194:        semaphore_t     semaphore;
                   2195:        lock_set_t      lock_set;
                   2196: 
                   2197:        /*
                   2198:         *  Destroy owned semaphores
                   2199:         */
                   2200: 
                   2201:        while (!queue_empty(&task->semaphore_list)) {
                   2202:                semaphore = (semaphore_t) queue_first(&task->semaphore_list);
                   2203:                (void) semaphore_destroy(task, semaphore);
                   2204:        }
                   2205: 
                   2206:        /*
                   2207:         *  Destroy owned lock sets
                   2208:         */
                   2209: 
                   2210:        while (!queue_empty(&task->lock_set_list)) {
                   2211:                lock_set = (lock_set_t) queue_first(&task->lock_set_list);
                   2212:                (void) lock_set_destroy(task, lock_set);
                   2213:        }
                   2214: }
                   2215: 
                   2216: void
                   2217: task_subsystem_destroy_all(task_t task)
                   2218: {
                   2219:        subsystem_t     subsystem;
                   2220: 
                   2221:        /*
                   2222:         *  Destroy owned subsystems
                   2223:         */
                   2224: 
                   2225:        while (!queue_empty(&task->subsystem_list)) {
                   2226:                subsystem = (subsystem_t) queue_first(&task->subsystem_list);
                   2227:                subsystem_deallocate(subsystem);
                   2228:        }
                   2229: }
                   2230: 
                   2231: /*
                   2232:  *     task_set_port_space:
                   2233:  *
                   2234:  *     Set port name space of task to specified size.
                   2235:  */
                   2236: 
                   2237: kern_return_t
                   2238: task_set_port_space(
                   2239:        task_t          task,
                   2240:        int             table_entries)
                   2241: {
                   2242:        kern_return_t kr;
                   2243:        
                   2244:        is_write_lock(task->itk_space);
                   2245:        kr = ipc_entry_grow_table(task->itk_space, table_entries);
                   2246:        if (kr == KERN_SUCCESS)
                   2247:                is_write_unlock(task->itk_space);
                   2248:        return kr;
                   2249: }
                   2250: 
                   2251: /*
                   2252:  * We need to export some functions to other components that
                   2253:  * are currently implemented in macros within the osfmk
                   2254:  * component.  Just export them as functions of the same name.
                   2255:  */
                   2256: boolean_t is_kerneltask(task_t t)
                   2257: {
                   2258:        if (t == kernel_task)
                   2259:                return(TRUE);
                   2260:        else
                   2261:                return((t->kernel_loaded));
                   2262: }
                   2263: 
                   2264: #undef current_task
                   2265: task_t current_task()
                   2266: {
                   2267:        return (current_task_fast());
                   2268: }

unix.superglobalmegacorp.com

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