|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Mach Operating System
27: * Copyright (c) 1987 Carnegie-Mellon University
28: * All rights reserved. The CMU software License Agreement specifies
29: * the terms and conditions for use and redistribution.
30: */
31: /*
32: * File: vm/vm_pageout.c
33: * Author: Avadis Tevanian, Jr., Michael Wayne Young
34: *
35: * Copyright (C) 1985, Avadis Tevanian, Jr., Michael Wayne Young
36: *
37: * The proverbial page-out daemon.
38: */
39:
40: #import <vm/vm_page.h>
41: #import <vm/pmap.h>
42: #import <vm/vm_object.h>
43: #import <vm/vm_pageout.h>
44: #import <mach/vm_statistics.h>
45: #import <mach/vm_param.h>
46: #import <kern/thread.h>
47: #import <machine/spl.h>
48:
49: simple_lock_data_t vm_pages_needed_lock;
50:
51: int vm_pages_needed; /* Event on which pageout daemon sleeps */
52: int vm_pageout_free_min = 0; /* Stop pageout to wait for pagers at this free level */
53:
54: int vm_page_free_min_sanity = 256*1024;
55:
56: #if MACH_VM_DEBUG
57: long vm_page_total_pages = 0;
58: long local_total_pages;
59: #endif /* MACH_VM_DEBUG */
60:
61: /*
62: * vm_pageout_scan does the dirty work for the pageout daemon.
63: */
64: boolean_t
65: vm_pageout_scan()
66: {
67: register vm_page_t m;
68: register int page_shortage;
69: register int s;
70: register int pages_freed = 0;
71: register int pages_cleaned = 0;
72: boolean_t free_pages;
73: boolean_t did_work = FALSE;
74: #if MACH_VM_DEBUG
75: int dbg_intoa_pages = 0;
76: int dbg_pages_needed = 0;
77: int dbg_pages_cleaned = 0;
78: #endif /* MACH_VM_DEBUG */
79:
80:
81: /*
82: * Only continue when we want more pages to be "free"
83: */
84: s = splimp();
85: simple_lock(&vm_page_queue_free_lock);
86:
87: free_pages = FALSE;
88: if (vm_page_free_count <= vm_page_free_min) {
89: free_pages = TRUE;
90: /*
91: * See whether the physical mapping system
92: * knows of any pages which are not being used.
93: */
94:
95: simple_unlock(&vm_page_queue_free_lock);
96: splx(s);
97:
98: /*
99: * And be sure the pmap system is updated so
100: * we can scan the inactive queue.
101: */
102:
103: pmap_update();
104: }
105: else {
106: simple_unlock(&vm_page_queue_free_lock);
107: splx(s);
108: }
109:
110: /*
111: * Acquire the resident page system lock,
112: * as we may be changing what's resident quite a bit.
113: */
114: vm_page_lock_queues();
115:
116: /*
117: * Start scanning the inactive queue for pages we can free.
118: * We keep scanning until we have enough free pages or
119: * we have scanned through the entire queue. If we
120: * encounter dirty pages, we start cleaning them.
121: */
122:
123: pages_freed = 0;
124: m = (vm_page_t) queue_first(&vm_page_queue_inactive);
125: while (free_pages &&
126: !queue_end(&vm_page_queue_inactive, (queue_entry_t) m)) {
127: vm_page_t next;
128:
129: s = splimp();
130: simple_lock(&vm_page_queue_free_lock);
131: if ((vm_page_free_count + pages_cleaned) >= vm_page_free_target) {
132: simple_unlock(&vm_page_queue_free_lock);
133: splx(s);
134: break;
135: }
136: simple_unlock(&vm_page_queue_free_lock);
137: splx(s);
138:
139: #if 0
140: if (pmap_is_referenced(VM_PAGE_TO_PHYS(m)) &&
141: (vm_page_inactive_target < vm_page_inactive_count))
142: #else
143: if (pmap_is_referenced(VM_PAGE_TO_PHYS(m)))
144: #endif
145: {
146: next = (vm_page_t) queue_next(&m->pageq);
147: vm_page_activate(m);
148: vm_stat.reactivations++;
149: m = next;
150: #if MACH_VM_DEBUG
151: dbg_intoa_pages++;
152: #endif /* MACH_VM_DEBUG */
153: continue;
154: }
155:
156: if (m->clean) {
157: register vm_object_t object;
158:
159: next = (vm_page_t) queue_next(&m->pageq);
160: object = m->object;
161: if (!vm_object_lock_try(object)) {
162: /*
163: * Can't lock object -
164: * skip page.
165: */
166: m = next;
167: continue;
168: }
169: did_work = TRUE;
170: m->busy = TRUE;
171: vm_page_unlock_queues();
172:
173: pmap_remove_all(VM_PAGE_TO_PHYS(m));
174: vm_page_lock_queues();
175: m->busy = FALSE;
176: PAGE_WAKEUP(m);
177:
178: next = (vm_page_t) queue_next(&m->pageq);
179: vm_page_addfree(m);
180: pages_freed++;
181: #if MACH_VM_DEBUG
182: --dbg_pages_needed;
183: #endif /* MACH_VM_DEBUG */
184: vm_object_unlock(object);
185: m = next;
186: }
187: else {
188: /*
189: * If a page is dirty, then it is either
190: * being washed (but not yet cleaned)
191: * or it is still in the laundry. If it is
192: * still in the laundry, then we start the
193: * cleaning operation.
194: */
195:
196: #if 0 && MACH_VM_DEBUG
197: kprintf(" : pulled dirty page off inactive list\n");
198: #endif /* MACH_VM_DEBUG */
199: if (m->laundry) {
200: /*
201: * Clean the page and remove it from the
202: * laundry.
203: *
204: * We set the busy bit to cause
205: * potential page faults on this page to
206: * block.
207: *
208: * And we set pageout-in-progress to keep
209: * the object from disappearing during
210: * pageout. This guarantees that the
211: * page won't move from the inactive
212: * queue. (However, any other page on
213: * the inactive queue may move!)
214: */
215:
216: register vm_object_t object;
217: register vm_pager_t pager;
218: boolean_t pageout_succeeded;
219:
220: #if 0 && MACH_VM_DEBUG
221: kprintf(" cleaning dirty page off inactive list\n");
222: #endif /* MACH_VM_DEBUG */
223: object = m->object;
224: if (!vm_object_lock_try(object)) {
225: /*
226: * Skip page if we can't lock
227: * its object
228: */
229: m = (vm_page_t) queue_next(&m->pageq);
230: continue;
231: }
232:
233: m->busy = TRUE;
234: vm_stat.pageouts++;
235:
236: /*
237: * Try to collapse the object before
238: * making a pager for it. We must
239: * unlock the page queues first.
240: */
241: vm_page_unlock_queues();
242:
243: did_work = TRUE;
244: /*
245: * Moved this call from inside the queue lock
246: * to prevent the following scenario:
247: * remove_all -> pmap_collapse ->
248: * kmem_free -> vm_page_lock_queues
249: */
250: pmap_remove_all(VM_PAGE_TO_PHYS(m));
251:
252: vm_object_collapse(object);
253:
254: object->paging_in_progress++;
255:
256: vm_object_unlock(object);
257:
258:
259: /*
260: * Do a wakeup here in case the following
261: * operations block.
262: */
263: thread_wakeup(&vm_page_free_count);
264:
265: /*
266: * If there is no pager for the page,
267: * use the default pager. If there's
268: * no place to put the page at the
269: * moment, leave it in the laundry and
270: * hope that there will be paging space
271: * later.
272: */
273:
274: if ((pager = object->pager) == vm_pager_null) {
275: pager = (vm_pager_t)vm_pager_allocate(
276: object->size);
277: if (pager != vm_pager_null) {
278: vm_object_setpager(object,
279: pager, 0, FALSE);
280: }
281: }
282:
283: pageout_succeeded = FALSE;
284: if (pager != vm_pager_null) {
285: if (vm_pager_put(pager, m) == PAGER_SUCCESS) {
286: pageout_succeeded = TRUE;
287: #if MACH_VM_DEBUG
288: dbg_pages_cleaned++;
289: #endif /* MACH_VM_DEBUG */
290: pages_cleaned++;
291: }
292: }
293:
294: vm_object_lock(object);
295: vm_page_lock_queues();
296:
297: /*
298: * If page couldn't be paged out, then
299: * reactivate the page so it doesn't
300: * clog the inactive list. (We will try
301: * paging out it again later).
302: */
303: next = (vm_page_t) queue_next(&m->pageq);
304: if (pageout_succeeded)
305: m->laundry = FALSE;
306: else
307: vm_page_activate(m);
308:
309: /* Why are we doing this. Was it not cleared when the mappings were removed
310: * Is this here for a different arch */
311: pmap_clear_reference(VM_PAGE_TO_PHYS(m));
312: m->busy = FALSE;
313: PAGE_WAKEUP(m);
314:
315: object->paging_in_progress--;
316: thread_wakeup(object);
317: vm_object_unlock(object);
318: m = next;
319: }
320: else
321: m = (vm_page_t) queue_next(&m->pageq);
322: }
323: }
324:
325: /*
326: * Compute the page shortage. If we are still very low on memory
327: * be sure that we will move a minimal amount of pages from active
328: * to inactive.
329: */
330:
331: page_shortage = vm_page_inactive_target - vm_page_inactive_count;
332: page_shortage -= vm_page_free_count;
333:
334: // if ((page_shortage <= 0) && (pages_freed == 0))
335: // page_shortage = 1;
336:
337: while (page_shortage > 0) {
338: /*
339: * Move some more pages from active to inactive.
340: */
341:
342: if (queue_empty(&vm_page_queue_active)) {
343: break;
344: }
345: did_work = TRUE;
346: m = (vm_page_t) queue_first(&vm_page_queue_active);
347: vm_page_deactivate(m);
348: page_shortage--;
349: }
350:
351: vm_page_unlock_queues();
352:
353: if (!pages_cleaned && !pages_freed && did_work) {
354: /*
355: * We did not issue any IO in the loop and did not free any
356: * pages. Yield to someone before proceeding so that we do
357: * not go compute bound, which will prevent the threads trying
358: * to do a biodone() from running. If that does not happen,
359: * no forward progress would be made.
360: */
361: thread_will_wait(current_thread());
362: thread_set_timeout(2); /* 2 ticks */
363: thread_block();
364: }
365:
366: return did_work;
367: }
368:
369:
370: /*
371: * vm_pageout is the high level pageout daemon.
372: */
373:
374: void vm_pageout()
375: {
376: thread_t self = current_thread();
377: boolean_t vm_pageout_scan_did_work = TRUE;
378:
379: stack_privilege(self);
380: self->sched_pri = self->priority = MAXPRI_USER;
381: self->policy = POLICY_FIXEDPRI;
382: self->sched_data = min_quantum;
383: self->vm_privilege = TRUE;
384:
385: (void) spl0();
386:
387: /*
388: * Initialize some paging parameters.
389: */
390:
391: if (vm_page_free_min == 0) {
392: // vm_page_free_min = vm_page_free_count / 20;
393: /*
394: ** This is 2.00% of available free pages
395: */
396: vm_page_free_min = vm_page_free_count / 50;
397: if (vm_page_free_min < 3)
398: vm_page_free_min = 3;
399:
400: if (vm_page_free_min*PAGE_SIZE > vm_page_free_min_sanity)
401: vm_page_free_min = vm_page_free_min_sanity/PAGE_SIZE;
402: }
403:
404: if (vm_page_free_reserved == 0) {
405: /*
406: ** This is 0.50% of available free pages
407: */
408: if ((vm_page_free_reserved = vm_page_free_min / 4) < 3)
409: vm_page_free_reserved = 3;
410: }
411: if (vm_pageout_free_min == 0) {
412: if ((vm_pageout_free_min = vm_page_free_reserved / 2) > 10)
413: vm_pageout_free_min = 10;
414: }
415:
416: if (vm_page_free_target == 0)
417: // vm_page_free_target = (vm_page_free_min * 4) / 3;
418: /*
419: ** This is 8.00% of available free pages
420: */
421: vm_page_free_target = vm_page_free_min * 4;
422:
423: if (vm_page_inactive_target == 0)
424: vm_page_inactive_target = vm_page_free_count / 3;
425:
426: if (vm_page_free_target <= vm_page_free_min)
427: vm_page_free_target = vm_page_free_min + 1;
428:
429: if (vm_page_inactive_target <= vm_page_free_target)
430: vm_page_inactive_target = vm_page_free_target + 1;
431:
432: #if MACH_VM_DEBUG
433: kprintf("vm_pageout: free_count=0x%X\n",
434: vm_page_free_count);
435: kprintf("vm_pageout: free_min=0x%X, free_reserved=0x%X\n",
436: vm_page_free_min, vm_page_free_reserved);
437: kprintf("vm_pageout: free_target=0x%X, inactive_target=0x%X\n",
438: vm_page_free_target, vm_page_inactive_target);
439: #endif
440:
441: /*
442: * The pageout daemon is never done, so loop
443: * forever.
444: */
445:
446: simple_lock(&vm_pages_needed_lock);
447: while (TRUE) {
448: if (!vm_pageout_scan_did_work)
449: thread_sleep(&vm_pages_needed,
450: &vm_pages_needed_lock, FALSE);
451: else
452: if ((vm_page_free_count > vm_page_free_min) &&
453: ((vm_page_free_count >= vm_page_free_target) ||
454: (vm_page_inactive_count > vm_page_inactive_target)))
455: thread_sleep(&vm_pages_needed,
456: &vm_pages_needed_lock, FALSE);
457: else{
458: simple_unlock(&vm_pages_needed_lock);
459: }
460: vm_pageout_scan_did_work = vm_pageout_scan();
461: simple_lock(&vm_pages_needed_lock);
462: thread_wakeup(&vm_page_free_count);
463: }
464: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.