|
|
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: * Mach Operating System
27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
28: * All Rights Reserved.
29: *
30: * Permission to use, copy, modify and distribute this software and its
31: * documentation is hereby granted, provided that both the copyright
32: * notice and this permission notice appear in all copies of the
33: * software, derivative works or modified versions, and any portions
34: * thereof, and that both notices appear in supporting documentation.
35: *
36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
39: *
40: * Carnegie Mellon requests users of this software to return to
41: *
42: * Software Distribution Coordinator or [email protected]
43: * School of Computer Science
44: * Carnegie Mellon University
45: * Pittsburgh PA 15213-3890
46: *
47: * any improvements or extensions that they make and grant Carnegie Mellon
48: * the rights to redistribute these changes.
49: */
50: /*
51: */
52: /*
53: *
54: * File: kern/thread_swap.c
55: * Author: Avadis Tevanian, Jr.
56: * Date: 1987
57: *
58: * Mach thread swapper:
59: * Find idle threads to swap, freeing up kernel stack resources
60: * at the expense of allowing them to execute.
61: *
62: * Swap in threads that need to be run. This is done here
63: * by the swapper thread since it cannot be done (in general)
64: * when the kernel tries to place a thread on a run queue.
65: *
66: * Note: The act of swapping a thread in Mach does not mean that
67: * its memory gets forcibly swapped to secondary storage. The memory
68: * for the task corresponding to a swapped thread is paged out
69: * through the normal paging mechanism.
70: *
71: */
72: #if 1
73:
74: #include <kern/thread.h>
75: #include <kern/lock.h>
76: #include <vm/vm_map.h>
77: #include <vm/vm_kern.h>
78: #include <mach/vm_param.h>
79: #include <kern/sched_prim.h>
80: #include <kern/sf.h>
81: #include <kern/processor.h>
82: #include <kern/thread_swap.h>
83: #include <kern/spl.h> /* for splsched */
84: #include <kern/misc_protos.h>
85: #include <kern/counters.h>
86: #include <mach/policy.h>
87:
88: queue_head_t swapin_queue;
89: decl_simple_lock_data(, swapper_lock_data)
90:
91: #define swapper_lock() simple_lock(&swapper_lock_data)
92: #define swapper_unlock() simple_unlock(&swapper_lock_data)
93:
94: mach_counter_t c_swapin_thread_block;
95:
96: /*
97: * swapper_init: [exported]
98: *
99: * Initialize the swapper module.
100: */
101: void swapper_init()
102: {
103: queue_init(&swapin_queue);
104: simple_lock_init(&swapper_lock_data, ETAP_THREAD_SWAPPER);
105: }
106:
107: /*
108: * thread_swapin: [exported]
109: *
110: * Place the specified thread in the list of threads to swapin. It
111: * is assumed that the thread is locked, therefore we are at splsched.
112: *
113: * We don't bother with stack_alloc_try to optimize swapin;
114: * our callers have already tried that route.
115: */
116:
117: void thread_swapin(thread)
118: thread_t thread;
119: {
120: switch (thread->state & TH_STACK_STATE) {
121: case TH_STACK_HANDOFF:
122: /*
123: * Swapped out - queue for swapin thread.
124: */
125: thread->state = (thread->state & ~TH_STACK_STATE)
126: | TH_STACK_COMING_IN;
127: swapper_lock();
128: enqueue_tail(&swapin_queue, (queue_entry_t) thread);
129: swapper_unlock();
130: thread_wakeup((event_t) &swapin_queue);
131: break;
132:
133: case TH_STACK_COMING_IN:
134: /*
135: * Already queued for swapin thread, or being
136: * swapped in.
137: */
138: break;
139:
140: default:
141: /*
142: * Already swapped in.
143: */
144: panic("thread_swapin");
145: }
146: }
147:
148: /*
149: * thread_doswapin:
150: *
151: * Swapin the specified thread, if it should be runnable, then put
152: * it on a run queue. No locks should be held on entry, as it is
153: * likely that this routine will sleep (waiting for stack allocation).
154: */
155: void thread_doswapin(thread)
156: register thread_t thread;
157: {
158: spl_t s;
159: vm_offset_t stack;
160:
161: /*
162: * do machdep allocation
163: */
164:
165: /*
166: * Allocate the kernel stack.
167: */
168: stack = stack_alloc(thread, thread_continue);
169: assert(stack);
170:
171: /*
172: * Place on run queue.
173: */
174:
175: s = splsched();
176: thread_lock(thread);
177: thread->state &= ~(TH_STACK_HANDOFF | TH_STACK_COMING_IN);
178: if (thread->state & TH_RUN)
179: thread_setrun(thread, TRUE, FALSE);
180: thread_unlock(thread);
181: (void) splx(s);
182: }
183:
184: /*
185: * swapin_thread: [exported]
186: *
187: * This procedure executes as a kernel thread. Threads that need to
188: * be swapped in are swapped in by this thread.
189: */
190: void swapin_thread_continue()
191: {
192: for (;;) {
193: register thread_t thread;
194: spl_t s;
195:
196: s = splsched();
197: swapper_lock();
198:
199: while ((thread = (thread_t) dequeue_head(&swapin_queue))
200: != THREAD_NULL) {
201: swapper_unlock();
202: (void) splx(s);
203:
204: thread_doswapin(thread); /* may block */
205:
206: s = splsched();
207: swapper_lock();
208: }
209:
210: assert_wait((event_t) &swapin_queue, THREAD_UNINT);
211: swapper_unlock();
212: (void) splx(s);
213: counter(c_swapin_thread_block++);
214: #if 1
215: thread_block(swapin_thread_continue);
216: #else
217: thread_block((void (*)(void)) 0);
218: #endif
219: }
220: }
221:
222: void swapin_thread()
223: {
224: stack_privilege(current_thread());
225: current_thread()->vm_privilege = TRUE;
226:
227: swapin_thread_continue();
228: /*NOTREACHED*/
229: }
230:
231: #else /* UNUSED CODE FOLLOWS */
232:
233: #include <kern/thread.h>
234: #include <kern/lock.h>
235: #include <vm/vm_map.h>
236: #include <vm/vm_kern.h>
237: #include <mach/vm_param.h>
238: #include <kern/sched_prim.h>
239: #include <kern/sf.h>
240: #include <kern/processor.h>
241: #include <kern/thread_swap.h>
242: #include <kern/spl.h> /* for splsched */
243: #include <kern/misc_protos.h>
244: #include <mach/policy.h>
245:
246: queue_head_t swapin_queue;
247: decl_simple_lock_data(,swapper_lock)
248:
249: #define swapper_lock() simple_lock(&swapper_lock)
250: #define swapper_unlock() simple_unlock(&swapper_lock)
251:
252: #define THREAD_SW_DEBUG 1
253: int thread_swap_debug = 0;
254:
255: /*
256: * MAXSLP and MAX_SWAP_RATE can be overridden in vm_param.h, or by poking
257: * the global variable (lower-case) at any time.
258: *
259: * MAXSLP is the amount of time a thread will be allowed to sleep
260: * without being a candidate for idle thread swapping.
261: *
262: * MAX_SWAP_RATE is the number of scheduler ticks (see sched_prim.c),
263: * between periodic scans of the idle thread list. When the pageout
264: * daemon detects a severe page shortage, this rate is ignored. A
265: * scheduler tick is usually 1 second.
266: */
267: #ifndef MAXSLP
268: #define MAXSLP 10
269: #endif
270:
271: int maxslp = MAXSLP;
272:
273: #ifndef MAX_SWAP_RATE
274: #define MAX_SWAP_RATE 60
275: #endif
276:
277: int max_swap_rate = MAX_SWAP_RATE;
278:
279: /* should we unwire the kernel stack when a thread is swapped out ? */
280: #ifdef HP700___ /* CHECKME! Is this true anymore?? From Cambridge branch */
281: /*
282: * On HP/PA, kernel stacks are ghost pages that are mapped at their
283: * physical address (physical addr == virtual address). They're not
284: * on any page list or VM object, so they can't be paged out.
285: */
286: boolean_t thread_swap_unwire_stack = FALSE;
287: #else /* HP700 */
288: boolean_t thread_swap_unwire_stack = TRUE;
289: #endif /* HP700 */
290:
291: #if THREAD_SWAP_UNWIRE_USER_STACK
292: boolean_t thread_swap_unwire_user_stack = TRUE;
293: #else /* THREAD_SWAP_UNWIRE_USER_STACK */
294: #define thread_swap_unwire_user_stack FALSE
295: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
296:
297: /*
298: * thread_swapper_init: [exported]
299: *
300: * Initialize the swapper module.
301: */
302: void thread_swapper_init(void)
303: {
304: queue_init(&swapin_queue);
305: simple_lock_init(&swapper_lock, ETAP_THREAD_SWAPPER);
306: }
307:
308: /*
309: * thread_swapin: [exported]
310: *
311: * Place the specified thread in the list of threads to swapin. If
312: * thr_act is associated with a thread, the thread is locked; if not,
313: * the thr_act itself (i.e., its act_lock()) is locked. Since
314: * swapper_lock() must be taken at splsched(), we go to splsched()
315: * ourself to cover the latter case. The make_unswappable argument
316: * is used to ask swapin_thread to make thread unswappable.
317: *
318: * The naked references to thr_act->thread here are safe purely based
319: * on the assumption that only an activation itself can remove itself
320: * from an RPC chain. Since its thread is "swapped out", the activation
321: * cannot be running. Similarly, the reference to thread->top_act
322: * in calls to this function from scheduler code is safe purely because
323: * an RPC chain can change only under its own steam (i.e., if the
324: * associated thread is running).
325: *
326: * XXX - Shuttle cloning would break the above assumptions.
327: */
328:
329: void thread_swapin(
330: thread_act_t thr_act,
331: boolean_t make_unswappable)
332: {
333: spl_t s;
334:
335: switch (thr_act->swap_state & TH_SW_STATE) {
336: case TH_SW_OUT:
337: /*
338: * Swapped out - queue for swapin thread
339: */
340: thr_act->swap_state = TH_SW_COMING_IN;
341: s = splsched();
342: swapper_lock();
343: queue_enter(&swapin_queue, thr_act, thread_act_t, swap_queue);
344: swapper_unlock();
345: thread_wakeup((event_t) &swapin_queue);
346: splx(s);
347: break;
348:
349: case TH_SW_GOING_OUT:
350: /*
351: * Being swapped out - wait until swapped out,
352: * then queue for swapin thread (in thread_swapout).
353: */
354: thr_act->swap_state = TH_SW_WANT_IN;
355: break;
356:
357: case TH_SW_WANT_IN:
358: case TH_SW_COMING_IN:
359: /*
360: * Already queued for swapin thread, or being
361: * swapped in
362: */
363: break;
364:
365: default:
366: /*
367: * Swapped in or unswappable
368: */
369: panic("thread_swapin");
370: }
371:
372: /*
373: * Set make unswappable flag if asked to. swapin thread
374: * will make thread unswappable.
375: */
376: if (make_unswappable)
377: thr_act->swap_state |= TH_SW_MAKE_UNSWAPPABLE;
378: }
379:
380: /*
381: * thread_swapin_blocking: [exported]
382: *
383: * Mimic thread_swapin(), but block if swapin of our target thread
384: * has already been initiated, and call thread_doswapin() directly
385: * (instead of via swapin thread) if we initiate it ourself.
386: *
387: * Locking: if thr_act is on an RPC chain, the rpc_lock() for the
388: * attached shuttle is held; otherwise both the act_lock() for
389: * thr_act plus the ip_lock() for its thread_pool port are held.
390: * NB: if thr_act is attached to a thread, thread_lock() controls
391: * access to thr_act's swap_state.
392: */
393: boolean_t thread_swapin_blocking(
394: thread_act_t thr_act)
395: {
396: spl_t s;
397: thread_t thread, othread;
398:
399: #define lock_swap_state(thr_act) \
400: MACRO_BEGIN \
401: if (thr_act->thread) { \
402: s = splsched(); \
403: thread_lock(thr_act->thread); \
404: } \
405: MACRO_END
406:
407: #define unlock_swap_state(thr_act) \
408: MACRO_BEGIN \
409: if (thr_act->thread) { \
410: thread_unlock(thr_act->thread); \
411: splx(s); \
412: } \
413: MACRO_END
414:
415: for (thread = thr_act->thread; ; ) {
416: lock_swap_state(thr_act);
417: switch (thr_act->swap_state & TH_SW_STATE) {
418: case TH_SW_OUT:
419: /*
420: * Swapped all the way out -- start it back in.
421: */
422: thr_act->swap_state = TH_SW_COMING_IN;
423: unlock_swap_state(thr_act);
424: if (thread)
425: rpc_unlock(thread);
426: else {
427: ip_unlock(thr_act->pool_port);
428: act_unlock(thr_act);
429: }
430: thread_doswapin(thr_act);
431: relock:
432: othread = thread;
433: thread = act_lock_thread(thr_act);
434: /*
435: * We may resume with a shuttle attached
436: * after blocking with no shuttle attached,
437: * but should never move between shuttles.
438: */
439: if (othread && thread != othread)
440: panic("thread_swapin_blocking: act moved");
441: if (othread) {
442: /*
443: * XXX - don't care about this ip_lock (taken
444: * by act_lock_thread() if pool_port non-null)
445: */
446: if (thr_act->pool_port)
447: ip_unlock(thr_act->pool_port);
448: act_unlock(thr_act);
449: }
450: else if (thread) {
451: /*
452: * XXX - don't care about this rpc_lock (taken
453: * by act_lock_thread() if thread non-null)
454: */
455: rpc_unlock(thr_act->thread);
456: }
457: break;
458:
459: case TH_SW_GOING_OUT:
460: /*
461: * Not out yet -- have to wait till it is, then queue
462: * it for swapin.
463: */
464: thr_act->swap_state = TH_SW_WANT_IN;
465:
466: /* fall-through */
467:
468: case TH_SW_WANT_IN:
469: case TH_SW_COMING_IN:
470: /*
471: * On its way back -- wait for it to get here.
472: */
473: assert_wait((event_t)&thr_act->swap_state, THREAD_UNINT);
474: unlock_swap_state(thr_act);
475: if (thread)
476: rpc_unlock(thread);
477: else {
478: ip_unlock(thr_act->pool_port);
479: act_unlock(thr_act);
480: }
481: thread_block((void (*)(void))0);
482: goto relock;
483: break;
484:
485: default:
486: /*
487: * Swapped in or not swappable -- finally!
488: */
489: unlock_swap_state(thr_act);
490: return (TRUE);
491: }
492: if (!thr_act->active)
493: break; /* out of loop -- don'tcha love C? */
494: }
495: return (FALSE);
496: }
497:
498: #undef lock_swap_state
499: #undef unlock_swap_state
500:
501: /*
502: * thread_doswapin: [exported]
503: *
504: * Swapin the specified thread, if it should be runnable, then put
505: * it on a run queue. No locks should be held on entry, as it is
506: * likely that this routine will sleep (waiting for page faults).
507: */
508: void thread_doswapin(
509: thread_act_t thr_act)
510: {
511: register vm_offset_t addr;
512: register int s;
513: kern_return_t kr;
514: thread_t thread;
515: sched_policy_t *policy;
516: sf_return_t sfr;
517:
518: /*
519: * Wire down the kernel stack.
520: */
521:
522: if (thread_swap_unwire_stack && (thread = thr_act->thread)) {
523: assert(KERNEL_STACK_SIZE % page_size == 0);
524: addr = thread->kernel_stack;
525: /*
526: * This pagein can never fail
527: */
528: #if THREAD_SW_DEBUG
529: if (thread_swap_debug) {
530: printf("thread_doswapin(%x): wiring stack %x\n",
531: thr_act, trunc_page(addr));
532: }
533: #endif /* THREAD_SW_DEBUG */
534: #if MACH_ASSERT
535: assert(thr_act->kernel_stack_swapped_in == FALSE);
536: thr_act->kernel_stack_swapped_in = TRUE;
537: #endif /* MACH_ASSERT */
538: for (;;) {
539: kr = vm_map_wire(kernel_map, trunc_page(addr),
540: round_page(addr + KERNEL_STACK_SIZE),
541: VM_PROT_READ|VM_PROT_WRITE,
542: FALSE);
543: if (kr == KERN_SUCCESS) {
544: break;
545: }
546: if (kr != KERN_MEMORY_ERROR) {
547: printf("vm_map_wire returned 0x%x\n", kr);
548: panic("thread_doswapin");
549: }
550: thread_block((void (*)(void)) 0);
551: }
552: vm_map_simplify(kernel_map, addr);
553: }
554:
555: #if THREAD_SWAP_UNWIRE_USER_STACK
556: if (thread_swap_unwire_user_stack && thr_act->user_stack) {
557: vm_offset_t user_stack;
558: long user_stack_size; /* signed ! */
559: vm_offset_t start, end;
560:
561: user_stack = thr_act->user_stack;
562: user_stack_size = (long) thr_act->user_stack_size;
563: #if 0
564: assert(thr_act->user_stack_size % page_size == 0);
565: #endif
566: #if THREAD_SW_DEBUG
567: if (thread_swap_debug) {
568: printf("thread_doswapin(%x): wiring user stack %x\n",
569: thr_act, trunc_page(user_stack));
570: }
571: #endif /* THREAD_SW_DEBUG */
572: #if MACH_ASSERT
573: assert(thr_act->user_stack_swapped_in == FALSE);
574: thr_act->user_stack_swapped_in = TRUE;
575: #endif /* MACH_ASSERT */
576: assert(thr_act->map != VM_MAP_NULL);
577: if (user_stack_size > 0) {
578: /* stack grows up */
579: start = trunc_page(user_stack);
580: end = round_page(user_stack + user_stack_size - 1);
581: } else {
582: /* stack grows down */
583: start = trunc_page(user_stack + user_stack_size + 1);
584: end = round_page(user_stack);
585: }
586: for (;;) {
587: kr = vm_map_wire(thr_act->map, start, end,
588: VM_PROT_READ|VM_PROT_WRITE,
589: TRUE);
590: if (kr == KERN_SUCCESS) {
591: break;
592: }
593: if (kr != KERN_MEMORY_ERROR) {
594: printf("vm_map_wire(user) returned 0x%x\n", kr);
595: panic("thread_doswapin 2");
596: }
597: thread_block((void (*)(void)) 0);
598: }
599: vm_map_simplify(thr_act->map, start);
600: }
601: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
602:
603: /*
604: * Make unswappable and wake up waiting thread(s) if needed.
605: * Place on run queue if appropriate.
606: *
607: * This function only operates on threads that had a state
608: * of TH_SW_OUT at one time, in which case, there needs
609: * to be a reference on the task's resident thread count.
610: */
611:
612: /*
613: * Increment the resident thread count for the task.
614: * This has no direct effect here, but serves as a counter
615: * for the pmap_collect call in thread_swapout.
616: */
617: if (thr_act->task != TASK_NULL) {
618: mutex_lock(&thr_act->task->act_list_lock);
619: ++thr_act->task->res_act_count;
620: mutex_unlock(&thr_act->task->act_list_lock);
621: }
622:
623: thread = act_lock_thread(thr_act);
624: if (thread != THREAD_NULL) {
625: s = splsched();
626: thread_lock(thread);
627: }
628: if (thr_act->swap_state & TH_SW_MAKE_UNSWAPPABLE) {
629: thr_act->swap_state = TH_SW_UNSWAPPABLE;
630: } else {
631: thr_act->swap_state = TH_SW_IN;
632: }
633:
634: if (thread != THREAD_NULL) {
635: if (thread->top_act == thr_act) {
636: thread->state &= ~TH_SWAPPED_OUT;
637: if (thread->state & TH_RUN) {
638: policy = &sched_policy[thread->policy];
639: sfr = sched_policy->sp_ops.sp_thread_unblock(
640: policy, thread);
641: assert(sfr == SF_SUCCESS);
642: }
643: }
644: thread_unlock(thread);
645: (void) splx(s);
646: }
647: thread_wakeup((event_t)&thr_act->swap_state);
648: act_unlock_thread(thr_act);
649: }
650:
651: /*
652: * thread_swapout: [exported]
653: *
654: * Swap out the specified thread (unwire its kernel stack).
655: * The thread must already be marked as 'swapping out'.
656: *
657: * Decrement the resident thread count for the task, and if
658: * it goes to zero, call pmap_collect on the task's pmap.
659: *
660: * The thread has an extra reference (obtained by the caller)
661: * to keep it from being deallocated during swapout.
662: */
663: void thread_swapout(
664: thread_act_t thr_act)
665: {
666: register vm_offset_t addr;
667: register boolean_t make_unswappable;
668: boolean_t collect;
669: int s;
670: kern_return_t kr;
671: thread_t thread;
672:
673: /*
674: * Thread is marked as swapped before we swap it out; if
675: * it is awakened while we are swapping it out, it will
676: * be put on the swapin list.
677: */
678:
679: /*
680: * Notify the pcb module that it must update any
681: * hardware state associated with this thread.
682: */
683: #if 0 /* XXX */
684: pcb_synch(thread);
685: #endif
686:
687: /*
688: * Unwire the kernel stack.
689: * No need to lock the thread to check TH_STACK_HANDOFF and
690: * get its kernel_stack address, since the thread is blocked
691: * somewhere and can't restart without being swapped back in.
692: */
693:
694: if (thread_swap_unwire_stack && (thread = thr_act->thread)) {
695: assert(KERNEL_STACK_SIZE % page_size == 0);
696: addr = thread->kernel_stack;
697: #if THREAD_SW_DEBUG
698: if (thread_swap_debug) {
699: printf("thread_swapout(%x):unwiring stack %x\n",
700: thr_act, trunc_page(addr));
701: }
702: #endif /* THREAD_SW_DEBUG */
703: #if MACH_ASSERT
704: assert(thr_act->kernel_stack_swapped_in == TRUE);
705: thr_act->kernel_stack_swapped_in = FALSE;
706: #endif /* MACH_ASSERT */
707: kr = vm_map_unwire(kernel_map, trunc_page(addr),
708: round_page(addr +
709: KERNEL_STACK_SIZE),
710: FALSE);
711: if (kr != KERN_SUCCESS) {
712: printf("vm_map_unwire returned %x\n", kr);
713: panic("thread_swapout");
714: }
715: vm_map_simplify(kernel_map, addr);
716: }
717:
718: #if THREAD_SWAP_UNWIRE_USER_STACK
719: if (thread_swap_unwire_user_stack && thr_act->user_stack) {
720: vm_offset_t user_stack;
721: long user_stack_size; /* signed ! */
722: vm_offset_t start, end;
723:
724: user_stack = thr_act->user_stack;
725: user_stack_size = thr_act->user_stack_size;
726: #if 0
727: assert(user_stack_size % page_size == 0);
728: #endif
729: #if THREAD_SW_DEBUG
730: if (thread_swap_debug) {
731: printf("thread_swapout(%x):unwiring user stack %x\n",
732: thr_act, trunc_page(user_stack));
733: }
734: #endif /* THREAD_SW_DEBUG */
735: #if MACH_ASSERT
736: assert(thr_act->user_stack_swapped_in == TRUE);
737: thr_act->user_stack_swapped_in = FALSE;
738: #endif /* MACH_ASSERT */
739: assert(thr_act->map != VM_MAP_NULL);
740: if (user_stack_size > 0) {
741: /* stack grows up */
742: start = trunc_page(user_stack);
743: end = round_page(user_stack + user_stack_size - 1);
744: } else {
745: /* stack grows down */
746: start = trunc_page(user_stack + user_stack_size + 1);
747: end = round_page(user_stack);
748: }
749: kr = vm_map_unwire(thr_act->map, start, end, TRUE);
750: if (kr != KERN_SUCCESS) {
751: printf("vm_map_unwire(user_stack) returned %x\n", kr);
752: panic("thread_swapout 2");
753: }
754: vm_map_simplify(thr_act->map, start);
755: }
756: #endif /* THREAD_SWAP_UNWIRE_USER_STACK */
757:
758: /*
759: * Arrange to call pmap_collect if this is the last resident
760: * thread for its task. The task and its map aren't going
761: * anywhere because of the extra reference on this thread.
762: */
763: mutex_lock(&thr_act->task->act_list_lock);
764: collect = (--thr_act->task->res_act_count == 0);
765: mutex_unlock(&thr_act->task->act_list_lock);
766:
767: thread = act_lock_thread(thr_act);
768: s = splsched();
769: if (thread)
770: thread_lock(thread);
771: switch (thr_act->swap_state & TH_SW_STATE) {
772: case TH_SW_GOING_OUT:
773: thr_act->swap_state = TH_SW_OUT;
774: break;
775:
776: case TH_SW_WANT_IN:
777: /* didn't get it out fast enough */
778: make_unswappable = thr_act->swap_state & TH_SW_MAKE_UNSWAPPABLE;
779: thr_act->swap_state = TH_SW_OUT;
780: thread_swapin(thr_act, make_unswappable);
781: collect = FALSE; /* don't pmap_collect */
782: break;
783:
784: default:
785: panic("thread_swapout");
786: }
787: if (thread)
788: thread_unlock(thread);
789: splx(s);
790: act_unlock_thread(thr_act);
791: if (collect) {
792: /* task and map can't disappear yet */
793: assert((thr_act->task != TASK_NULL) &&
794: (thr_act->task->map != VM_MAP_NULL));
795: pmap_collect(vm_map_pmap(thr_act->task->map));
796: }
797: }
798:
799: /*
800: * swapin_thread: [exported]
801: *
802: * This procedure executes as a kernel thread. Threads that need to
803: * be swapped in are swapped in by this thread.
804: */
805: void swapin_thread(void)
806: {
807: thread_swappable(current_act(), FALSE);
808: stack_privilege(current_thread());
809:
810: while (TRUE) {
811: register thread_act_t thr_act;
812: register int s;
813:
814: s = splsched();
815: swapper_lock();
816:
817: while (! queue_empty(&swapin_queue)) {
818: queue_remove_first(&swapin_queue, thr_act, thread_act_t,
819: swap_queue);
820: swapper_unlock();
821: splx(s);
822:
823: thread_doswapin(thr_act);
824:
825: s = splsched();
826: swapper_lock();
827: }
828:
829: assert_wait((event_t) &swapin_queue, THREAD_UNINT);
830: swapper_unlock();
831: splx(s);
832: thread_block((void (*)(void)) 0);
833: }
834: }
835:
836: boolean_t thread_swapout_allowed = TRUE;
837:
838: int last_swap_tick = 0;
839:
840: /*
841: * swapout_threads: [exported]
842: *
843: * This procedure is called periodically by the pageout daemon. It
844: * determines if it should scan for threads to swap and starts that
845: * scan if appropriate.
846: * The pageout daemon sets the now flag if all the page queues are
847: * empty and it wants to start the swapper right away.
848: */
849: void swapout_threads(
850: boolean_t now)
851: {
852: if (thread_swapout_allowed &&
853: (now || (sched_tick > (last_swap_tick + max_swap_rate)))) {
854: last_swap_tick = sched_tick;
855: thread_wakeup((event_t) &last_swap_tick); /* poke swapper */
856: thread_block((void (*)(void)) 0);/* let it run if it wants to */
857: }
858: }
859:
860: boolean_t thread_swapout_empty_acts = FALSE;
861:
862: void swapout_scan(void); /* forward */
863:
864: /*
865: * swapout_scan:
866: *
867: * Scan the list of all threads looking for threads to swap.
868: */
869: void swapout_scan(void)
870: {
871: register int s;
872: register thread_t thread, prev_thread;
873: processor_set_t pset, prev_pset;
874: thread_act_t thr_act, prev_act;
875: task_t task, prev_task;
876:
877: zone_gc();
878:
879: prev_thread = THREAD_NULL;
880: prev_act = THR_ACT_NULL;
881: prev_task = TASK_NULL;
882: prev_pset = PROCESSOR_SET_NULL;
883: /*
884: * Ugh. If an activation is terminated while being swapped
885: * out, we can no longer count on consistency of the lists
886: * we're traversing, so we have to start over.
887: *
888: * Note: we deliberately leave the "prev" variables alone if
889: * we restart -- we will remove a ref to them as needed in
890: * the normal operation of the loop.
891: */
892: restart:
893: mutex_lock(&all_psets_lock);
894: pset = (processor_set_t) queue_first(&all_psets);
895: while (!queue_end(&all_psets, (queue_entry_t) pset)) {
896: pset_lock(pset);
897: task = (task_t) queue_first(&pset->tasks);
898: while (!queue_end(&pset->tasks, (queue_entry_t) task)) {
899: task_lock(task);
900: thr_act = (thread_act_t) queue_first(&task->thr_acts);
901: while (!queue_end(&task->thr_acts,
902: (queue_entry_t) thr_act)) {
903: boolean_t swap_it;
904: thread_act_t act;
905:
906: thread = act_lock_thread(thr_act);
907: s = splsched();
908: if (thread != THREAD_NULL) {
909: thread_lock(thread);
910: swap_it = TRUE;
911: for (act = thread->top_act; act; act = act->lower)
912: if (act->swap_state == TH_SW_UNSWAPPABLE) {
913: swap_it = FALSE;
914: break;
915: }
916: if (!swap_it)
917: ;
918: else if (
919: /* don't swap real-time threads */
920: (thread->policy &
921: POLICYCLASS_FIXEDPRI) != 0 ||
922: (thread->state &
923: (TH_RUN|TH_SWAPPED_OUT)) != 0 ||
924: thr_act->swap_state != TH_SW_IN ||
925: (thread->state & TH_UNINT) != 0 ||
926: (sched_tick-thread->sleep_stamp <=
927: maxslp) ||
928: !thr_act->active) {
929: swap_it = FALSE;
930: }
931: } else {
932: if (! thread_swapout_empty_acts) {
933: splx(s);
934: act_unlock_thread(thr_act);
935: thr_act = (thread_act_t)
936: queue_next(&thr_act->thr_acts);
937: continue;
938: }
939: if (thr_act->swap_state == TH_SW_IN &&
940: thr_act->active &&
941: thr_act->thread_pool_next) {
942: swap_it = TRUE;
943: } else {
944: swap_it = FALSE;
945: }
946: }
947: if (swap_it) {
948: thr_act->swap_state = TH_SW_GOING_OUT;
949: if (thread != THREAD_NULL) {
950: if (thread->top_act ==
951: thr_act) {
952: thread->state |=
953: TH_SWAPPED_OUT;
954: }
955: thread->ref_count++;
956: thread_unlock(thread);
957: }
958: act_locked_act_reference(thr_act);
959: (void) splx(s);
960: act_unlock_thread(thr_act);
961: task->ref_count++;
962: task_unlock(task);
963: pset->ref_count++;
964: pset_unlock(pset);
965: mutex_unlock(&all_psets_lock);
966:
967: thread_swapout(thr_act); /* swap it */
968:
969: if (prev_thread != THREAD_NULL) {
970: thread_deallocate(prev_thread);
971: }
972: if (prev_act != THR_ACT_NULL) {
973: act_deallocate(prev_act);
974: }
975: if (prev_task != TASK_NULL) {
976: task_deallocate(prev_task);
977: }
978: if (prev_pset != PROCESSOR_SET_NULL)
979: pset_deallocate(prev_pset);
980:
981: prev_thread = thread;
982: prev_act = thr_act;
983: prev_task = task;
984: prev_pset = pset;
985: mutex_lock(&all_psets_lock);
986: pset_lock(pset);
987: task_lock(task);
988: thread = act_lock_thread(thr_act);
989: /*
990: * See if current act was terminated; if so,
991: * can't continue with current traversal --
992: * we don't have a valid "next" pointer, and
993: * there's no certain way to acquire one.
994: *
995: * Also check for task having moved between
996: * psets; don't want to continue current
997: * traversal if it has. (The traversal would
998: * be valid in this case, just not complete.)
999: */
1000: if (!thr_act->active || task->processor_set != pset) {
1001: act_unlock_thread(thr_act);
1002: task_unlock(task);
1003: pset_unlock(pset);
1004: mutex_unlock(&all_psets_lock);
1005: goto restart;
1006: }
1007:
1008: s = splsched();
1009: assert(!prev_thread || thread == prev_thread);
1010: } else {
1011: if (thread != THREAD_NULL)
1012: thread_unlock(thread);
1013: }
1014: splx(s);
1015: act_unlock_thread(thr_act);
1016: thr_act = (thread_act_t)
1017: queue_next(&thr_act->thr_acts);
1018: }
1019: task_unlock(task);
1020: task = (task_t) queue_next(&task->pset_tasks);
1021: }
1022: pset_unlock(pset);
1023: pset = (processor_set_t) queue_next(&pset->all_psets);
1024: }
1025: mutex_unlock(&all_psets_lock);
1026:
1027: if (prev_thread != THREAD_NULL) {
1028: thread_deallocate(prev_thread);
1029: }
1030: if (prev_act != THR_ACT_NULL) {
1031: act_deallocate(prev_act);
1032: }
1033: if (prev_task != TASK_NULL) {
1034: task_deallocate(prev_task);
1035: }
1036: if (prev_pset != PROCESSOR_SET_NULL)
1037: pset_deallocate(prev_pset);
1038: }
1039:
1040: /*
1041: * swapout_thread: [exported]
1042: *
1043: * Executes as a separate kernel thread. This thread is periodically
1044: * woken up. When this happens, it initiates the scan for threads
1045: * to swap.
1046: */
1047: void swapout_thread(void)
1048: {
1049: thread_swappable(current_act(), FALSE);
1050: stack_privilege(current_thread());
1051:
1052: spllo();
1053: while (TRUE) {
1054: swapout_scan();
1055:
1056: assert_wait((event_t)&last_swap_tick, THREAD_UNINT);
1057: thread_block((void (*) (void)) 0);
1058: }
1059: }
1060:
1061: /*
1062: * Mark a thread as swappable or unswappable. May be called at
1063: * any time. No longer assumes thread is swapped in. Frees
1064: * kernel stack backing store when a kernel thread is made
1065: * unswappable. Panics if a kernel thread is subsequently made
1066: * swappable.
1067: */
1068: void thread_swappable(
1069: thread_act_t thr_act,
1070: boolean_t is_swappable)
1071: {
1072: int s;
1073: thread_t thread;
1074:
1075: thread = act_lock_thread(thr_act);
1076: if (thread) {
1077: s = splsched();
1078: thread_lock(thread);
1079: }
1080: if (is_swappable) {
1081: if (thr_act->swap_state == TH_SW_UNSWAPPABLE) {
1082: if (thr_act->task == kernel_task) {
1083: panic("thread_swappable");
1084: }
1085: thr_act->swap_state = TH_SW_IN;
1086: }
1087: }
1088: else {
1089: switch(thr_act->swap_state) {
1090: case TH_SW_UNSWAPPABLE:
1091: /*
1092: * Thread is already unswappable, won't need to
1093: * free backing store.
1094: */
1095: is_swappable = TRUE;
1096: break;
1097:
1098: case TH_SW_IN:
1099: thr_act->swap_state = TH_SW_UNSWAPPABLE;
1100: break;
1101:
1102: default:
1103: do {
1104: thread_swapin(thr_act, TRUE);
1105: assert_wait((event_t) &thr_act->swap_state, THREAD_UNINT);
1106: if (thread) {
1107: thread_unlock(thread);
1108: splx(s);
1109: }
1110: act_unlock_thread(thr_act);
1111: thread_block((void (*)(void))0);
1112: thread = act_lock_thread(thr_act);
1113: if (thread) {
1114: s = splsched();
1115: thread_lock(thread);
1116: }
1117: } while (thr_act->swap_state != TH_SW_UNSWAPPABLE);
1118: break;
1119: }
1120: }
1121: if (thread) {
1122: thread_unlock(thread);
1123: splx(s);
1124: }
1125: act_unlock_thread(thr_act);
1126:
1127: /*
1128: * Deallocate kernel stack backing store for any
1129: * kernel thread made unswappable.
1130: */
1131: if (!is_swappable && thr_act->task == kernel_task) {
1132: #if 0
1133: stack_backing_free(thr_act->kernel_stack, KERNEL_STACK_SIZE);
1134: #endif
1135: }
1136: }
1137:
1138: int thread_swap_disable_swapins = 0;
1139:
1140: void
1141: thread_swap_disable(
1142: thread_act_t thr_act)
1143: {
1144: spl_t s;
1145: thread_t thread;
1146:
1147: /*
1148: * Note: we have to swapin the thread only to make sure
1149: * that its stacks are wired when we free them.
1150: */
1151: thread = act_lock_thread(thr_act);
1152: if (thread) {
1153: s = splsched();
1154: thread_lock(thread);
1155: }
1156: if ((thread_swap_unwire_stack || thread_swap_unwire_user_stack) &&
1157: (thr_act->swap_state != TH_SW_UNSWAPPABLE)) {
1158: /*
1159: * Make the activation unswappable or it might get swapped
1160: * before we complete its termination.
1161: */
1162: if (thr_act->swap_state == TH_SW_IN ||
1163: thr_act->swap_state == (TH_SW_IN|TH_SW_TASK_SWAPPING)) {
1164: thr_act->swap_state = TH_SW_UNSWAPPABLE;
1165: if (thread) {
1166: thread_unlock(thread);
1167: splx(s);
1168: }
1169: act_unlock_thread(thr_act);
1170: } else {
1171: thr_act->swap_state |= TH_SW_MAKE_UNSWAPPABLE;
1172: if (thread) {
1173: thread_unlock(thread);
1174: splx(s);
1175: }
1176: act_unlock_thread(thr_act);
1177: thread_swap_disable_swapins++;
1178: thread_doswapin(thr_act);
1179: }
1180:
1181: assert(thr_act->swap_state == TH_SW_UNSWAPPABLE);
1182: } else {
1183: if (thread) {
1184: thread_unlock(thread);
1185: splx(s);
1186: }
1187: act_unlock_thread(thr_act);
1188: }
1189: }
1190:
1191: #endif /* UNUSED CODE */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.