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

unix.superglobalmegacorp.com

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