|
|
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: * Copyright (c) 1990 NeXT, Inc. ! 27: * ! 28: * History: ! 29: * ! 30: * 6-Aug-90: Brian Pinkerton at NeXT ! 31: * created ! 32: */ ! 33: ! 34: ! 35: #import <mach_xp.h> ! 36: ! 37: #import <sys/types.h> ! 38: #import <sys/param.h> ! 39: ! 40: #import <mach/vm_param.h> ! 41: #import <vm/vm_object.h> ! 42: #import <vm/vm_map.h> ! 43: #import <vm/vm_page.h> ! 44: #import <mach/vm_statistics.h> ! 45: ! 46: #import <mach/boolean.h> ! 47: #import <mach/kern_return.h> ! 48: #import <kern/task.h> ! 49: #import <kern/kalloc.h> ! 50: ! 51: #import <mach/mach_types.h> /* to get vm_address_t */ ! 52: ! 53: ! 54: static kern_return_t map_push_range(vm_map_t map, vm_offset_t start, vm_offset_t end); ! 55: ! 56: static kern_return_t object_push(vm_object_t object, vm_offset_t object_start, vm_offset_t object_end); ! 57: ! 58: enum pageout_outcome { PAGEOUT_SUCCESS, PAGEOUT_ERROR, PAGEOUT_RERUN }; ! 59: ! 60: /* ! 61: * Push all pages to disk. ! 62: */ ! 63: kern_return_t ! 64: vm_synchronize( ! 65: vm_map_t task_map, ! 66: vm_address_t vmaddr, ! 67: vm_size_t vmsize) ! 68: { ! 69: kern_return_t result; ! 70: ! 71: if (!task_map) ! 72: return KERN_FAILURE; ! 73: ! 74: if (vmsize == 0) ! 75: vmsize = task_map->max_offset - task_map->min_offset; ! 76: ! 77: if (vmaddr == 0) ! 78: vmaddr = task_map->min_offset; ! 79: ! 80: result = map_push_range(task_map, vmaddr, vmaddr+vmsize); ! 81: ! 82: return result; ! 83: } ! 84: ! 85: ! 86: /* ! 87: * Push a range of pages in a map. ! 88: */ ! 89: static kern_return_t ! 90: map_push_range( ! 91: vm_map_t map, ! 92: vm_offset_t start, ! 93: vm_offset_t end) ! 94: { ! 95: vm_map_entry_t entry; ! 96: vm_object_t object; ! 97: vm_offset_t tend; ! 98: int offset; ! 99: kern_return_t rtn, realRtn = KERN_SUCCESS; ! 100: ! 101: vm_map_lock_read(map); ! 102: /* ! 103: * Push all the pages in this map. ! 104: */ ! 105: for ( entry = vm_map_first_entry(map) ! 106: ; entry != vm_map_to_entry(map) ! 107: ; entry = entry->vme_next) ! 108: { ! 109: if (entry->is_a_map || entry->is_sub_map) { ! 110: vm_map_t sub_map; ! 111: /* ! 112: * Recurse over this sub-map. ! 113: */ ! 114: sub_map = entry->object.sub_map; ! 115: rtn = map_push_range(sub_map, start, end); ! 116: if (rtn == KERN_FAILURE) ! 117: realRtn = KERN_FAILURE; ! 118: continue; ! 119: } ! 120: if (entry->vme_start > end || entry->vme_end <= start) ! 121: continue; ! 122: ! 123: /* ! 124: * Push the pages we can see in this object chain. ! 125: */ ! 126: object = entry->object.vm_object; ! 127: if (entry->vme_start > start) ! 128: start = entry->vme_start; ! 129: tend = (entry->vme_end > end) ? end : entry->vme_end; ! 130: offset = entry->offset + start - entry->vme_start; ! 131: rtn = object_push(object, offset, offset + tend - start); ! 132: if (rtn) ! 133: realRtn = KERN_FAILURE; ! 134: } ! 135: vm_map_unlock(map); ! 136: ! 137: return realRtn; ! 138: } ! 139: ! 140: ! 141: /* ! 142: * Page out a page belonging to the given object. The object must be locked. ! 143: */ ! 144: static enum pageout_outcome ! 145: vm_pageout_page(vm_object_t object, vm_page_t m) ! 146: { ! 147: enum pageout_outcome pageout_succeeded; ! 148: vm_pager_t pager = object->pager; ! 149: ! 150: vm_page_lock_queues(); ! 151: if (m->clean && !pmap_is_modified(VM_PAGE_TO_PHYS(m))) { ! 152: vm_page_unlock_queues(); ! 153: return PAGEOUT_SUCCESS; ! 154: } ! 155: ! 156: /* ! 157: * If the page is already busy, sleep on it... ! 158: */ ! 159: while (m->busy) { ! 160: vm_page_unlock_queues(); ! 161: PAGE_ASSERT_WAIT(m, FALSE); ! 162: vm_object_unlock(object); ! 163: thread_block(); ! 164: vm_object_lock(object); ! 165: return PAGEOUT_RERUN; ! 166: } ! 167: ! 168: object->paging_in_progress++; ! 169: ! 170: m->busy = TRUE; ! 171: if (m->inactive) ! 172: vm_page_activate(m); ! 173: vm_page_deactivate(m); ! 174: ! 175: pmap_remove_all(VM_PAGE_TO_PHYS(m)); ! 176: vm_stat.pageouts++; ! 177: ! 178: vm_page_unlock_queues(); ! 179: if (pager == vm_pager_null) { ! 180: object->paging_in_progress--; ! 181: return PAGEOUT_ERROR; ! 182: } ! 183: vm_object_unlock(object); ! 184: ! 185: pageout_succeeded = PAGEOUT_ERROR; ! 186: if (pager != vm_pager_null) { ! 187: if (vm_pager_put(pager, m) == PAGER_SUCCESS) { ! 188: pageout_succeeded = PAGEOUT_SUCCESS; ! 189: } ! 190: } ! 191: ! 192: vm_object_lock(object); ! 193: vm_page_lock_queues(); ! 194: m->busy = FALSE; ! 195: PAGE_WAKEUP(m); ! 196: ! 197: object->paging_in_progress--; ! 198: vm_page_unlock_queues(); ! 199: ! 200: return pageout_succeeded; ! 201: } ! 202: ! 203: ! 204: /* ! 205: * Count resident pages in this object and all shadow objects over the ! 206: * specified address range. ! 207: * ! 208: * If we encounter an error, we'll attempt to push the rest of the pages, ! 209: * and return an error for the whole object. ! 210: * ! 211: * If we encounter a locked page, then we'll restart ! 212: */ ! 213: static kern_return_t ! 214: object_push(vm_object_t object, vm_offset_t object_start, vm_offset_t object_end) ! 215: { ! 216: vm_object_t shadow; ! 217: vm_page_t page; ! 218: vm_size_t object_size; ! 219: int flags; ! 220: int allPageoutsSucceeded = TRUE; ! 221: kern_return_t rtn = FALSE; ! 222: ! 223: if (object == VM_OBJECT_NULL) ! 224: return KERN_SUCCESS; ! 225: ! 226: vm_object_lock(object); ! 227: ! 228: retry: ! 229: for ( page = (vm_page_t) queue_first(&object->memq) ! 230: ; !queue_end(&object->memq, (queue_entry_t) page) ! 231: ; page = (vm_page_t) queue_next(&page->listq)) ! 232: { ! 233: /* ! 234: * If this page isn't actually referenced from this ! 235: * entry, then forget it. ! 236: */ ! 237: if (page->offset < object_start || page->offset >= object_end) ! 238: continue; ! 239: ! 240: /* ! 241: * Push this page. If we fail, retry on the whole object. ! 242: */ ! 243: switch (vm_pageout_page(object, page)) { ! 244: case PAGEOUT_RERUN: ! 245: goto retry; ! 246: case PAGEOUT_ERROR: ! 247: allPageoutsSucceeded = FALSE; ! 248: case PAGEOUT_SUCCESS: ! 249: default: ! 250: break; ! 251: } ! 252: } ! 253: ! 254: /* ! 255: * Recurse over shadow objects. ! 256: */ ! 257: object_size = object_end - object_start; ! 258: if (object->size && object_end - object_start > object->size) ! 259: object_size = object->size; ! 260: object_start += object->shadow_offset; ! 261: object_end = object_start + object_size; ! 262: ! 263: if (object_push(object->shadow, object_start, object_end) != KERN_SUCCESS) ! 264: rtn = KERN_FAILURE; ! 265: ! 266: vm_object_unlock(object); ! 267: thread_wakeup(object); ! 268: ! 269: if (rtn == KERN_FAILURE || !allPageoutsSucceeded) ! 270: return KERN_FAILURE; ! 271: else ! 272: return KERN_SUCCESS; ! 273: } ! 274:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.