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