|
|
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.