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

unix.superglobalmegacorp.com

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