Annotation of XNU/osfmk/kern/task_swap.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /*      
                     26:  *             File:   kern/task_swap.c
                     27:  *      
                     28:  *     Task residency management primitives implementation.
                     29:  */
                     30: #include <mach_assert.h>
                     31: #include <task_swapper.h>
                     32: 
                     33: #include <kern/spl.h>
                     34: #include <kern/lock.h>
                     35: #include <kern/queue.h>
                     36: #include <kern/host.h>
                     37: #include <kern/task.h>
                     38: #include <kern/task_swap.h>
                     39: #include <kern/thread.h>
                     40: #include <kern/thread_swap.h>
                     41: #include <kern/host_statistics.h>
                     42: #include <kern/misc_protos.h>
                     43: #include <kern/assert.h>
                     44: #include <mach/policy.h>
                     45: 
                     46: #include <ipc/ipc_port.h>      /* We use something from in here */
                     47: 
                     48: /*
                     49:  * Note:  if TASK_SWAPPER is disabled, then this file defines only
                     50:  * a stub version of task_swappable(), so that the service can always
                     51:  * be defined, even if swapping has been configured out of the kernel.
                     52:  */
                     53: #if TASK_SWAPPER
                     54: 
                     55: /* temporary debug flags */
                     56: #define TASK_SW_DEBUG 1
                     57: #define TASK_SW_STATS 1
                     58: 
                     59: int task_swap_debug = 0;
                     60: int task_swap_stats = 0;
                     61: int task_swap_enable = 1;
                     62: int task_swap_on = 1;
                     63: 
                     64: queue_head_t   swapped_tasks;          /* completely swapped out tasks */
                     65: queue_head_t   swapout_thread_q;       /* threads to be swapped out */
                     66: mutex_t                task_swapper_lock;      /* protects above queue */
                     67: 
                     68: #define task_swapper_lock()    mutex_lock(&task_swapper_lock)
                     69: #define task_swapper_unlock()  mutex_unlock(&task_swapper_lock)
                     70: 
                     71: queue_head_t   eligible_tasks;         /* tasks eligible for swapout */
                     72: mutex_t                task_swapout_list_lock; /* protects above queue */
                     73: #define task_swapout_lock()    mutex_lock(&task_swapout_list_lock)
                     74: #define task_swapout_unlock()  mutex_unlock(&task_swapout_list_lock)
                     75: 
                     76: /*
                     77:  * The next section of constants and globals are tunable parameters
                     78:  * used in making swapping decisions.  They may be changed dynamically
                     79:  * without adversely affecting the robustness of the system; however,
                     80:  * the policy will change, one way or the other.
                     81:  */
                     82: 
                     83: #define SHORT_AVG_INTERVAL     5       /* in seconds */
                     84: #define LONG_AVG_INTERVAL      30      /* in seconds */
                     85: #define AVE_SCALE              1024
                     86: 
                     87: unsigned int short_avg_interval = SHORT_AVG_INTERVAL;
                     88: unsigned int long_avg_interval = LONG_AVG_INTERVAL;
                     89: 
                     90: #ifndef MIN_SWAP_PAGEOUT_RATE
                     91: #define MIN_SWAP_PAGEOUT_RATE  10
                     92: #endif
                     93: 
                     94: /*
                     95:  * The following are all stored in fixed-point representation (the actual
                     96:  * value times AVE_SCALE), to allow more accurate computing of decaying
                     97:  * averages.  So all variables that end with "avg" must be divided by
                     98:  * AVE_SCALE to convert them or compare them to ints.
                     99:  */
                    100: unsigned int vm_grab_rate_avg;
                    101: unsigned int vm_pageout_rate_avg = MIN_SWAP_PAGEOUT_RATE * AVE_SCALE;
                    102: unsigned int vm_pageout_rate_longavg = MIN_SWAP_PAGEOUT_RATE * AVE_SCALE;
                    103: unsigned int vm_pageout_rate_peakavg = MIN_SWAP_PAGEOUT_RATE * AVE_SCALE;
                    104: unsigned int vm_page_free_avg; /* average free pages over short_avg_interval */
                    105: unsigned int vm_page_free_longavg; /* avg free pages over long_avg_interval */
                    106: 
                    107: /*
                    108:  * Trigger task swapping when paging activity reaches
                    109:  * SWAP_HIGH_WATER_MARK per cent of the maximum paging activity ever observed.
                    110:  * Turn off task swapping when paging activity goes back down to below
                    111:  * SWAP_PAGEOUT_LOW_WATER_MARK per cent of the maximum.
                    112:  * These numbers have been found empirically and might need some tuning...
                    113:  */
                    114: #ifndef SWAP_PAGEOUT_HIGH_WATER_MARK
                    115: #define SWAP_PAGEOUT_HIGH_WATER_MARK   30
                    116: #endif
                    117: #ifndef SWAP_PAGEOUT_LOW_WATER_MARK
                    118: #define SWAP_PAGEOUT_LOW_WATER_MARK    10
                    119: #endif
                    120: 
                    121: #ifndef MAX_GRAB_RATE
                    122: #define MAX_GRAB_RATE  ((unsigned int) -1)     /* XXX no maximum */
                    123: #endif
                    124: 
                    125: /*
                    126:  * swap_{start,stop}_pageout_rate start at the minimum value, then increase
                    127:  * to adjust to the hardware's performance, following the paging rate peaks.
                    128:  */
                    129: unsigned int swap_pageout_high_water_mark = SWAP_PAGEOUT_HIGH_WATER_MARK;
                    130: unsigned int swap_pageout_low_water_mark = SWAP_PAGEOUT_LOW_WATER_MARK;
                    131: unsigned int swap_start_pageout_rate = MIN_SWAP_PAGEOUT_RATE * AVE_SCALE *
                    132:                                        SWAP_PAGEOUT_HIGH_WATER_MARK / 100;
                    133: unsigned int swap_stop_pageout_rate = MIN_SWAP_PAGEOUT_RATE * AVE_SCALE *
                    134:                                        SWAP_PAGEOUT_LOW_WATER_MARK / 100;
                    135: #if    TASK_SW_DEBUG
                    136: unsigned int fixed_swap_start_pageout_rate = 0;        /* only for testing purpose */
                    137: unsigned int fixed_swap_stop_pageout_rate = 0; /* only for testing purpose */
                    138: #endif /* TASK_SW_DEBUG */
                    139: unsigned int max_grab_rate = MAX_GRAB_RATE;
                    140: 
                    141: #ifndef MIN_SWAP_TIME
                    142: #define MIN_SWAP_TIME  1
                    143: #endif
                    144: 
                    145: int min_swap_time = MIN_SWAP_TIME;                     /* in seconds */
                    146: 
                    147: #ifndef MIN_RES_TIME
                    148: #define MIN_RES_TIME   6
                    149: #endif
                    150: 
                    151: int min_res_time = MIN_RES_TIME;                       /* in seconds */
                    152: 
                    153: #ifndef MIN_ACTIVE_TASKS
                    154: #define MIN_ACTIVE_TASKS       4
                    155: #endif
                    156: 
                    157: int min_active_tasks = MIN_ACTIVE_TASKS;
                    158: 
                    159: #ifndef TASK_SWAP_CYCLE_TIME
                    160: #define TASK_SWAP_CYCLE_TIME   2
                    161: #endif
                    162: 
                    163: int task_swap_cycle_time = TASK_SWAP_CYCLE_TIME;       /* in seconds */
                    164: 
                    165: int last_task_swap_cycle = 0;
                    166: 
                    167: /* temporary statistics */
                    168: int task_swapouts = 0;
                    169: int task_swapins = 0;
                    170: int task_swaprss_out = 0;      /* total rss at swapout time */
                    171: int task_swaprss_in = 0;       /* total rss at swapin time */
                    172: int task_swap_total_time = 0;  /* total time spent swapped out */
                    173: int tasks_swapped_out = 0;     /* number of tasks swapped out now */
                    174: 
                    175: #ifdef TASK_SW_STATS
                    176: #define TASK_STATS_INCR(cnt)   (cnt)++
                    177: #else
                    178: #define TASK_STATS_INCR(cnt)
                    179: #endif /* TASK_SW_STATS */
                    180: 
                    181: #if    TASK_SW_DEBUG
                    182: boolean_t on_swapped_list(task_t task);        /* forward */
                    183: /*
                    184:  * Debug function to determine if a task is already on the
                    185:  * swapped out tasks list.  It also checks for tasks on the list
                    186:  * that are in an illegal state (i.e. swapped in).
                    187:  */
                    188: boolean_t
                    189: on_swapped_list(task_t task)
                    190: {
                    191:        task_t ltask;
                    192:        /* task_swapper_lock is locked. */
                    193: 
                    194:        if (queue_empty(&swapped_tasks)) {
                    195:                return(FALSE);
                    196:        }
                    197:        ltask = (task_t)queue_first(&swapped_tasks);
                    198:        while (!queue_end(&swapped_tasks, (queue_entry_t)ltask)) {
                    199:                /* check for illegal state */
                    200:                if (ltask->swap_state == TASK_SW_IN) {
                    201:                        printf("on_swapped_list and in: 0x%X\n",ltask);
                    202:                        Debugger("");
                    203:                }
                    204:                if (ltask == task)
                    205:                        return(TRUE);
                    206:                ltask = (task_t)queue_next(&ltask->swapped_tasks);
                    207:        }
                    208:        return(FALSE);
                    209: }
                    210: #endif /* TASK_SW_DEBUG */
                    211: 
                    212: /*
                    213:  *     task_swapper_init: [exported]
                    214:  */
                    215: void
                    216: task_swapper_init()
                    217: {
                    218:        queue_init(&swapped_tasks);
                    219:        queue_init(&eligible_tasks);
                    220:        queue_init(&swapout_thread_q);
                    221:        mutex_init(&task_swapper_lock, ETAP_THREAD_TASK_SWAP);
                    222:        mutex_init(&task_swapout_list_lock, ETAP_THREAD_TASK_SWAPOUT);
                    223:        vm_page_free_avg = vm_page_free_count * AVE_SCALE;
                    224:        vm_page_free_longavg = vm_page_free_count * AVE_SCALE;
                    225: }
                    226: 
                    227: #endif /* TASK_SWAPPER */
                    228: 
                    229: /*
                    230:  *     task_swappable: [exported]
                    231:  *
                    232:  *     Make a task swappable or non-swappable. If made non-swappable,
                    233:  *     it will be swapped in.
                    234:  *
                    235:  *     Locking: task_swapout_lock is taken before task lock.
                    236:  */
                    237: kern_return_t
                    238: task_swappable(host_t host, task_t task, boolean_t make_swappable)
                    239: {
                    240:        if (host == HOST_NULL)
                    241:                return(KERN_INVALID_ARGUMENT);
                    242: 
                    243:        if (task == TASK_NULL)
                    244:                return(KERN_INVALID_ARGUMENT);
                    245: 
                    246: #if    !TASK_SWAPPER
                    247: 
                    248:        /*
                    249:         * If we don't support swapping, this call is purely advisory.
                    250:         */
                    251:        return(KERN_SUCCESS);
                    252: 
                    253: #else  /* TASK_SWAPPER */
                    254:        
                    255:        task_lock(task);
                    256:        if (make_swappable) {
                    257:                /* make task swappable */
                    258:                if (task->swap_state == TASK_SW_UNSWAPPABLE) {
                    259:                        task->swap_state = TASK_SW_IN; 
                    260:                        task_unlock(task);
                    261:                        task_swapout_eligible(task);
                    262:                }
                    263:        } else {
                    264:            switch (task->swap_state) {
                    265:                case TASK_SW_IN:
                    266:                        task->swap_state = TASK_SW_UNSWAPPABLE;
                    267:                        task_unlock(task);
                    268:                        task_swapout_ineligible(task);
                    269:                        break;
                    270:                case TASK_SW_UNSWAPPABLE:
                    271:                        task_unlock(task);
                    272:                        break;
                    273:                default:
                    274:                        /*
                    275:                         * swap_state could be TASK_SW_OUT, TASK_SW_GOING_OUT,
                    276:                         * or TASK_SW_COMING_IN.  task_swapin handles all
                    277:                         * three, and its default case will catch any bad
                    278:                         * states.
                    279:                         */
                    280:                        task_unlock(task);
                    281:                        task_swapin(task, TRUE);
                    282:                        break;
                    283:            }
                    284:        }
                    285:        return(KERN_SUCCESS);
                    286: 
                    287: #endif /* TASK_SWAPPER */
                    288: 
                    289: }
                    290: 
                    291: #if    TASK_SWAPPER
                    292: 
                    293: /*
                    294:  *     task_swapout:
                    295:  *     A reference to the task must be held.
                    296:  *
                    297:  *     Start swapping out a task by sending an AST_SWAPOUT to each thread.
                    298:  *     When the threads reach a clean point, they queue themselves up on the
                    299:  *     swapout_thread_q to be swapped out by the task_swap_swapout_thread.
                    300:  *     The task can be swapped in at any point in this process.
                    301:  *
                    302:  *     A task will not be fully swapped out (i.e. its map residence count
                    303:  *     at zero) until all currently-swapped threads run and reach
                    304:  *     a clean point, at which time they will be swapped again,
                    305:  *     decrementing the swap_ast_waiting count on the task.
                    306:  *
                    307:  *     Locking: no locks held upon entry and exit.
                    308:  *              Task_lock is held throughout this function.
                    309:  */
                    310: kern_return_t
                    311: task_swapout(task_t task)
                    312: {
                    313:        thread_act_t thr_act;
                    314:        thread_t thread;
                    315:        queue_head_t *list;
                    316:        int s;
                    317: 
                    318:        task_swapout_lock();
                    319:        task_lock(task);
                    320:        /*
                    321:         * NOTE: look into turning these into assertions if they
                    322:         * are invariants.
                    323:         */
                    324:        if ((task->swap_state != TASK_SW_IN) || (!task->active)) {
                    325:                task_unlock(task);
                    326:                task_swapout_unlock();
                    327:                return(KERN_FAILURE);
                    328:        }
                    329:        if (task->swap_flags & TASK_SW_ELIGIBLE) {
                    330:                queue_remove(&eligible_tasks, task, task_t, swapped_tasks);
                    331:                task->swap_flags &= ~TASK_SW_ELIGIBLE;
                    332:        }
                    333:        task_swapout_unlock();
                    334: 
                    335:        /* set state to avoid races with task_swappable(FALSE) */
                    336:        task->swap_state = TASK_SW_GOING_OUT;
                    337:        task->swap_rss = pmap_resident_count(task->map->pmap);
                    338:        task_swaprss_out += task->swap_rss;
                    339:        task->swap_ast_waiting = task->thr_act_count;
                    340: 
                    341:        /*
                    342:         * halt all threads in this task:
                    343:         * We don't need the thread list lock for traversal.
                    344:         */
                    345:        list = &task->thr_acts;
                    346:        thr_act = (thread_act_t) queue_first(list);
                    347:        while (!queue_end(list, (queue_entry_t) thr_act)) {
                    348:                boolean_t swappable;
                    349:                thread_act_t ract;
                    350: 
                    351:                thread = act_lock_thread(thr_act);
                    352:                s = splsched();
                    353:                if (!thread)
                    354:                        swappable = (thr_act->swap_state != TH_SW_UNSWAPPABLE);
                    355:                else {
                    356:                        thread_lock(thread);
                    357:                        swappable = TRUE;
                    358:                        for (ract = thread->top_act; ract; ract = ract->lower)
                    359:                                if (ract->swap_state == TH_SW_UNSWAPPABLE) {
                    360:                                        swappable = FALSE;
                    361:                                        break;
                    362:                                }
                    363:                }
                    364:                if (swappable)
                    365:                        thread_ast_set(thr_act, AST_SWAPOUT);
                    366:                if (thread)
                    367:                        thread_unlock(thread);
                    368:                splx(s);
                    369:                assert((thr_act->ast & AST_TERMINATE) == 0);
                    370:                act_unlock_thread(thr_act);
                    371:                thr_act = (thread_act_t) queue_next(&thr_act->thr_acts);
                    372:        }
                    373: 
                    374:        task->swap_stamp = sched_tick;
                    375:        task->swap_nswap++;
                    376:        assert((task->swap_flags&TASK_SW_WANT_IN) == 0);
                    377:        /* put task on the queue of swapped out tasks */
                    378:        task_swapper_lock();
                    379: #if    TASK_SW_DEBUG
                    380:        if (task_swap_debug && on_swapped_list(task)) {
                    381:                printf("task 0x%X already on list\n", task);
                    382:                Debugger("");
                    383:        }
                    384: #endif /* TASK_SW_DEBUG */
                    385:        queue_enter(&swapped_tasks, task, task_t, swapped_tasks);
                    386:        tasks_swapped_out++;
                    387:        task_swapouts++;
                    388:        task_swapper_unlock();
                    389:        task_unlock(task);
                    390: 
                    391:        return(KERN_SUCCESS);
                    392: }
                    393: 
                    394: #ifdef TASK_SW_STATS
                    395: int    task_sw_race_in = 0;
                    396: int    task_sw_race_coming_in = 0;
                    397: int    task_sw_race_going_out = 0;
                    398: int    task_sw_before_ast = 0;
                    399: int    task_sw_before_swap = 0;
                    400: int    task_sw_after_swap = 0;
                    401: int    task_sw_race_in_won = 0;
                    402: int    task_sw_unswappable = 0;
                    403: int    task_sw_act_inactive = 0;
                    404: #endif /* TASK_SW_STATS */
                    405: 
                    406: /*
                    407:  *     thread_swapout_enqueue is called by thread_halt_self when it 
                    408:  *     processes AST_SWAPOUT to enqueue threads to be swapped out.
                    409:  *     It must be called at normal interrupt priority for the
                    410:  *     sake of the task_swapper_lock.
                    411:  *
                    412:  *     There can be races with task swapin here.
                    413:  *     First lock task and decrement swap_ast_waiting count, and if
                    414:  *     it's 0, we can decrement the residence count on the task's map
                    415:  *     and set the task's swap state to TASK_SW_OUT.
                    416:  */
                    417: void
                    418: thread_swapout_enqueue(thread_act_t thr_act)
                    419: {
                    420:        task_t task = thr_act->task;
                    421:        task_lock(task);
                    422:        /*
                    423:         * If the swap_state is not TASK_SW_GOING_OUT, then
                    424:         * task_swapin has beaten us to this operation, and
                    425:         * we have nothing to do.
                    426:         */
                    427:        if (task->swap_state != TASK_SW_GOING_OUT) {
                    428:                task_unlock(task);
                    429:                return;
                    430:        }
                    431:        if (--task->swap_ast_waiting == 0) {
                    432:                vm_map_t map = task->map;
                    433:                task->swap_state = TASK_SW_OUT;
                    434:                task_unlock(task);
                    435:                mutex_lock(&map->s_lock);
                    436:                vm_map_res_deallocate(map);
                    437:                mutex_unlock(&map->s_lock);
                    438:        } else
                    439:                task_unlock(task);
                    440: 
                    441:        task_swapper_lock();
                    442:        act_lock(thr_act);
                    443:        if (! (thr_act->swap_state & TH_SW_TASK_SWAPPING)) {
                    444:                /*
                    445:                 * We lost a race with task_swapin(): don't enqueue.
                    446:                 */
                    447:        } else {
                    448:                queue_enter(&swapout_thread_q, thr_act,
                    449:                            thread_act_t, swap_queue);
                    450:                thread_wakeup((event_t)&swapout_thread_q);
                    451:        }
                    452:        act_unlock(thr_act);
                    453:        task_swapper_unlock();
                    454: }
                    455: 
                    456: /*
                    457:  *     task_swap_swapout_thread: [exported]
                    458:  *
                    459:  *     Executes as a separate kernel thread.
                    460:  *     Its job is to swap out threads that have been halted by AST_SWAPOUT.
                    461:  */
                    462: void
                    463: task_swap_swapout_thread(void)
                    464: {
                    465:        thread_act_t thr_act;
                    466:        thread_t thread, nthread;
                    467:        task_t task;
                    468:        int s;
                    469: 
                    470:        thread_swappable(current_act(), FALSE);
                    471:        stack_privilege(current_thread());
                    472: 
                    473:        spllo();
                    474: 
                    475:        while (TRUE) {
                    476:                task_swapper_lock();
                    477:                while (! queue_empty(&swapout_thread_q)) {
                    478: 
                    479:                        queue_remove_first(&swapout_thread_q, thr_act,
                    480:                                           thread_act_t, swap_queue);
                    481:                        /*
                    482:                         * If we're racing with task_swapin, we need
                    483:                         * to make it safe for it to do remque on the
                    484:                         * thread, so make its links point to itself.
                    485:                         * Allowing this ugliness is cheaper than 
                    486:                         * making task_swapin search the entire queue.
                    487:                         */
                    488:                        act_lock(thr_act);
                    489:                        queue_init((queue_t) &thr_act->swap_queue);
                    490:                        act_unlock(thr_act);
                    491:                        task_swapper_unlock();
                    492:                        /*
                    493:                         * Wait for thread's RUN bit to be deasserted.
                    494:                         */
                    495:                        thread = act_lock_thread(thr_act);
                    496:                        if (thread == THREAD_NULL)
                    497:                                act_unlock_thread(thr_act);
                    498:                        else {
                    499:                                boolean_t r;
                    500: 
                    501:                                thread_reference(thread);
                    502:                                thread_hold(thr_act);
                    503:                                act_unlock_thread(thr_act);
                    504:                                r = thread_stop_wait(thread);
                    505:                                nthread = act_lock_thread(thr_act);
                    506:                                thread_release(thr_act);
                    507:                                thread_deallocate(thread);
                    508:                                act_unlock_thread(thr_act);
                    509:                                if (!r || nthread != thread) {
                    510:                                        task_swapper_lock();
                    511:                                        continue;
                    512:                                }
                    513:                        }
                    514:                        task = thr_act->task;
                    515:                        task_lock(task);
                    516:                        /* 
                    517:                         * we can race with swapin, which would set the
                    518:                         * state to TASK_SW_IN. 
                    519:                         */
                    520:                        if ((task->swap_state != TASK_SW_OUT) &&
                    521:                            (task->swap_state != TASK_SW_GOING_OUT)) {
                    522:                                task_unlock(task);
                    523:                                task_swapper_lock();
                    524:                                TASK_STATS_INCR(task_sw_race_in_won);
                    525:                                if (thread != THREAD_NULL)
                    526:                                        thread_unstop(thread);
                    527:                                continue;
                    528:                        }
                    529:                        nthread = act_lock_thread(thr_act);
                    530:                        if (nthread != thread || thr_act->active == FALSE) {
                    531:                                act_unlock_thread(thr_act);
                    532:                                task_unlock(task);
                    533:                                task_swapper_lock();
                    534:                                TASK_STATS_INCR(task_sw_act_inactive);
                    535:                                if (thread != THREAD_NULL)
                    536:                                        thread_unstop(thread);
                    537:                                continue;
                    538:                        }
                    539:                        s = splsched();
                    540:                        if (thread != THREAD_NULL)
                    541:                                thread_lock(thread);
                    542:                        /* 
                    543:                         * Thread cannot have been swapped out yet because
                    544:                         * TH_SW_TASK_SWAPPING was set in AST.  If task_swapin
                    545:                         * beat us here, we either wouldn't have found it on
                    546:                         * the queue, or the task->swap_state would have
                    547:                         * changed.  The synchronization is on the
                    548:                         * task's swap_state and the task_lock.
                    549:                         * The thread can't be swapped in any other way
                    550:                         * because its task has been swapped.
                    551:                         */
                    552:                        assert(thr_act->swap_state & TH_SW_TASK_SWAPPING);
                    553:                        assert(thread == THREAD_NULL ||
                    554:                               !(thread->state & (TH_SWAPPED_OUT|TH_RUN)));
                    555:                        assert((thr_act->swap_state & TH_SW_STATE) == TH_SW_IN);
                    556:                        /* assert(thread->state & TH_HALTED); */
                    557:                        /* this also clears TH_SW_TASK_SWAPPING flag */
                    558:                        thr_act->swap_state = TH_SW_GOING_OUT;
                    559:                        if (thread != THREAD_NULL) {
                    560:                                if (thread->top_act == thr_act) {
                    561:                                        thread->state |= TH_SWAPPED_OUT;
                    562:                                        /*
                    563:                                         * Once we unlock the task, things can happen
                    564:                                         * to the thread, so make sure it's consistent
                    565:                                         * for thread_swapout.
                    566:                                         */
                    567:                                }
                    568:                                thread->ref_count++;
                    569:                                thread_unlock(thread);
                    570:                                thread_unstop(thread);
                    571:                        }
                    572:                        splx(s);
                    573:                        act_locked_act_reference(thr_act);
                    574:                        act_unlock_thread(thr_act);
                    575:                        task_unlock(task);
                    576: 
                    577:                        thread_swapout(thr_act);        /* do the work */
                    578: 
                    579:                        if (thread != THREAD_NULL)
                    580:                                thread_deallocate(thread);
                    581:                        act_deallocate(thr_act);
                    582:                        task_swapper_lock();
                    583:                }
                    584:                assert_wait((event_t)&swapout_thread_q, THREAD_UNINT);
                    585:                task_swapper_unlock();
                    586:                thread_block((void (*)(void)) 0);
                    587:        }
                    588: }
                    589: 
                    590: /*
                    591:  *     task_swapin:
                    592:  *
                    593:  *     Make a task resident.
                    594:  *     Performs all of the work to make a task resident and possibly
                    595:  *     non-swappable.  If we race with a competing task_swapin call,
                    596:  *     we wait for its completion, then return.
                    597:  *
                    598:  *     Locking: no locks held upon entry and exit.
                    599:  *
                    600:  *     Note that TASK_SW_MAKE_UNSWAPPABLE can only be set when the
                    601:  *     state is TASK_SW_COMING_IN.
                    602:  */
                    603: 
                    604: kern_return_t
                    605: task_swapin(task_t task, boolean_t make_unswappable)
                    606: {
                    607:        register queue_head_t   *list;
                    608:        register thread_act_t   thr_act, next;
                    609:        thread_t                thread;
                    610:        int                     s;
                    611:        boolean_t               swappable = TRUE;
                    612: 
                    613:        task_lock(task);
                    614:        switch (task->swap_state) {
                    615:            case TASK_SW_OUT:
                    616:                        {
                    617:                        vm_map_t map = task->map;
                    618:                        /*
                    619:                         * Task has made it all the way out, which means
                    620:                         * that vm_map_res_deallocate has been done; set 
                    621:                         * state to TASK_SW_COMING_IN, then bring map
                    622:                         * back in.  We could actually be racing with
                    623:                         * the thread_swapout_enqueue, which does the
                    624:                         * vm_map_res_deallocate, but that race is covered.
                    625:                         */
                    626:                        task->swap_state = TASK_SW_COMING_IN;
                    627:                        assert(task->swap_ast_waiting == 0);
                    628:                        assert(map->res_count >= 0);
                    629:                        task_unlock(task);
                    630:                        mutex_lock(&map->s_lock);
                    631:                        vm_map_res_reference(map);
                    632:                        mutex_unlock(&map->s_lock);
                    633:                        task_lock(task);
                    634:                        assert(task->swap_state == TASK_SW_COMING_IN);
                    635:                        }
                    636:                        break;
                    637: 
                    638:            case TASK_SW_GOING_OUT:
                    639:                        /*
                    640:                         * Task isn't all the way out yet.  There is
                    641:                         * still at least one thread not swapped, and
                    642:                         * vm_map_res_deallocate has not been done.
                    643:                         */
                    644:                        task->swap_state = TASK_SW_COMING_IN;
                    645:                        assert(task->swap_ast_waiting > 0 ||
                    646:                               (task->swap_ast_waiting == 0 &&
                    647:                                task->thr_act_count == 0));
                    648:                        assert(task->map->res_count > 0);
                    649:                        TASK_STATS_INCR(task_sw_race_going_out);
                    650:                        break;
                    651:            case TASK_SW_IN:
                    652:                        assert(task->map->res_count > 0);
                    653: #if    TASK_SW_DEBUG
                    654:                        task_swapper_lock();
                    655:                        if (task_swap_debug && on_swapped_list(task)) {
                    656:                                printf("task 0x%X on list, state is SW_IN\n",
                    657:                                        task);
                    658:                                Debugger("");
                    659:                        }
                    660:                        task_swapper_unlock();
                    661: #endif /* TASK_SW_DEBUG */
                    662:                        TASK_STATS_INCR(task_sw_race_in);
                    663:                        if (make_unswappable) {
                    664:                                task->swap_state = TASK_SW_UNSWAPPABLE;
                    665:                                task_unlock(task);
                    666:                                task_swapout_ineligible(task);
                    667:                        } else
                    668:                                task_unlock(task);
                    669:                        return(KERN_SUCCESS);
                    670:            case TASK_SW_COMING_IN:
                    671:                        /* 
                    672:                         * Raced with another task_swapin and lost;
                    673:                         * wait for other one to complete first
                    674:                         */
                    675:                        assert(task->map->res_count >= 0);
                    676:                        /*
                    677:                         * set MAKE_UNSWAPPABLE so that whoever is swapping
                    678:                         * the task in will make it unswappable, and return
                    679:                         */
                    680:                        if (make_unswappable)
                    681:                                task->swap_flags |= TASK_SW_MAKE_UNSWAPPABLE;
                    682:                        task->swap_flags |= TASK_SW_WANT_IN;
                    683:                        assert_wait((event_t)&task->swap_state, THREAD_UNINT);
                    684:                        task_unlock(task);
                    685:                        thread_block((void (*)(void)) 0);
                    686:                        TASK_STATS_INCR(task_sw_race_coming_in);
                    687:                        return(KERN_SUCCESS);
                    688:            case TASK_SW_UNSWAPPABLE:
                    689:                        /* 
                    690:                         * This can happen, since task_terminate 
                    691:                         * unconditionally calls task_swapin.
                    692:                         */
                    693:                        task_unlock(task);
                    694:                        return(KERN_SUCCESS);
                    695:            default:
                    696:                        panic("task_swapin bad state");
                    697:                        break;
                    698:        }
                    699:        if (make_unswappable)
                    700:                task->swap_flags |= TASK_SW_MAKE_UNSWAPPABLE;
                    701:        assert(task->swap_state == TASK_SW_COMING_IN);
                    702:        task_swapper_lock();
                    703: #if    TASK_SW_DEBUG
                    704:        if (task_swap_debug && !on_swapped_list(task)) {
                    705:                printf("task 0x%X not on list\n", task);
                    706:                Debugger("");
                    707:        }
                    708: #endif /* TASK_SW_DEBUG */
                    709:        queue_remove(&swapped_tasks, task, task_t, swapped_tasks);
                    710:        tasks_swapped_out--;
                    711:        task_swapins++;
                    712:        task_swapper_unlock();
                    713: 
                    714:        /*
                    715:         * Iterate through all threads for this task and 
                    716:         * release them, as required.  They may not have been swapped
                    717:         * out yet.  The task remains locked throughout.
                    718:         */
                    719:        list = &task->thr_acts;
                    720:        thr_act = (thread_act_t) queue_first(list);
                    721:        while (!queue_end(list, (queue_entry_t) thr_act)) {
                    722:                boolean_t need_to_release;
                    723:                next = (thread_act_t) queue_next(&thr_act->thr_acts);
                    724:                /*
                    725:                 * Keep task_swapper_lock across thread handling
                    726:                 * to synchronize with task_swap_swapout_thread
                    727:                 */
                    728:                task_swapper_lock();
                    729:                thread = act_lock_thread(thr_act);
                    730:                s = splsched();
                    731:                if (thr_act->ast & AST_SWAPOUT) {
                    732:                        /* thread hasn't gotten the AST yet, just clear it */
                    733:                        thread_ast_clear(thr_act, AST_SWAPOUT);
                    734:                        need_to_release = FALSE;
                    735:                        TASK_STATS_INCR(task_sw_before_ast);
                    736:                        splx(s);
                    737:                        act_unlock_thread(thr_act);
                    738:                } else {
                    739:                        /*
                    740:                         * If AST_SWAPOUT was cleared, then thread_hold,
                    741:                         * or equivalent was done.
                    742:                         */
                    743:                        need_to_release = TRUE;
                    744:                        /*
                    745:                         * Thread has hit AST, but it may not have
                    746:                         * been dequeued yet, so we need to check.
                    747:                         * NOTE: the thread may have been dequeued, but
                    748:                         * has not yet been swapped (the task_swapper_lock
                    749:                         * has been dropped, but the thread is not yet
                    750:                         * locked), and the TH_SW_TASK_SWAPPING flag may 
                    751:                         * not have been cleared.  In this case, we will do 
                    752:                         * an extra remque, which the task_swap_swapout_thread
                    753:                         * has made safe, and clear the flag, which is also
                    754:                         * checked by the t_s_s_t before doing the swapout.
                    755:                         */
                    756:                        if (thread)
                    757:                                thread_lock(thread);
                    758:                        if (thr_act->swap_state & TH_SW_TASK_SWAPPING) {
                    759:                                /* 
                    760:                                 * hasn't yet been dequeued for swapout,
                    761:                                 * so clear flags and dequeue it first.
                    762:                                 */
                    763:                                thr_act->swap_state &= ~TH_SW_TASK_SWAPPING;
                    764:                                assert(thr_act->thread == THREAD_NULL || 
                    765:                                       !(thr_act->thread->state &
                    766:                                         TH_SWAPPED_OUT));
                    767:                                queue_remove(&swapout_thread_q, thr_act,
                    768:                                             thread_act_t, swap_queue);
                    769:                                TASK_STATS_INCR(task_sw_before_swap);
                    770:                        } else {
                    771:                                TASK_STATS_INCR(task_sw_after_swap);
                    772:                                /*
                    773:                                 * It's possible that the thread was
                    774:                                 * made unswappable before hitting the
                    775:                                 * AST, in which case it's still running.
                    776:                                 */
                    777:                                if (thr_act->swap_state == TH_SW_UNSWAPPABLE) {
                    778:                                        need_to_release = FALSE;
                    779:                                        TASK_STATS_INCR(task_sw_unswappable);
                    780:                                }
                    781:                        }
                    782:                        if (thread)
                    783:                                thread_unlock(thread);
                    784:                        splx(s);
                    785:                        act_unlock_thread(thr_act);
                    786:                }
                    787:                task_swapper_unlock();
                    788: 
                    789:                /* 
                    790:                 * thread_release will swap in the thread if it's been
                    791:                 * swapped out.
                    792:                 */
                    793:                if (need_to_release) {
                    794:                        act_lock_thread(thr_act);
                    795:                        thread_release(thr_act);
                    796:                        act_unlock_thread(thr_act);
                    797:                }
                    798:                thr_act = next;
                    799:        }
                    800: 
                    801:        if (task->swap_flags & TASK_SW_MAKE_UNSWAPPABLE) {
                    802:                task->swap_flags &= ~TASK_SW_MAKE_UNSWAPPABLE;
                    803:                task->swap_state = TASK_SW_UNSWAPPABLE;
                    804:                swappable = FALSE;
                    805:        } else {
                    806:                task->swap_state = TASK_SW_IN;
                    807:        }
                    808: 
                    809:        task_swaprss_in += pmap_resident_count(task->map->pmap);
                    810:        task_swap_total_time += sched_tick - task->swap_stamp;
                    811:        /* note when task came back in */
                    812:        task->swap_stamp = sched_tick;
                    813:        if (task->swap_flags & TASK_SW_WANT_IN) {
                    814:                task->swap_flags &= ~TASK_SW_WANT_IN;
                    815:                thread_wakeup((event_t)&task->swap_state);
                    816:        }
                    817:        assert((task->swap_flags & TASK_SW_ELIGIBLE) == 0);
                    818:        task_unlock(task);
                    819: #if    TASK_SW_DEBUG
                    820:        task_swapper_lock();
                    821:        if (task_swap_debug && on_swapped_list(task)) {
                    822:                printf("task 0x%X on list at end of swap in\n", task);
                    823:                Debugger("");
                    824:        }
                    825:        task_swapper_unlock();
                    826: #endif /* TASK_SW_DEBUG */
                    827:        /*
                    828:         * Make the task eligible to be swapped again
                    829:         */
                    830:        if (swappable)
                    831:                task_swapout_eligible(task);
                    832:        return(KERN_SUCCESS);
                    833: }
                    834: 
                    835: void wake_task_swapper(boolean_t now); /* forward */
                    836: 
                    837: /*
                    838:  *     wake_task_swapper: [exported]
                    839:  *
                    840:  *     Wakes up task swapper if now == TRUE or if at least
                    841:  *     task_swap_cycle_time has elapsed since the last call.
                    842:  *
                    843:  *     NOTE: this function is not multithreaded, so if there is
                    844:  *     more than one caller, it must be modified.
                    845:  */
                    846: void
                    847: wake_task_swapper(boolean_t now)
                    848: {
                    849:        /* last_task_swap_cycle may require locking */
                    850:        if (now ||
                    851:            (sched_tick > (last_task_swap_cycle + task_swap_cycle_time))) {
                    852:                last_task_swap_cycle = sched_tick;
                    853:                if (task_swap_debug)
                    854:                        printf("wake_task_swapper: waking swapper\n");
                    855:                thread_wakeup((event_t)&swapped_tasks); /* poke swapper */
                    856:        }
                    857: }
                    858: 
                    859: task_t pick_intask(void);      /* forward */
                    860: /*
                    861:  * pick_intask:
                    862:  * returns a task to be swapped in, or TASK_NULL if nothing suitable is found.
                    863:  *
                    864:  * current algorithm: Return the task that has been swapped out the 
                    865:  *     longest, as long as it is > min_swap_time.  It will be dequeued
                    866:  *     if actually swapped in.
                    867:  *
                    868:  * NOTE:**********************************************
                    869:  * task->swap_rss (the size when the task was swapped out) could be used to
                    870:  * further refine the selection.  Another possibility would be to look at
                    871:  * the state of the thread(s) to see if the task/threads would run if they
                    872:  * were swapped in.
                    873:  * ***************************************************
                    874:  *
                    875:  * Locking:  no locks held upon entry and exit.
                    876:  */
                    877: task_t
                    878: pick_intask(void)
                    879: {
                    880:        register task_t         task = TASK_NULL;
                    881: 
                    882:        task_swapper_lock();
                    883:        /* the oldest task is the first one */
                    884:        if (!queue_empty(&swapped_tasks)) {
                    885:                task = (task_t) queue_first(&swapped_tasks);
                    886:                assert(task != TASK_NULL);
                    887:                /* Make sure it's been out min_swap_time */
                    888:                if ((sched_tick - task->swap_stamp) < min_swap_time)
                    889:                        task = TASK_NULL;
                    890:        }
                    891:        task_swapper_unlock();
                    892:        return(task);
                    893: #if    0
                    894:        /*
                    895:         * This code looks at the entire list of swapped tasks, but since
                    896:         * it does not yet do anything but look at time swapped, we 
                    897:         * can simply use the fact that the queue is ordered, and take 
                    898:         * the first one off the queue.
                    899:         */
                    900:        task = (task_t)queue_first(&swapped_tasks);
                    901:        while (!queue_end(&swapped_tasks, (queue_entry_t)task)) {
                    902:                task_lock(task);
                    903:                tmp_time = sched_tick - task->swap_stamp;
                    904:                if (tmp_time > min_swap_time && tmp_time > time_swapped) {
                    905:                        target_task = task;
                    906:                        time_swapped = tmp_time;
                    907:                }
                    908:                task_unlock(task);
                    909:                task = (task_t)queue_next(&task->swapped_tasks);
                    910:        }
                    911:        task_swapper_unlock();
                    912:        return(target_task);
                    913: #endif
                    914: }
                    915: 
                    916: task_t pick_outtask(void);     /* forward */
                    917: /*
                    918:  * pick_outtask:
                    919:  * returns a task to be swapped out, with a reference on the task,
                    920:  * or NULL if no suitable task is found.
                    921:  *
                    922:  * current algorithm:
                    923:  * 
                    924:  * Examine all eligible tasks.  While looking, use the first thread in 
                    925:  * each task as an indication of the task's activity.  Count up 
                    926:  * "active" threads (those either runnable or sleeping).  If the task 
                    927:  * is active (by these criteria), swapped in, and resident 
                    928:  * for at least min_res_time, then select the task with the largest 
                    929:  * number of pages in memory.  If there are less 
                    930:  * than min_active_tasks active tasks in the system, then don't 
                    931:  * swap anything out (this avoids swapping out the only running task 
                    932:  * in the system, for example).
                    933:  *
                    934:  * NOTE:  the task selected will not be removed from the eligible list.
                    935:  *       This means that it will be selected again if it is not swapped
                    936:  *       out, where it is removed from the list.
                    937:  *
                    938:  * Locking: no locks held upon entry and exit.  Task_swapout_lock must be
                    939:  *         taken before task locks.
                    940:  *
                    941:  * ***************************************************
                    942:  * TBD:
                    943:  * This algorithm only examines the first thread in the task.  Currently, since
                    944:  * most swappable tasks in the system are single-threaded, this generalization
                    945:  * works reasonably well.  However, the algorithm should be changed
                    946:  * to consider all threads in the task if more multi-threaded tasks were used.  
                    947:  * ***************************************************
                    948:  */
                    949: 
                    950: #ifdef TASK_SW_STATS
                    951: int inactive_task_count = 0;
                    952: int empty_task_count = 0;
                    953: #endif /* TASK_SW_STATS */
                    954: 
                    955: task_t
                    956: pick_outtask(void)
                    957: {
                    958:        register task_t         task;
                    959:        register task_t         target_task = TASK_NULL;
                    960:        unsigned long           task_rss;
                    961:        unsigned long           target_rss = 0;
                    962:        boolean_t               wired;
                    963:        boolean_t               active;
                    964:        int                     nactive = 0;
                    965: 
                    966:        task_swapout_lock();
                    967:        if (queue_empty(&eligible_tasks)) {
                    968:                /* not likely to happen */
                    969:                task_swapout_unlock();
                    970:                return(TASK_NULL);
                    971:        }
                    972:        task = (task_t)queue_first(&eligible_tasks);
                    973:        while (!queue_end(&eligible_tasks, (queue_entry_t)task)) {
                    974:                int s;
                    975:                register thread_act_t thr_act;
                    976:                thread_t th;
                    977:                
                    978: 
                    979:                task_lock(task);
                    980:                /*
                    981:                 * Don't swap real-time tasks.
                    982:                 * XXX Should we enforce that or can we let really critical
                    983:                 * tasks use task_swappable() to make sure they never end up
                    984:                 * n the eligible list ?
                    985:                 */
                    986:                if (task->policy & POLICYCLASS_FIXEDPRI) {
                    987:                        goto tryagain;
                    988:                }
                    989:                if (!task->active) {
                    990:                        TASK_STATS_INCR(inactive_task_count);
                    991:                        goto tryagain;
                    992:                }
                    993:                if (task->res_act_count == 0) {
                    994:                        TASK_STATS_INCR(empty_task_count);
                    995:                        goto tryagain;
                    996:                }
                    997:                assert(!queue_empty(&task->thr_acts));
                    998:                thr_act = (thread_act_t)queue_first(&task->thr_acts);
                    999:                active = FALSE;
                   1000:                th = act_lock_thread(thr_act);
                   1001:                s = splsched();
                   1002:                if (th != THREAD_NULL)
                   1003:                        thread_lock(th);
                   1004:                if ((th == THREAD_NULL) ||
                   1005:                    (th->state == TH_RUN) ||
                   1006:                    (th->state & TH_WAIT)) {
                   1007:                        /*
                   1008:                         * thread is "active": either runnable 
                   1009:                         * or sleeping.  Count it and examine 
                   1010:                         * it further below.
                   1011:                         */
                   1012:                        nactive++;
                   1013:                        active = TRUE;
                   1014:                }
                   1015:                if (th != THREAD_NULL)
                   1016:                        thread_unlock(th);
                   1017:                splx(s);
                   1018:                act_unlock_thread(thr_act);
                   1019:                if (active &&
                   1020:                    (task->swap_state == TASK_SW_IN) &&
                   1021:                    ((sched_tick - task->swap_stamp) > min_res_time)) {
                   1022:                        long rescount = pmap_resident_count(task->map->pmap);
                   1023:                        /*
                   1024:                         * thread must be "active", task must be swapped
                   1025:                         * in and resident for at least min_res_time
                   1026:                         */
                   1027: #if 0
                   1028: /* DEBUG Test round-robin strategy.  Picking biggest task could cause extreme
                   1029:  * unfairness to such large interactive programs as xterm.  Instead, pick the
                   1030:  * first task that has any pages resident:
                   1031:  */
                   1032:                        if (rescount > 1) {
                   1033:                                task->ref_count++;
                   1034:                                target_task = task;
                   1035:                                task_unlock(task);
                   1036:                                task_swapout_unlock();
                   1037:                                return(target_task);
                   1038:                        }
                   1039: #else
                   1040:                        if (rescount > target_rss) {
                   1041:                                /*
                   1042:                                 * task is not swapped, and it has the
                   1043:                                 * largest rss seen so far.
                   1044:                                 */
                   1045:                                task->ref_count++;
                   1046:                                target_rss = rescount;
                   1047:                                assert(target_task != task);
                   1048:                                if (target_task != TASK_NULL)
                   1049:                                        task_deallocate(target_task);
                   1050:                                target_task = task;
                   1051:                        }
                   1052: #endif
                   1053:                }
                   1054: tryagain:
                   1055:                task_unlock(task);
                   1056:                task = (task_t)queue_next(&task->swapped_tasks);
                   1057:        }
                   1058:        task_swapout_unlock();
                   1059:        /* only swap out if there are at least min_active_tasks */
                   1060:        if (nactive < min_active_tasks) {
                   1061:                if (target_task != TASK_NULL) {
                   1062:                        task_deallocate(target_task);
                   1063:                        target_task = TASK_NULL;
                   1064:                }
                   1065:        }
                   1066:        return(target_task);
                   1067: }
                   1068: 
                   1069: #if    TASK_SW_DEBUG
                   1070: void print_pid(task_t task, unsigned long n1, unsigned long n2,
                   1071:               const char *comp, const char *inout);    /* forward */
                   1072: void
                   1073: print_pid(
                   1074:        task_t task,
                   1075:        unsigned long n1,
                   1076:        unsigned long n2,
                   1077:        const char *comp,
                   1078:        const char *inout)
                   1079: {
                   1080:        long rescount;
                   1081:        task_lock(task);
                   1082:        rescount = pmap_resident_count(task->map->pmap);
                   1083:        task_unlock(task);
                   1084:        printf("task_swapper: swapped %s task %x; %d %s %d; res=%d\n",
                   1085:                inout, task, n1, comp, n2, rescount);
                   1086: }
                   1087: #endif
                   1088: 
                   1089: /*
                   1090:  *     task_swapper: [exported]
                   1091:  *
                   1092:  *     Executes as a separate kernel thread.
                   1093:  */
                   1094: #define MAX_LOOP 3
                   1095: void
                   1096: task_swapper(void)
                   1097: {
                   1098:        task_t  outtask, intask;
                   1099:        int timeout;
                   1100:        int loopcnt = 0;
                   1101:        boolean_t start_swapping;
                   1102:        boolean_t stop_swapping;
                   1103:        int local_page_free_avg;
                   1104:        extern int hz;
                   1105: 
                   1106:        thread_swappable(current_act(), FALSE);
                   1107:        stack_privilege(current_thread());
                   1108: 
                   1109:        spllo();
                   1110: 
                   1111:        for (;;) {
                   1112:        local_page_free_avg = vm_page_free_avg;
                   1113:        while (TRUE) {
                   1114: #if    0
                   1115:                if (task_swap_debug)
                   1116:                        printf("task_swapper: top of loop; cnt = %d\n",loopcnt);
                   1117: #endif
                   1118:                intask = pick_intask();
                   1119: 
                   1120:                start_swapping = ((vm_pageout_rate_avg > swap_start_pageout_rate) ||
                   1121:                                  (vm_grab_rate_avg > max_grab_rate));
                   1122:                stop_swapping = (vm_pageout_rate_avg < swap_stop_pageout_rate);
                   1123: 
                   1124:                /*
                   1125:                 * If a lot of paging is going on, or another task should come
                   1126:                 * in but memory is tight, find something to swap out and start
                   1127:                 * it.  Don't swap any task out if task swapping is disabled.
                   1128:                 * vm_page_queue_free_lock protects the vm globals.
                   1129:                 */
                   1130:                outtask = TASK_NULL;
                   1131:                if (start_swapping ||
                   1132:                    (!stop_swapping && intask &&
                   1133:                     ((local_page_free_avg / AVE_SCALE) < vm_page_free_target))
                   1134:                   ) {
                   1135:                        if (task_swap_enable &&
                   1136:                            (outtask = pick_outtask()) &&
                   1137:                            (task_swapout(outtask) == KERN_SUCCESS)) {
                   1138:                                unsigned long rss;
                   1139: #if    TASK_SW_DEBUG
                   1140:                                if (task_swap_debug)
                   1141:                                    print_pid(outtask, local_page_free_avg / AVE_SCALE,
                   1142:                                              vm_page_free_target, "<",
                   1143:                                              "out");
                   1144: #endif
                   1145:                                rss = outtask->swap_rss;
                   1146:                                if (outtask->swap_nswap == 1)
                   1147:                                        rss /= 2; /* divide by 2 if never out */
                   1148:                                local_page_free_avg += (rss/short_avg_interval) * AVE_SCALE;
                   1149:                        }
                   1150:                        if (outtask != TASK_NULL)
                   1151:                                task_deallocate(outtask);
                   1152:                }
                   1153: 
                   1154:                /*
                   1155:                 * If there is an eligible task to bring in and there are at
                   1156:                 * least vm_page_free_target free pages, swap it in.  If task
                   1157:                 * swapping has been disabled, bring the task in anyway.
                   1158:                 */
                   1159:                if (intask && ((local_page_free_avg / AVE_SCALE) >=
                   1160:                                                        vm_page_free_target ||
                   1161:                                stop_swapping || !task_swap_enable)) {
                   1162:                        if (task_swapin(intask, FALSE) == KERN_SUCCESS) {
                   1163:                                unsigned long rss;
                   1164: #if    TASK_SW_DEBUG
                   1165:                                if (task_swap_debug)
                   1166:                                    print_pid(intask, local_page_free_avg / AVE_SCALE,
                   1167:                                              vm_page_free_target, ">=",
                   1168:                                              "in");
                   1169: #endif
                   1170:                                rss = intask->swap_rss;
                   1171:                                if (intask->swap_nswap == 1)
                   1172:                                        rss /= 2; /* divide by 2 if never out */
                   1173:                                local_page_free_avg -= (rss/short_avg_interval) * AVE_SCALE;
                   1174:                        }
                   1175:                }
                   1176:                /*
                   1177:                 * XXX
                   1178:                 * Here we have to decide whether to continue swapping
                   1179:                 * in and/or out before sleeping.  The decision should
                   1180:                 * be made based on the previous action (swapin/out) and
                   1181:                 * current system parameters, such as paging rates and
                   1182:                 * demand.
                   1183:                 * The function, compute_vm_averages, which does these
                   1184:                 * calculations, depends on being called every second,
                   1185:                 * so we can't just do the same thing.
                   1186:                 */
                   1187:                if (++loopcnt < MAX_LOOP)
                   1188:                        continue;
                   1189: 
                   1190:                /*
                   1191:                 * Arrange to be awakened if paging is still heavy or there are
                   1192:                 * any tasks partially or completely swapped out.  (Otherwise,
                   1193:                 * the wakeup will come from the external trigger(s).)
                   1194:                 */
                   1195:                timeout = 0;
                   1196:                if (start_swapping)
                   1197:                        timeout = task_swap_cycle_time;
                   1198:                else {
                   1199:                        task_swapper_lock();
                   1200:                        if (!queue_empty(&swapped_tasks))
                   1201:                                timeout = min_swap_time;
                   1202:                        task_swapper_unlock();
                   1203:                }
                   1204:                assert_wait((event_t)&swapped_tasks, THREAD_UNINT);
                   1205:                if (timeout) {
                   1206:                        if (task_swap_debug)
                   1207:                                printf("task_swapper: set timeout of %d\n",
                   1208:                                                                timeout);
                   1209:                        thread_set_timeout(timeout, NSEC_PER_SEC);
                   1210:                }
                   1211:                if (task_swap_debug)
                   1212:                        printf("task_swapper: blocking\n");
                   1213:                thread_block((void (*)(void)) 0);
                   1214:                if (timeout) {
                   1215:                        thread_cancel_timeout(current_thread());
                   1216:                }
                   1217:                /* reset locals */
                   1218:                loopcnt = 0;
                   1219:                local_page_free_avg = vm_page_free_avg;
                   1220:        }
                   1221:        }
                   1222: }
                   1223: 
                   1224: /* from BSD */
                   1225: #define ave(smooth, cnt, time) \
                   1226:        smooth = ((time - 1) * (smooth) + ((cnt) * AVE_SCALE)) / (time)
                   1227: 
                   1228: /*
                   1229:  * We estimate the system paging load in more than one metric: 
                   1230:  *     1) the total number of calls into the function, vm_page_grab, 
                   1231:  *        which allocates all page frames for real pages.
                   1232:  *     2) the total number of pages paged in and out of paging files.
                   1233:  *        This is a measure of page cleaning and faulting from backing
                   1234:  *        store.
                   1235:  *
                   1236:  * When either metric passes a threshold, tasks are swapped out.
                   1237:  */
                   1238: long last_grab_count = 0;
                   1239: long last_pageout_count = 0;
                   1240: 
                   1241: /*
                   1242:  * compute_vm_averages: [exported]
                   1243:  *
                   1244:  * This function is to be called once a second to calculate average paging
                   1245:  * demand and average numbers of free pages for use by the task swapper.
                   1246:  * Can also be used to wake up task swapper at desired thresholds.
                   1247:  *
                   1248:  * NOTE: this function is single-threaded, and requires locking if
                   1249:  *     ever there are multiple callers.
                   1250:  */
                   1251: void
                   1252: compute_vm_averages(void)
                   1253: {
                   1254:        extern unsigned long vm_page_grab_count;
                   1255:        long grab_count, pageout_count;
                   1256:        int i;
                   1257: 
                   1258:        ave(vm_page_free_avg, vm_page_free_count, short_avg_interval);
                   1259:        ave(vm_page_free_longavg, vm_page_free_count, long_avg_interval);
                   1260: 
                   1261:        /* 
                   1262:         * NOTE: the vm_page_grab_count and vm_stat structure are 
                   1263:         * under control of vm_page_queue_free_lock.  We're simply reading
                   1264:         * memory here, and the numbers don't depend on each other, so
                   1265:         * no lock is taken.
                   1266:         */
                   1267: 
                   1268:        grab_count = vm_page_grab_count;
                   1269:        pageout_count = 0;
                   1270:        for (i = 0; i < NCPUS; i++) {
                   1271:                pageout_count += vm_stat[i].pageouts;
                   1272:        }
                   1273: 
                   1274:        ave(vm_pageout_rate_avg, pageout_count - last_pageout_count,
                   1275:            short_avg_interval);
                   1276:        ave(vm_pageout_rate_longavg, pageout_count - last_pageout_count,
                   1277:            long_avg_interval);
                   1278:        ave(vm_grab_rate_avg, grab_count - last_grab_count,
                   1279:            short_avg_interval);
                   1280:        last_grab_count = grab_count;
                   1281:        last_pageout_count = pageout_count;
                   1282: 
                   1283:        /*
                   1284:         * Adjust swap_{start,stop}_pageout_rate to the paging rate peak.
                   1285:         * This is an attempt to find the optimum paging rates at which
                   1286:         * to trigger task swapping on or off to regulate paging activity,
                   1287:         * depending on the hardware capacity.
                   1288:         */
                   1289:        if (vm_pageout_rate_avg > vm_pageout_rate_peakavg) {
                   1290:                unsigned int desired_max;
                   1291: 
                   1292:                vm_pageout_rate_peakavg = vm_pageout_rate_avg;
                   1293:                swap_start_pageout_rate =
                   1294:                        vm_pageout_rate_peakavg * swap_pageout_high_water_mark / 100;
                   1295:                swap_stop_pageout_rate = 
                   1296:                        vm_pageout_rate_peakavg * swap_pageout_low_water_mark / 100;
                   1297:        }
                   1298: 
                   1299: #if    TASK_SW_DEBUG
                   1300:        /*
                   1301:         * For measurements, allow fixed values.
                   1302:         */
                   1303:        if (fixed_swap_start_pageout_rate)
                   1304:                swap_start_pageout_rate = fixed_swap_start_pageout_rate;
                   1305:        if (fixed_swap_stop_pageout_rate)
                   1306:                swap_stop_pageout_rate = fixed_swap_stop_pageout_rate;
                   1307: #endif /* TASK_SW_DEBUG */
                   1308: 
                   1309: #if    TASK_SW_DEBUG
                   1310:        if (task_swap_stats)
                   1311:                printf("vm_avgs: pageout_rate: %d %d (on/off: %d/%d); page_free: %d %d (tgt: %d)\n",
                   1312:                       vm_pageout_rate_avg / AVE_SCALE,
                   1313:                       vm_pageout_rate_longavg / AVE_SCALE,
                   1314:                       swap_start_pageout_rate / AVE_SCALE,
                   1315:                       swap_stop_pageout_rate / AVE_SCALE,
                   1316:                       vm_page_free_avg / AVE_SCALE,
                   1317:                       vm_page_free_longavg / AVE_SCALE,
                   1318:                       vm_page_free_target);
                   1319: #endif /* TASK_SW_DEBUG */
                   1320:        
                   1321:        if (vm_page_free_avg / AVE_SCALE <= vm_page_free_target) {
                   1322:                if (task_swap_on) {
                   1323:                        /* The following is a delicate attempt to balance the
                   1324:                         * need for reasonably rapid response to system
                   1325:                         * thrashing, with the equally important desire to
                   1326:                         * prevent the onset of swapping simply because of a
                   1327:                         * short burst of paging activity.
                   1328:                         */
                   1329:                        if ((vm_pageout_rate_longavg > swap_stop_pageout_rate) &&
                   1330:                            (vm_pageout_rate_avg > swap_start_pageout_rate) ||
                   1331:                            (vm_pageout_rate_avg > vm_pageout_rate_peakavg) ||
                   1332:                            (vm_grab_rate_avg > max_grab_rate))
                   1333:                                wake_task_swapper(FALSE);
                   1334:                }
                   1335:        } else /* page demand is low; should consider swapin */ {
                   1336:                if (tasks_swapped_out != 0)
                   1337:                        wake_task_swapper(TRUE);
                   1338:        }
                   1339: }
                   1340: 
                   1341: void
                   1342: task_swapout_eligible(task_t task)
                   1343: {
                   1344: #if    TASK_SW_DEBUG
                   1345:        task_swapper_lock();
                   1346:        if (task_swap_debug && on_swapped_list(task)) {
                   1347:                printf("swapout_eligible: task 0x%X on swapped list\n", task);
                   1348:                Debugger("");
                   1349:        }
                   1350:        task_swapper_unlock();
                   1351: #endif
                   1352:        task_swapout_lock();
                   1353:        task_lock(task);
                   1354: #if    TASK_SW_DEBUG
                   1355:        if (task->swap_flags & TASK_SW_ELIGIBLE) {
                   1356:                printf("swapout_eligible: task 0x%X already eligible\n", task);
                   1357:        }
                   1358: #endif /* TASK_SW_DEBUG */
                   1359:        if ((task->swap_state == TASK_SW_IN) &&
                   1360:            ((task->swap_flags & TASK_SW_ELIGIBLE) == 0)) {
                   1361:                queue_enter(&eligible_tasks,task,task_t,swapped_tasks);
                   1362:                task->swap_flags |= TASK_SW_ELIGIBLE;
                   1363:        }
                   1364:        task_unlock(task);
                   1365:        task_swapout_unlock();
                   1366: }
                   1367: 
                   1368: void
                   1369: task_swapout_ineligible(task_t task)
                   1370: {
                   1371: #if    TASK_SW_DEBUG
                   1372:        task_swapper_lock();
                   1373:        if (task_swap_debug && on_swapped_list(task)) {
                   1374:                printf("swapout_ineligible: task 0x%X on swapped list\n", task);
                   1375:                Debugger("");
                   1376:        }
                   1377:        task_swapper_unlock();
                   1378: #endif
                   1379:        task_swapout_lock();
                   1380:        task_lock(task);
                   1381: #if    TASK_SW_DEBUG
                   1382:        if (!(task->swap_flags & TASK_SW_ELIGIBLE))
                   1383:                printf("swapout_ineligible: task 0x%X already inel.\n", task);
                   1384: #endif /* TASK_SW_DEBUG */
                   1385:        if ((task->swap_state != TASK_SW_IN) && 
                   1386:            (task->swap_flags & TASK_SW_ELIGIBLE)) {
                   1387:                queue_remove(&eligible_tasks, task, task_t, swapped_tasks);
                   1388:                task->swap_flags &= ~TASK_SW_ELIGIBLE;
                   1389:        }
                   1390:        task_unlock(task);
                   1391:        task_swapout_unlock();
                   1392: }
                   1393: 
                   1394: int task_swap_ast_aborted = 0;
                   1395: 
                   1396: /*
                   1397:  *     Process an AST_SWAPOUT.
                   1398:  */
                   1399: void
                   1400: swapout_ast()
                   1401: {
                   1402:        spl_t           s;
                   1403:        thread_act_t    act;
                   1404:        thread_t        thread;
                   1405: 
                   1406:        act = current_act();
                   1407: 
                   1408:        /*
                   1409:         * Task is being swapped out.  First mark it as suspended
                   1410:         * and halted, then call thread_swapout_enqueue to put
                   1411:         * the thread on the queue for task_swap_swapout_threads
                   1412:         * to swap out the thread.
                   1413:         */
                   1414:        /*
                   1415:         * Don't swap unswappable threads
                   1416:         */
                   1417:        thread = act_lock_thread(act);
                   1418:        s = splsched();
                   1419:        if (thread)
                   1420:                thread_lock(thread);
                   1421:        if ((act->ast & AST_SWAPOUT) == 0) {
                   1422:                /*
                   1423:                 * Race with task_swapin. Abort swapout.
                   1424:                 */
                   1425:                task_swap_ast_aborted++;        /* not locked XXX */
                   1426:                if (thread)
                   1427:                        thread_unlock(thread);
                   1428:                splx(s);
                   1429:                act_unlock_thread(act);
                   1430:        } else if (act->swap_state == TH_SW_IN) {
                   1431:                /*
                   1432:                 * Mark swap_state as TH_SW_TASK_SWAPPING to avoid
                   1433:                 * race with thread swapper, which will only
                   1434:                 * swap thread if swap_state is TH_SW_IN.
                   1435:                 * This way, the thread can only be swapped by
                   1436:                 * the task swapping mechanism.
                   1437:                 */
                   1438:                act->swap_state |= TH_SW_TASK_SWAPPING;
                   1439:                /* assert(act->suspend_count == 0); XXX ? */
                   1440:                if (thread)
                   1441:                        thread_unlock(thread);
                   1442:                if (act->suspend_count++ == 0)  /* inline thread_hold */
                   1443:                        install_special_handler(act);
                   1444:                /* self->state |= TH_HALTED; */
                   1445:                thread_ast_clear(act, AST_SWAPOUT);
                   1446:                /*
                   1447:                 * Initialize the swap_queue fields to allow an extra
                   1448:                 * queue_remove() in task_swapin if we lose the race
                   1449:                 * (task_swapin can be called before we complete
                   1450:                 * thread_swapout_enqueue).
                   1451:                 */
                   1452:                queue_init((queue_t) &act->swap_queue);
                   1453:                splx(s);
                   1454:                act_unlock_thread(act);
                   1455:                /* this must be called at normal interrupt level */
                   1456:                thread_swapout_enqueue(act);
                   1457:        } else {
                   1458:                /* thread isn't swappable; continue running */
                   1459:                assert(act->swap_state == TH_SW_UNSWAPPABLE);
                   1460:                if (thread)
                   1461:                        thread_unlock(thread);
                   1462:                thread_ast_clear(act, AST_SWAPOUT);
                   1463:                splx(s);
                   1464:                act_unlock_thread(act);
                   1465:        }
                   1466: }
                   1467: 
                   1468: #endif /* TASK_SWAPPER */

unix.superglobalmegacorp.com

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