Annotation of OSKit-Mach/kern/task.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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