Annotation of kernel/kern/task.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1993-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: #include <mach_host.h>
        !            59: #include <norma_task.h>
        !            60: 
        !            61: #include <mach/machine/vm_types.h>
        !            62: #include <mach/vm_param.h>
        !            63: #include <mach/task_info.h>
        !            64: #include <mach/task_special_ports.h>
        !            65: #include <ipc/ipc_space.h>
        !            66: #include <kern/mach_param.h>
        !            67: #include <kern/task.h>
        !            68: #include <kern/thread.h>
        !            69: #include <kern/zalloc.h>
        !            70: #include <kern/kalloc.h>
        !            71: #include <kern/processor.h>
        !            72: #include <kern/sched_prim.h>   /* for thread_wakeup */
        !            73: #include <kern/ipc_tt.h>
        !            74: #include <vm/vm_kern.h>                /* for kernel_map, ipc_kernel_map */
        !            75: 
        !            76: #if    NORMA_TASK
        !            77: #define        task_create     task_create_local
        !            78: #endif /* NORMA_TASK */
        !            79: 
        !            80: task_t kernel_task = TASK_NULL;
        !            81: zone_t task_zone;
        !            82: 
        !            83: extern zone_t  u_task_zone;    /* UNIX */
        !            84: 
        !            85: void task_init(void)
        !            86: {
        !            87:        task_zone = zinit(
        !            88:                        sizeof(struct task),
        !            89:                        TASK_MAX * sizeof(struct task),
        !            90:                        TASK_CHUNK * sizeof(struct task),
        !            91:                        FALSE, "tasks");
        !            92: 
        !            93:        /*
        !            94:         * Create the kernel task as the first task.
        !            95:         * Task_create must assign to kernel_task as a side effect,
        !            96:         * for other initialization. (:-()
        !            97:         */
        !            98:        (void) task_create(TASK_NULL, FALSE, &kernel_task);
        !            99: 
        !           100:        kernel_task->kernel_privilege = TRUE;
        !           101:        kernel_task->kernel_vm_space = TRUE;
        !           102: }
        !           103: 
        !           104: /*
        !           105:  * Create a task running in the kernel address space.  It may
        !           106:  * have its own map of size mem_size (if 0, it uses the kernel map),
        !           107:  * and may have ipc privileges.
        !           108:  */
        !           109: task_t kernel_task_create(
        !           110:        task_t          parent_task,
        !           111:        vm_size_t       map_size)
        !           112: {
        !           113:        task_t          new_task;
        !           114:        vm_offset_t     min, max;
        !           115: 
        !           116:        /*
        !           117:         * Create the task.
        !           118:         */
        !           119:        (void) task_create(parent_task, FALSE, &new_task);
        !           120:        task_deallocate(new_task); // extra ref for convert_task_to_port()
        !           121: 
        !           122:        /*
        !           123:         * Task_create creates the task with a user-space map.
        !           124:         * Remove the map and replace it with the kernel map
        !           125:         * or a submap of the kernel map.
        !           126:         */
        !           127:        vm_map_deallocate(new_task->map);
        !           128:        if (map_size == 0)
        !           129:            new_task->map = kernel_map;
        !           130:        else
        !           131:            new_task->map = kmem_suballoc(kernel_map, &min, &max,
        !           132:                                          map_size, FALSE);
        !           133:                                          
        !           134:        new_task->kernel_vm_space = TRUE;
        !           135: 
        !           136:        return new_task;
        !           137: }
        !           138: 
        !           139: kern_return_t task_create(
        !           140:        task_t          parent_task,
        !           141:        boolean_t       inherit_memory,
        !           142:        task_t          *child_task)            /* OUT */
        !           143: {
        !           144:        register task_t new_task;
        !           145:        register processor_set_t        pset;
        !           146:        int i;
        !           147: 
        !           148:        new_task = (task_t) zalloc(task_zone);
        !           149:        if (new_task == TASK_NULL) {
        !           150:                panic("task_create: no memory for task structure");
        !           151:        }
        !           152: 
        !           153:        /* one ref for just being alive; one for our caller */
        !           154:        new_task->ref_count = 2;
        !           155: 
        !           156:        if (child_task == &kernel_task)  {
        !           157:                new_task->map = kernel_map; 
        !           158:        } else if (inherit_memory) {
        !           159:                new_task->map = vm_map_fork(parent_task->map);
        !           160:        } else {
        !           161:                new_task->map = vm_map_create(pmap_create(0),
        !           162:                                        round_page(VM_MIN_ADDRESS),
        !           163:                                        trunc_page(VM_MAX_ADDRESS), TRUE);
        !           164:        }
        !           165: 
        !           166:        simple_lock_init(&new_task->lock);
        !           167:        queue_init(&new_task->thread_list);
        !           168:        simple_lock_init(&new_task->thread_list_lock);
        !           169:        new_task->suspend_count = 0;
        !           170:        new_task->active = TRUE;
        !           171:        new_task->user_stop_count = 0;
        !           172:        new_task->thread_count = 0;
        !           173:        
        !           174:        new_task->pcb_common = 0;
        !           175:        pcb_common_init(new_task);
        !           176: 
        !           177:        new_task->proc = 0;
        !           178: 
        !           179:        new_task->kernel_vm_space = FALSE;
        !           180: 
        !           181:        ipc_task_init(new_task, parent_task);
        !           182: 
        !           183:        new_task->total_user_time.seconds = 0;
        !           184:        new_task->total_user_time.microseconds = 0;
        !           185:        new_task->total_system_time.seconds = 0;
        !           186:        new_task->total_system_time.microseconds = 0;
        !           187: 
        !           188:        if (parent_task != TASK_NULL) {
        !           189:                new_task->kernel_privilege = parent_task->kernel_privilege;
        !           190:                task_lock(parent_task);
        !           191:                pset = parent_task->processor_set;
        !           192:                if (!pset->active)
        !           193:                        pset = &default_pset;
        !           194:                pset_reference(pset);
        !           195:                new_task->priority = parent_task->priority;
        !           196:                task_unlock(parent_task);
        !           197:        }
        !           198:        else {
        !           199:                new_task->kernel_privilege = FALSE;
        !           200:                pset = &default_pset;
        !           201:                pset_reference(pset);
        !           202:                new_task->priority = BASEPRI_USER;
        !           203:        }
        !           204:        pset_lock(pset);
        !           205:        pset_add_task(pset, new_task);
        !           206:        pset_unlock(pset);
        !           207: 
        !           208:        new_task->may_assign = TRUE;
        !           209:        new_task->assign_active = FALSE;
        !           210:  
        !           211:        ipc_task_enable(new_task);
        !           212: 
        !           213: #if    NORMA_TASK
        !           214:        new_task->child_node = -1;
        !           215: #endif /* NORMA_TASK */
        !           216: 
        !           217:        *child_task = new_task;
        !           218:        return KERN_SUCCESS;
        !           219: }
        !           220: 
        !           221: /*
        !           222:  *     task_deallocate:
        !           223:  *
        !           224:  *     Give up a reference to the specified task and destroy it if there
        !           225:  *     are no other references left.  It is assumed that the current thread
        !           226:  *     is never in this task.
        !           227:  */
        !           228: void task_deallocate(
        !           229:        register task_t task)
        !           230: {
        !           231:        register int c;
        !           232:        register processor_set_t pset;
        !           233: 
        !           234:        if (task == TASK_NULL)
        !           235:                return;
        !           236: 
        !           237:        task_lock(task);
        !           238:        c = --(task->ref_count);
        !           239:        task_unlock(task);
        !           240:        if (c != 0)
        !           241:                return;
        !           242: 
        !           243: #if    NORMA_TASK
        !           244:        if (task->map == VM_MAP_NULL) {
        !           245:                /* norma placeholder task */
        !           246:                zfree(task_zone, (vm_offset_t) task);
        !           247:                return;
        !           248:        }
        !           249: #endif /* NORMA_TASK */
        !           250: 
        !           251:        pset = task->processor_set;
        !           252:        pset_lock(pset);
        !           253:        pset_remove_task(pset,task);
        !           254:        pset_unlock(pset);
        !           255:        pset_deallocate(pset);
        !           256:        vm_map_deallocate(task->map);
        !           257:        is_release(task->itk_space);
        !           258:        pcb_common_terminate(task);
        !           259:        zfree(task_zone, (vm_offset_t) task);
        !           260: }
        !           261: 
        !           262: void task_reference(
        !           263:        register task_t task)
        !           264: {
        !           265:        if (task == TASK_NULL)
        !           266:                return;
        !           267: 
        !           268:        task_lock(task);
        !           269:        task->ref_count++;
        !           270:        task_unlock(task);
        !           271: }
        !           272: 
        !           273: /*
        !           274:  *     task_terminate:
        !           275:  *
        !           276:  *     Terminate the specified task.  See comments on thread_terminate
        !           277:  *     (kern/thread.c) about problems with terminating the "current task."
        !           278:  */
        !           279: kern_return_t task_terminate(
        !           280:        register task_t task)
        !           281: {
        !           282:        register thread_t       thread, cur_thread;
        !           283:        register queue_head_t   *list;
        !           284:        register task_t         cur_task;
        !           285:        int                     s;
        !           286: 
        !           287:        if (task == TASK_NULL)
        !           288:                return KERN_INVALID_ARGUMENT;
        !           289: 
        !           290:        /* Disallow termination of U**X proc tasks */
        !           291:        if (task->proc)
        !           292:                return KERN_FAILURE;
        !           293: 
        !           294:        list = &task->thread_list;
        !           295:        cur_task = current_task();
        !           296:        cur_thread = current_thread();
        !           297: 
        !           298:        /*
        !           299:         *      Deactivate task so that it can't be terminated again,
        !           300:         *      and so lengthy operations in progress will abort.
        !           301:         *
        !           302:         *      If the current thread is in this task, remove it from
        !           303:         *      the task's thread list to keep the thread-termination
        !           304:         *      loop simple.
        !           305:         */
        !           306:        if (task == cur_task) {
        !           307:                task_lock(task);
        !           308:                if (!task->active) {
        !           309:                        /*
        !           310:                         *      Task is already being terminated.
        !           311:                         */
        !           312:                        task_unlock(task);
        !           313:                        return KERN_FAILURE;
        !           314:                }
        !           315:                /*
        !           316:                 *      Make sure current thread is not being terminated.
        !           317:                 */
        !           318:                s = splsched();
        !           319:                simple_lock(&task->thread_list_lock);
        !           320:                thread_lock(cur_thread);
        !           321:                if (!cur_thread->active) {
        !           322:                        thread_unlock(cur_thread);
        !           323:                        simple_unlock(&task->thread_list_lock);
        !           324:                        (void) splx(s);
        !           325:                        task_unlock(task);
        !           326:                        thread_terminate(cur_thread);
        !           327:                        return KERN_FAILURE;
        !           328:                }
        !           329:                task->active = FALSE;
        !           330:                queue_remove(list, cur_thread, thread_t, thread_list);
        !           331:                thread_unlock(cur_thread);
        !           332:                simple_unlock(&task->thread_list_lock);
        !           333:                (void) splx(s);
        !           334:                task_unlock(task);
        !           335: 
        !           336:                /*
        !           337:                 *      Shut down this thread's ipc now because it must
        !           338:                 *      be left alone to terminate the task.
        !           339:                 */
        !           340:                ipc_thread_disable(cur_thread);
        !           341:                ipc_thread_terminate(cur_thread);
        !           342:        }
        !           343:        else {
        !           344:                /*
        !           345:                 *      Lock both current and victim task to check for
        !           346:                 *      potential deadlock.
        !           347:                 */
        !           348:                if ((vm_offset_t)task < (vm_offset_t)cur_task) {
        !           349:                        task_lock(task);
        !           350:                        task_lock(cur_task);
        !           351:                }
        !           352:                else {
        !           353:                        task_lock(cur_task);
        !           354:                        task_lock(task);
        !           355:                }
        !           356:                /*
        !           357:                 *      Check if current thread or task is being terminated.
        !           358:                 */
        !           359:                s = splsched();
        !           360:                thread_lock(cur_thread);
        !           361:                if ((!cur_task->active) ||(!cur_thread->active)) {
        !           362:                        /*
        !           363:                         * Current task or thread is being terminated.
        !           364:                         */
        !           365:                        thread_unlock(cur_thread);
        !           366:                        (void) splx(s);
        !           367:                        task_unlock(task);
        !           368:                        task_unlock(cur_task);
        !           369:                        thread_terminate(cur_thread);
        !           370:                        return KERN_FAILURE;
        !           371:                }
        !           372:                thread_unlock(cur_thread);
        !           373:                (void) splx(s);
        !           374:                task_unlock(cur_task);
        !           375: 
        !           376:                if (!task->active) {
        !           377:                        /*
        !           378:                         *      Task is already being terminated.
        !           379:                         */
        !           380:                        task_unlock(task);
        !           381:                        return KERN_FAILURE;
        !           382:                }
        !           383:                task->active = FALSE;
        !           384:                task_unlock(task);
        !           385:        }
        !           386: 
        !           387:        /*
        !           388:         *      Prevent further execution of the task.  ipc_task_disable
        !           389:         *      prevents further task operations via the task port.
        !           390:         *      If this is the current task, the current thread will
        !           391:         *      be left running.
        !           392:         */
        !           393:        ipc_task_disable(task);
        !           394:        (void) task_hold(task);
        !           395:        (void) task_dowait(task,TRUE);                  /* may block */
        !           396: 
        !           397:        /*
        !           398:         *      Terminate each thread in the task.
        !           399:         *
        !           400:          *      The task_port is closed down, so no more thread_create
        !           401:          *      operations can be done.  Thread_force_terminate closes the
        !           402:          *      thread port for each thread; when that is done, the
        !           403:          *      thread will eventually disappear.  Thus the loop will
        !           404:          *      terminate.  Call thread_force_terminate instead of
        !           405:          *      thread_terminate to avoid deadlock checks.  Need
        !           406:          *      to call thread_block() inside loop because some other
        !           407:          *      thread (e.g., the reaper) may have to run to get rid
        !           408:          *      of all references to the thread; it won't vanish from
        !           409:          *      the task's thread list until the last one is gone.
        !           410:          */
        !           411:         task_lock(task);
        !           412:         while (!queue_empty(list)) {
        !           413:                 thread = (thread_t) queue_first(list);
        !           414:                 thread_reference(thread);
        !           415:                 task_unlock(task);
        !           416:                 thread_force_terminate(thread);
        !           417:                 thread_deallocate(thread);
        !           418:                 thread_block_with_continuation((void (*)()) 0);
        !           419:                 task_lock(task);
        !           420:         }
        !           421:         task_unlock(task);
        !           422: 
        !           423:        /*
        !           424:         *      Shut down IPC.
        !           425:         */
        !           426:        ipc_task_terminate(task);
        !           427: 
        !           428: 
        !           429:        /*
        !           430:         *      Deallocate the task's reference to itself.
        !           431:         */
        !           432:        task_deallocate(task);
        !           433: 
        !           434:        /*
        !           435:         *      If the current thread is in this task, it has not yet
        !           436:         *      been terminated (since it was removed from the task's
        !           437:         *      thread-list).  Put it back in the thread list (for
        !           438:         *      completeness), and terminate it.  Since it holds the
        !           439:         *      last reference to the task, terminating it will deallocate
        !           440:         *      the task.
        !           441:         */
        !           442:        if (cur_thread->task == task) {
        !           443:                task_lock(task);
        !           444:                s = splsched();
        !           445:                simple_lock(&task->thread_list_lock);
        !           446:                queue_enter(list, cur_thread, thread_t, thread_list);
        !           447:                simple_unlock(&task->thread_list_lock);
        !           448:                (void) splx(s);
        !           449:                task_unlock(task);
        !           450:                (void) thread_terminate(cur_thread);
        !           451:        }
        !           452: 
        !           453:        return KERN_SUCCESS;
        !           454: }
        !           455: 
        !           456: /*
        !           457:  *     task_hold:
        !           458:  *
        !           459:  *     Suspend execution of the specified task.
        !           460:  *     This is a recursive-style suspension of the task, a count of
        !           461:  *     suspends is maintained.
        !           462:  */
        !           463: kern_return_t task_hold(
        !           464:        register task_t task)
        !           465: {
        !           466:        register queue_head_t   *list;
        !           467:        register thread_t       thread, cur_thread;
        !           468: 
        !           469:        cur_thread = current_thread();
        !           470: 
        !           471:        task_lock(task);
        !           472:        if (!task->active) {
        !           473:                task_unlock(task);
        !           474:                return KERN_FAILURE;
        !           475:        }
        !           476: 
        !           477:        task->suspend_count++;
        !           478: 
        !           479:        /*
        !           480:         *      Iterate through all the threads and hold them.
        !           481:         *      Do not hold the current thread if it is within the
        !           482:         *      task.
        !           483:         */
        !           484:        list = &task->thread_list;
        !           485:        queue_iterate(list, thread, thread_t, thread_list) {
        !           486:                if (thread != cur_thread)
        !           487:                        thread_hold(thread);
        !           488:        }
        !           489:        task_unlock(task);
        !           490:        return KERN_SUCCESS;
        !           491: }
        !           492: 
        !           493: /*
        !           494:  *     task_dowait:
        !           495:  *
        !           496:  *     Wait until the task has really been suspended (all of the threads
        !           497:  *     are stopped).  Skip the current thread if it is within the task.
        !           498:  *
        !           499:  *     If task is deactivated while waiting, return a failure code unless
        !           500:  *     must_wait is true.
        !           501:  */
        !           502: kern_return_t task_dowait(
        !           503:        register task_t task,
        !           504:        boolean_t must_wait)
        !           505: {
        !           506:        register queue_head_t   *list;
        !           507:        register thread_t       thread, cur_thread, prev_thread;
        !           508:        register kern_return_t  ret = KERN_SUCCESS;
        !           509: 
        !           510:        /*
        !           511:         *      Iterate through all the threads.
        !           512:         *      While waiting for each thread, we gain a reference to it
        !           513:         *      to prevent it from going away on us.  This guarantees
        !           514:         *      that the "next" thread in the list will be a valid thread.
        !           515:         *
        !           516:         *      We depend on the fact that if threads are created while
        !           517:         *      we are looping through the threads, they will be held
        !           518:         *      automatically.  We don't care about threads that get
        !           519:         *      deallocated along the way (the reference prevents it
        !           520:         *      from happening to the thread we are working with).
        !           521:         *
        !           522:         *      If the current thread is in the affected task, it is skipped.
        !           523:         *
        !           524:         *      If the task is deactivated before we're done, and we don't
        !           525:         *      have to wait for it (must_wait is FALSE), just bail out.
        !           526:         */
        !           527:        cur_thread = current_thread();
        !           528: 
        !           529:        list = &task->thread_list;
        !           530:        prev_thread = THREAD_NULL;
        !           531:        task_lock(task);
        !           532:        queue_iterate(list, thread, thread_t, thread_list) {
        !           533:                if (!(task->active) && !(must_wait)) {
        !           534:                        ret = KERN_FAILURE;
        !           535:                        break;
        !           536:                }
        !           537:                if (thread != cur_thread) {
        !           538:                        thread_reference(thread);
        !           539:                        task_unlock(task);
        !           540:                        if (prev_thread != THREAD_NULL)
        !           541:                                thread_deallocate(prev_thread);
        !           542:                                                        /* may block */
        !           543:                        (void) thread_dowait(thread, TRUE);  /* may block */
        !           544:                        prev_thread = thread;
        !           545:                        task_lock(task);
        !           546:                }
        !           547:        }
        !           548:        task_unlock(task);
        !           549:        if (prev_thread != THREAD_NULL)
        !           550:                thread_deallocate(prev_thread);         /* may block */
        !           551:        return ret;
        !           552: }
        !           553: 
        !           554: kern_return_t task_release(
        !           555:        register task_t task)
        !           556: {
        !           557:        register queue_head_t   *list;
        !           558:        register thread_t       thread, next;
        !           559: 
        !           560:        task_lock(task);
        !           561:        if (!task->active) {
        !           562:                task_unlock(task);
        !           563:                return KERN_FAILURE;
        !           564:        }
        !           565: 
        !           566:        task->suspend_count--;
        !           567: 
        !           568:        /*
        !           569:         *      Iterate through all the threads and release them
        !           570:         */
        !           571:        list = &task->thread_list;
        !           572:        thread = (thread_t) queue_first(list);
        !           573:        while (!queue_end(list, (queue_entry_t) thread)) {
        !           574:                next = (thread_t) queue_next(&thread->thread_list);
        !           575:                thread_release(thread);
        !           576:                thread = next;
        !           577:        }
        !           578:        task_unlock(task);
        !           579:        return KERN_SUCCESS;
        !           580: }
        !           581: 
        !           582: /*
        !           583:  *     task_halt:
        !           584:  *
        !           585:  *     Halt all threads in the task.  Do not halt the current thread if
        !           586:  *     it is within the task.
        !           587:  *
        !           588:  *     Only called from exit().
        !           589:  */
        !           590: kern_return_t task_halt(task)
        !           591:        register task_t task;
        !           592: {
        !           593:        register queue_head_t   *list;
        !           594:        register thread_t       thread, cur_thread, prev_thread;
        !           595:        register kern_return_t  ret = KERN_SUCCESS;
        !           596: 
        !           597:        /*
        !           598:         *      Iterate through all the threads.
        !           599:         *      While waiting for each thread, we gain a reference to it
        !           600:         *      to prevent it from going away on us.  This guarantees
        !           601:         *      that the "next" thread in the list will be a valid thread.
        !           602:         *
        !           603:         *      If the current thread is in the affected task, it is skipped.
        !           604:         */
        !           605:        cur_thread = current_thread();
        !           606: 
        !           607:        list = &task->thread_list;
        !           608:        prev_thread = THREAD_NULL;
        !           609:        task_lock(task);
        !           610:        thread = (thread_t) queue_first(list);
        !           611:        while (!queue_end(list, (queue_entry_t) thread)) {
        !           612:                if (thread != cur_thread) {
        !           613:                        thread_reference(thread);
        !           614:                        task_unlock(task);
        !           615:                        if (prev_thread != THREAD_NULL)
        !           616:                            thread_deallocate(prev_thread); /* may block */
        !           617: #if    MACH_HOST
        !           618:                        thread_freeze(thread);
        !           619:                        if (thread->processor_set != &default_pset)
        !           620:                            thread_doassign(thread, &default_pset, FALSE);
        !           621: #endif MACH_HOST
        !           622:                        thread_halt(thread, TRUE); /* may block */
        !           623: #if    MACH_HOST
        !           624:                        thread_unfreeze(thread);
        !           625: #endif MACH_HOST
        !           626:                        prev_thread = thread;
        !           627:                        task_lock(task);
        !           628:                }
        !           629:                thread = (thread_t) queue_next(&thread->thread_list);
        !           630:        }
        !           631:        task_unlock(task);
        !           632:        if (prev_thread != THREAD_NULL)
        !           633:                thread_deallocate(prev_thread);         /* may block */
        !           634:        return(ret);    
        !           635: }
        !           636: 
        !           637: kern_return_t task_threads(
        !           638:        task_t          task,
        !           639:        thread_array_t  *thread_list,
        !           640:        natural_t       *count)
        !           641: {
        !           642:        unsigned int actual;    /* this many threads */
        !           643:        thread_t thread;
        !           644:        thread_t *threads;
        !           645:        int i;
        !           646: 
        !           647:        vm_size_t size, size_needed;
        !           648:        vm_offset_t addr;
        !           649: 
        !           650:        if (task == TASK_NULL)
        !           651:                return KERN_INVALID_ARGUMENT;
        !           652: 
        !           653:        size = 0; addr = 0;
        !           654: 
        !           655:        for (;;) {
        !           656:                task_lock(task);
        !           657:                if (!task->active) {
        !           658:                        task_unlock(task);
        !           659:                        return KERN_FAILURE;
        !           660:                }
        !           661: 
        !           662:                actual = task->thread_count;
        !           663: 
        !           664:                /* do we have the memory we need? */
        !           665: 
        !           666:                size_needed = actual * sizeof(mach_port_t);
        !           667:                if (size_needed <= size)
        !           668:                        break;
        !           669: 
        !           670:                /* unlock the task and allocate more memory */
        !           671:                task_unlock(task);
        !           672: 
        !           673:                if (size != 0)
        !           674:                        kfree(addr, size);
        !           675: 
        !           676:                assert(size_needed > 0);
        !           677:                size = size_needed;
        !           678: 
        !           679:                addr = kalloc(size);
        !           680:                if (addr == 0)
        !           681:                        return KERN_RESOURCE_SHORTAGE;
        !           682:        }
        !           683: 
        !           684:        /* OK, have memory and the task is locked & active */
        !           685: 
        !           686:        threads = (thread_t *) addr;
        !           687: 
        !           688:        for (i = 0, thread = (thread_t) queue_first(&task->thread_list);
        !           689:             i < actual;
        !           690:             i++, thread = (thread_t) queue_next(&thread->thread_list)) {
        !           691:                /* take ref for convert_thread_to_port */
        !           692:                thread_reference(thread);
        !           693:                threads[i] = thread;
        !           694:        }
        !           695:        assert(queue_end(&task->thread_list, (queue_entry_t) thread));
        !           696: 
        !           697:        /* can unlock task now that we've got the thread refs */
        !           698:        task_unlock(task);
        !           699: 
        !           700:        if (actual == 0) {
        !           701:                /* no threads, so return null pointer and deallocate memory */
        !           702: 
        !           703:                *thread_list = 0;
        !           704:                *count = 0;
        !           705: 
        !           706:                if (size != 0)
        !           707:                        kfree(addr, size);
        !           708:        } else {
        !           709:                /* if we allocated too much, must copy */
        !           710: 
        !           711:                if (size_needed < size) {
        !           712:                        vm_offset_t newaddr;
        !           713: 
        !           714:                        newaddr = kalloc(size_needed);
        !           715:                        if (newaddr == 0) {
        !           716:                                for (i = 0; i < actual; i++)
        !           717:                                        thread_deallocate(threads[i]);
        !           718:                                kfree(addr, size);
        !           719:                                return KERN_RESOURCE_SHORTAGE;
        !           720:                        }
        !           721: 
        !           722:                        bcopy((char *) addr, (char *) newaddr, size_needed);
        !           723:                        kfree(addr, size);
        !           724:                        threads = (thread_t *) newaddr;
        !           725:                }
        !           726: 
        !           727:                *thread_list = (mach_port_t *) threads;
        !           728:                *count = actual;
        !           729: 
        !           730:                /* do the conversion that Mig should handle */
        !           731: 
        !           732:                for (i = 0; i < actual; i++)
        !           733:                        ((ipc_port_t *) threads)[i] =
        !           734:                                convert_thread_to_port(threads[i]);
        !           735:        }
        !           736: 
        !           737:        return KERN_SUCCESS;
        !           738: }
        !           739: 
        !           740: kern_return_t task_suspend(
        !           741:        register task_t task)
        !           742: {
        !           743:        register boolean_t      hold;
        !           744: 
        !           745:        if (task == TASK_NULL)
        !           746:                return KERN_INVALID_ARGUMENT;
        !           747: 
        !           748:        hold = FALSE;
        !           749:        task_lock(task);
        !           750:        if ((task->user_stop_count)++ == 0)
        !           751:                hold = TRUE;
        !           752:        task_unlock(task);
        !           753: 
        !           754:        /*
        !           755:         *      If the stop count was positive, the task is
        !           756:         *      already stopped and we can exit.
        !           757:         */
        !           758:        if (!hold) {
        !           759:                return KERN_SUCCESS;
        !           760:        }
        !           761: 
        !           762:        /*
        !           763:         *      Hold all of the threads in the task, and wait for
        !           764:         *      them to stop.  If the current thread is within
        !           765:         *      this task, hold it separately so that all of the
        !           766:         *      other threads can stop first.
        !           767:         */
        !           768: 
        !           769:        if (task_hold(task) != KERN_SUCCESS)
        !           770:                return KERN_FAILURE;
        !           771: 
        !           772:        if (task_dowait(task, FALSE) != KERN_SUCCESS)
        !           773:                return KERN_FAILURE;
        !           774: 
        !           775:        if (current_task() == task) {
        !           776:                int s;
        !           777: 
        !           778:                thread_hold(current_thread());
        !           779:                /*
        !           780:                 *      We want to call thread_block on our way out,
        !           781:                 *      to stop running.
        !           782:                 */
        !           783:                s = splsched();
        !           784:                ast_on(cpu_number(), AST_BLOCK);
        !           785:                (void) splx(s);
        !           786:        }
        !           787: 
        !           788:        return KERN_SUCCESS;
        !           789: }
        !           790: 
        !           791: kern_return_t task_resume(
        !           792:        register task_t task)
        !           793: {
        !           794:        register boolean_t      release;
        !           795: 
        !           796:        if (task == TASK_NULL)
        !           797:                return KERN_INVALID_ARGUMENT;
        !           798: 
        !           799:        release = FALSE;
        !           800:        task_lock(task);
        !           801:        if (task->user_stop_count > 0) {
        !           802:                if (--(task->user_stop_count) == 0)
        !           803:                        release = TRUE;
        !           804:        }
        !           805:        else {
        !           806:                task_unlock(task);
        !           807:                return KERN_FAILURE;
        !           808:        }
        !           809:        task_unlock(task);
        !           810: 
        !           811:        /*
        !           812:         *      Release the task if necessary.
        !           813:         */
        !           814:        if (release)
        !           815:                return task_release(task);
        !           816: 
        !           817:        return KERN_SUCCESS;
        !           818: }
        !           819: 
        !           820: kern_return_t task_info(
        !           821:        task_t                  task,
        !           822:        int                     flavor,
        !           823:        task_info_t             task_info_out,  /* pointer to OUT array */
        !           824:        natural_t               *task_info_count)       /* IN/OUT */
        !           825: {
        !           826:        vm_map_t                map;
        !           827: 
        !           828:        if (task == TASK_NULL)
        !           829:                return KERN_INVALID_ARGUMENT;
        !           830: 
        !           831:        switch (flavor) {
        !           832:            case TASK_BASIC_INFO:
        !           833:            {
        !           834:                register task_basic_info_t      basic_info;
        !           835: 
        !           836:                if (*task_info_count < TASK_BASIC_INFO_COUNT) {
        !           837:                    return KERN_INVALID_ARGUMENT;
        !           838:                }
        !           839: 
        !           840:                basic_info = (task_basic_info_t) task_info_out;
        !           841: 
        !           842:                map = (task == kernel_task) ? kernel_map : task->map;
        !           843: 
        !           844:                basic_info->virtual_size  = map->size;
        !           845:                basic_info->resident_size = pmap_resident_count(map->pmap)
        !           846:                                                   * PAGE_SIZE;
        !           847: 
        !           848:                task_lock(task);
        !           849:                basic_info->base_priority = task->priority;
        !           850:                basic_info->suspend_count = task->user_stop_count;
        !           851:                basic_info->user_time.seconds
        !           852:                                = task->total_user_time.seconds;
        !           853:                basic_info->user_time.microseconds
        !           854:                                = task->total_user_time.microseconds;
        !           855:                basic_info->system_time.seconds
        !           856:                                = task->total_system_time.seconds;
        !           857:                basic_info->system_time.microseconds 
        !           858:                                = task->total_system_time.microseconds;
        !           859:                task_unlock(task);
        !           860: 
        !           861:                *task_info_count = TASK_BASIC_INFO_COUNT;
        !           862:                break;
        !           863:            }
        !           864: 
        !           865:            case TASK_THREAD_TIMES_INFO:
        !           866:            {
        !           867:                register task_thread_times_info_t times_info;
        !           868:                register thread_t       thread;
        !           869: 
        !           870:                if (*task_info_count < TASK_THREAD_TIMES_INFO_COUNT) {
        !           871:                    return KERN_INVALID_ARGUMENT;
        !           872:                }
        !           873: 
        !           874:                times_info = (task_thread_times_info_t) task_info_out;
        !           875:                times_info->user_time.seconds = 0;
        !           876:                times_info->user_time.microseconds = 0;
        !           877:                times_info->system_time.seconds = 0;
        !           878:                times_info->system_time.microseconds = 0;
        !           879: 
        !           880:                task_lock(task);
        !           881:                queue_iterate(&task->thread_list, thread,
        !           882:                              thread_t, thread_list)
        !           883:                {
        !           884:                    time_value_t user_time, system_time;
        !           885:                    int          s;
        !           886: 
        !           887:                    s = splsched();
        !           888:                    thread_lock(thread);
        !           889: 
        !           890:                    thread_read_times(thread, &user_time, &system_time);
        !           891: 
        !           892:                    thread_unlock(thread);
        !           893:                    splx(s);
        !           894: 
        !           895:                    time_value_add(&times_info->user_time, &user_time);
        !           896:                    time_value_add(&times_info->system_time, &system_time);
        !           897:                }
        !           898:                task_unlock(task);
        !           899: 
        !           900:                *task_info_count = TASK_THREAD_TIMES_INFO_COUNT;
        !           901:                break;
        !           902:            }
        !           903: 
        !           904:            default:
        !           905:                return KERN_INVALID_ARGUMENT;
        !           906:        }
        !           907: 
        !           908:        return KERN_SUCCESS;
        !           909: }
        !           910: 
        !           911: /*
        !           912:  *     Special version of task_suspend that doesn't wait.
        !           913:  *     Called only from interrupt level (U*X psignal).
        !           914:  *     Will go away when signal code becomes sane.
        !           915:  */
        !           916: kern_return_t task_suspend_nowait(task)
        !           917:        register task_t task;
        !           918: {
        !           919:        register boolean_t      hold;
        !           920: 
        !           921:        if (task == TASK_NULL)
        !           922:                return(KERN_INVALID_ARGUMENT);
        !           923: 
        !           924:        hold = FALSE;
        !           925:        task_lock(task);
        !           926:        if ((task->user_stop_count)++ == 0)
        !           927:                hold = TRUE;
        !           928:        task_unlock(task);
        !           929: 
        !           930:        /*
        !           931:         *      If the stop count was positive, the task is
        !           932:         *      already stopped and we can exit.
        !           933:         */
        !           934:        if (!hold) {
        !           935:                return (KERN_SUCCESS);
        !           936:        }
        !           937: 
        !           938:        /*
        !           939:         *      Hold all of the threads in the task.
        !           940:         *      If the current thread is within
        !           941:         *      this task, hold it separately so that all of the
        !           942:         *      other threads can stop first.
        !           943:         */
        !           944: 
        !           945:        if (task_hold(task) != KERN_SUCCESS)
        !           946:                return(KERN_FAILURE);
        !           947: 
        !           948:        if (current_task() == task) {
        !           949:                thread_hold(current_thread());
        !           950:        }
        !           951: 
        !           952:        return(KERN_SUCCESS);
        !           953: }
        !           954: 
        !           955: #if    MACH_HOST
        !           956: /*
        !           957:  *     task_assign:
        !           958:  *
        !           959:  *     Change the assigned processor set for the task
        !           960:  */
        !           961: kern_return_t
        !           962: task_assign(
        !           963:        task_t          task,
        !           964:        processor_set_t new_pset,
        !           965:        boolean_t       assign_threads)
        !           966: {
        !           967:        kern_return_t           ret = KERN_SUCCESS;
        !           968:        register thread_t       thread, prev_thread;
        !           969:        register queue_head_t   *list;
        !           970:        register processor_set_t        pset;
        !           971: 
        !           972:        if (task == TASK_NULL || new_pset == PROCESSOR_SET_NULL) {
        !           973:                return KERN_INVALID_ARGUMENT;
        !           974:        }
        !           975: 
        !           976:        /*
        !           977:         *      Freeze task`s assignment.  Prelude to assigning
        !           978:         *      task.  Only one freeze may be held per task.
        !           979:         */
        !           980: 
        !           981:        task_lock(task);
        !           982:        while (task->may_assign == FALSE) {
        !           983:                task->assign_active = TRUE;
        !           984:                assert_wait((event_t)&task->assign_active, TRUE);
        !           985:                task_unlock(task);
        !           986:                thread_block((void (*)()) 0);
        !           987:                task_lock(task);
        !           988:        }
        !           989: 
        !           990:        /*
        !           991:         *      Avoid work if task already in this processor set.
        !           992:         */
        !           993:        if (task->processor_set == new_pset)  {
        !           994:                /*
        !           995:                 *      No need for task->assign_active wakeup:
        !           996:                 *      task->may_assign is still TRUE.
        !           997:                 */
        !           998:                task_unlock(task);
        !           999:                return KERN_SUCCESS;
        !          1000:        }
        !          1001: 
        !          1002:        task->may_assign = FALSE;
        !          1003:        task_unlock(task);
        !          1004: 
        !          1005:        /*
        !          1006:         *      Safe to get the task`s pset: it cannot change while
        !          1007:         *      task is frozen.
        !          1008:         */
        !          1009:        pset = task->processor_set;
        !          1010: 
        !          1011:        /*
        !          1012:         *      Lock both psets now.  Use ordering to avoid deadlock.
        !          1013:         */
        !          1014:     Restart:
        !          1015:        if ((vm_offset_t) pset < (vm_offset_t) new_pset) {
        !          1016:            pset_lock(pset);
        !          1017:            pset_lock(new_pset);
        !          1018:        }
        !          1019:        else {
        !          1020:            pset_lock(new_pset);
        !          1021:            pset_lock(pset);
        !          1022:        }
        !          1023: 
        !          1024:        /*
        !          1025:         *      Check if new_pset is ok to assign to.  If not,
        !          1026:         *      reassign to default_pset.
        !          1027:         */
        !          1028:        if (!new_pset->active) {
        !          1029:            pset_unlock(pset);
        !          1030:            pset_unlock(new_pset);
        !          1031:            new_pset = &default_pset;
        !          1032:            goto Restart;
        !          1033:        }
        !          1034: 
        !          1035:        pset_reference(new_pset);
        !          1036: 
        !          1037:        /*
        !          1038:         *      Now grab the task lock and move the task.
        !          1039:         */
        !          1040: 
        !          1041:        task_lock(task);
        !          1042:        pset_remove_task(pset, task);
        !          1043:        pset_add_task(new_pset, task);
        !          1044: 
        !          1045:        pset_unlock(pset);
        !          1046:        pset_unlock(new_pset);
        !          1047: 
        !          1048:        if (assign_threads == FALSE) {
        !          1049:                /*
        !          1050:                 *      We leave existing threads at their
        !          1051:                 *      old assignments.  Unfreeze task`s
        !          1052:                 *      assignment.
        !          1053:                 */
        !          1054:                task->may_assign = TRUE;
        !          1055:                if (task->assign_active) {
        !          1056:                        task->assign_active = FALSE;
        !          1057:                        thread_wakeup((event_t) &task->assign_active);
        !          1058:                }
        !          1059:                task_unlock(task);
        !          1060:                pset_deallocate(pset);
        !          1061:                return KERN_SUCCESS;
        !          1062:        }
        !          1063: 
        !          1064:        /*
        !          1065:         *      If current thread is in task, freeze its assignment.
        !          1066:         */
        !          1067:        if (current_thread()->task == task) {
        !          1068:                task_unlock(task);
        !          1069:                thread_freeze(current_thread());
        !          1070:                task_lock(task);
        !          1071:        }
        !          1072: 
        !          1073:        /*
        !          1074:         *      Iterate down the thread list reassigning all the threads.
        !          1075:         *      New threads pick up task's new processor set automatically.
        !          1076:         *      Do current thread last because new pset may be empty.
        !          1077:         */
        !          1078:        list = &task->thread_list;
        !          1079:        prev_thread = THREAD_NULL;
        !          1080:        queue_iterate(list, thread, thread_t, thread_list) {
        !          1081:                if (!(task->active)) {
        !          1082:                        ret = KERN_FAILURE;
        !          1083:                        break;
        !          1084:                }
        !          1085:                if (thread != current_thread()) {
        !          1086:                        thread_reference(thread);
        !          1087:                        task_unlock(task);
        !          1088:                        if (prev_thread != THREAD_NULL)
        !          1089:                            thread_deallocate(prev_thread); /* may block */
        !          1090:                        thread_assign(thread,new_pset);     /* may block */
        !          1091:                        prev_thread = thread;
        !          1092:                        task_lock(task);
        !          1093:                }
        !          1094:        }
        !          1095: 
        !          1096:        /*
        !          1097:         *      Done, wakeup anyone waiting for us.
        !          1098:         */
        !          1099:        task->may_assign = TRUE;
        !          1100:        if (task->assign_active) {
        !          1101:                task->assign_active = FALSE;
        !          1102:                thread_wakeup((event_t)&task->assign_active);
        !          1103:        }
        !          1104:        task_unlock(task);
        !          1105:        if (prev_thread != THREAD_NULL)
        !          1106:                thread_deallocate(prev_thread);         /* may block */
        !          1107: 
        !          1108:        /*
        !          1109:         *      Finish assignment of current thread.
        !          1110:         */
        !          1111:        if (current_thread()->task == task)
        !          1112:                thread_doassign(current_thread(), new_pset, TRUE);
        !          1113: 
        !          1114:        pset_deallocate(pset);
        !          1115: 
        !          1116:        return ret;
        !          1117: }
        !          1118: #else  /* MACH_HOST */
        !          1119: /*
        !          1120:  *     task_assign:
        !          1121:  *
        !          1122:  *     Change the assigned processor set for the task
        !          1123:  */
        !          1124: kern_return_t
        !          1125: task_assign(
        !          1126:        task_t          task,
        !          1127:        processor_set_t new_pset,
        !          1128:        boolean_t       assign_threads)
        !          1129: {
        !          1130:        return KERN_FAILURE;
        !          1131: }
        !          1132: #endif /* MACH_HOST */
        !          1133:        
        !          1134: 
        !          1135: /*
        !          1136:  *     task_assign_default:
        !          1137:  *
        !          1138:  *     Version of task_assign to assign to default processor set.
        !          1139:  */
        !          1140: kern_return_t
        !          1141: task_assign_default(
        !          1142:        task_t          task,
        !          1143:        boolean_t       assign_threads)
        !          1144: {
        !          1145:        return task_assign(task, &default_pset, assign_threads);
        !          1146: }
        !          1147: 
        !          1148: /*
        !          1149:  *     task_get_assignment
        !          1150:  *
        !          1151:  *     Return name of processor set that task is assigned to.
        !          1152:  */
        !          1153: kern_return_t task_get_assignment(
        !          1154:        task_t          task,
        !          1155:        processor_set_t *pset)
        !          1156: {
        !          1157:        if (!task->active)
        !          1158:                return KERN_FAILURE;
        !          1159: 
        !          1160:        *pset = task->processor_set;
        !          1161:        pset_reference(*pset);
        !          1162:        return KERN_SUCCESS;
        !          1163: }
        !          1164: 
        !          1165: /*
        !          1166:  *     task_priority
        !          1167:  *
        !          1168:  *     Set priority of task; used only for newly created threads.
        !          1169:  *     Optionally change priorities of threads.
        !          1170:  */
        !          1171: kern_return_t
        !          1172: task_priority(
        !          1173:        task_t          task,
        !          1174:        int             priority,
        !          1175:        boolean_t       change_threads)
        !          1176: {
        !          1177:        kern_return_t   ret = KERN_SUCCESS;
        !          1178: 
        !          1179:        if (task == TASK_NULL || invalid_pri(priority))
        !          1180:                return KERN_INVALID_ARGUMENT;
        !          1181: 
        !          1182:        task_lock(task);
        !          1183:        task->priority = priority;
        !          1184: 
        !          1185:        if (change_threads) {
        !          1186:                register thread_t       thread;
        !          1187:                register queue_head_t   *list;
        !          1188: 
        !          1189:                list = &task->thread_list;
        !          1190:                queue_iterate(list, thread, thread_t, thread_list) {
        !          1191:                        if (thread_priority(thread, priority, FALSE)
        !          1192:                                != KERN_SUCCESS)
        !          1193:                                        ret = KERN_FAILURE;
        !          1194:                }
        !          1195:        }
        !          1196: 
        !          1197:        task_unlock(task);
        !          1198:        return ret;
        !          1199: }
        !          1200: 
        !          1201: task_t current_task_EXTERNAL()
        !          1202: {
        !          1203:        return current_task();
        !          1204: }
        !          1205: 
        !          1206: /*
        !          1207:  * Loadable servers need to be able to find their task map.
        !          1208:  */
        !          1209: vm_map_t current_map_EXTERNAL()
        !          1210: {
        !          1211:        return current_task()->map;
        !          1212: }

unix.superglobalmegacorp.com

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