Annotation of XNU/osfmk/kern/task.c, revision 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.