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