|
|
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(<ask->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 */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.