Annotation of Gnu-Mach/kern/task.c, revision 1.1.1.3

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

unix.superglobalmegacorp.com

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