|
|
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) 1992 NeXT, Inc. ! 27: * ! 28: * History: ! 29: * ! 30: * 14-Dec-92: Brian Pinkerton at NeXT ! 31: * Created ! 32: */ ! 33: #import <sys/types.h> ! 34: #import <sys/param.h> ! 35: ! 36: #import <mach/mach_types.h> ! 37: #import <mach/vm_param.h> ! 38: #import <mach/boolean.h> ! 39: #import <mach/kern_return.h> ! 40: #import <mach/vm_policy.h> ! 41: ! 42: #import <vm/vm_object.h> ! 43: #import <vm/vm_map.h> ! 44: #import <vm/vm_page.h> ! 45: #import <vm/vnode_pager.h> ! 46: ! 47: #import <kern/task.h> ! 48: #import <kern/kalloc.h> ! 49: ! 50: ! 51: /* ! 52: * Returns the given page to the HEAD of the free list, ! 53: * disassociating it with any VM object. ! 54: * ! 55: * Object and page must be locked prior to entry. ! 56: */ ! 57: static void ! 58: vm_page_free_head(mem) ! 59: register vm_page_t mem; ! 60: { ! 61: vm_page_remove(mem); ! 62: if (mem->free) ! 63: return; ! 64: ! 65: if (mem->active) { ! 66: queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq); ! 67: mem->active = FALSE; ! 68: vm_page_active_count--; ! 69: } ! 70: ! 71: if (mem->inactive) { ! 72: queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq); ! 73: mem->inactive = FALSE; ! 74: vm_page_inactive_count--; ! 75: } ! 76: ! 77: if (!mem->fictitious) { ! 78: int spl; ! 79: ! 80: spl = splimp(); ! 81: simple_lock(&vm_page_queue_free_lock); ! 82: queue_enter_first(&vm_page_queue_free, mem, vm_page_t, pageq); ! 83: mem->free = TRUE; ! 84: vm_page_free_count++; ! 85: simple_unlock(&vm_page_queue_free_lock); ! 86: splx(spl); ! 87: } ! 88: } ! 89: ! 90: ! 91: /* ! 92: * Do something with a particular page. This function is the locus for all ! 93: * policy decisions. ! 94: */ ! 95: void ! 96: vm_policy_apply(vm_object_t object, vm_page_t m, int when) ! 97: { ! 98: boolean_t shared = FALSE; ! 99: ! 100: /* ! 101: * Determine whether an object is "shared". It is shared if it has ! 102: * more than two references, and it's backed by something that's not ! 103: * the swapfile. ! 104: * ! 105: * Note: this is a pretty bogus definition of shared. The ref count ! 106: * on the object could easily be high even if only one task has this ! 107: * object mapped. This is OK, though, because we're making a ! 108: * conservative decision. Someone can always turn on the shared ! 109: * flag if they want to be really aggressive. ! 110: */ ! 111: if (object->ref_count > 2) { ! 112: if (object->pager && !object->pager->is_device) { ! 113: vnode_pager_t pager = (vnode_pager_t) object->pager; ! 114: shared = !pager->vs_swapfile; ! 115: } ! 116: } ! 117: ! 118: if (!(when & VM_DEACTIVATE_SHARED) && shared) ! 119: return; ! 120: ! 121: vm_page_lock_queues(); ! 122: ! 123: switch (when) { ! 124: /* ! 125: * Make this page as cold as possible. That means that we ! 126: * try to free the page. ! 127: */ ! 128: case VM_DEACTIVATE_NOW: ! 129: if (m->clean && !pmap_is_modified(VM_PAGE_TO_PHYS(m))) ! 130: vm_page_free_head(m); ! 131: else { ! 132: if (m->active) ! 133: vm_page_deactivate(m); ! 134: } ! 135: pmap_remove_all(VM_PAGE_TO_PHYS(m)); ! 136: break; ! 137: ! 138: /* ! 139: * a little warmer. ! 140: */ ! 141: case VM_DEACTIVATE_SOON: ! 142: if (m->active) ! 143: vm_page_deactivate(m); ! 144: break; ! 145: default: ! 146: break; ! 147: } ! 148: ! 149: vm_page_unlock_queues(); ! 150: } ! 151: ! 152: ! 153: /* ! 154: * Deactivate active pages in this object and all shadow objects over the ! 155: * specified address range. ! 156: * ! 157: * If we encounter an error, we'll attempt to push the rest of the pages, ! 158: * and return an error for the whole object. ! 159: * ! 160: * If we encounter a locked page, then we'll skip it... ! 161: */ ! 162: static void ! 163: deactivate_object(vm_object_t object, vm_offset_t start, vm_offset_t end, int temperature) ! 164: { ! 165: vm_object_t shadow; ! 166: vm_page_t page; ! 167: vm_size_t size; ! 168: int flags; ! 169: ! 170: if (object == VM_OBJECT_NULL) ! 171: return; ! 172: ! 173: vm_object_lock(object); ! 174: ! 175: for (page = (vm_page_t) queue_first(&object->memq); ! 176: !queue_end(&object->memq, (queue_entry_t) page); ! 177: page = (vm_page_t) queue_next(&page->listq)) ! 178: { ! 179: /* ! 180: * If this page isn't actually referenced from this ! 181: * entry, then forget it. ! 182: */ ! 183: if (page->offset < start || page->offset >= end) ! 184: continue; ! 185: ! 186: vm_policy_apply(object, page, temperature); ! 187: } ! 188: ! 189: /* ! 190: * Recurse over shadow objects. ! 191: */ ! 192: size = end - start; ! 193: if ((object->size > 0) && (end - start > object->size)) ! 194: size = object->size; ! 195: start += object->shadow_offset; ! 196: end = start + size; ! 197: ! 198: deactivate_object(object->shadow, start, end, temperature); ! 199: ! 200: vm_object_unlock(object); ! 201: thread_wakeup(object); ! 202: } ! 203: ! 204: ! 205: /* ! 206: * Push a range of pages in a map. ! 207: */ ! 208: static void ! 209: deactivate_range(vm_map_t map, vm_offset_t start, vm_offset_t end, int temp) ! 210: { ! 211: vm_map_entry_t entry; ! 212: vm_object_t object; ! 213: vm_offset_t tend; ! 214: int offset; ! 215: ! 216: vm_map_lock_read(map); ! 217: ! 218: /* ! 219: * Push all the pages in this map. ! 220: */ ! 221: for (entry = vm_map_first_entry(map); ! 222: entry != vm_map_to_entry(map); ! 223: entry = entry->vme_next) ! 224: { ! 225: /* ! 226: * Recurse over sub-maps. ! 227: */ ! 228: if (entry->is_a_map || entry->is_sub_map) { ! 229: vm_map_t sub_map; ! 230: sub_map = entry->object.sub_map; ! 231: deactivate_range(sub_map, start, end, temp); ! 232: continue; ! 233: } ! 234: if (entry->vme_start > end || entry->vme_end <= start) ! 235: continue; ! 236: ! 237: /* ! 238: * Push the pages we can see in this object chain. ! 239: */ ! 240: if (entry->vme_start > start) ! 241: start = entry->vme_start; ! 242: ! 243: if (entry->vme_end < end) ! 244: tend = entry->vme_end; ! 245: else ! 246: tend = end; ! 247: ! 248: object = entry->object.vm_object; ! 249: offset = entry->offset + start - entry->vme_start; ! 250: deactivate_object(object, offset, offset + tend - start, temp); ! 251: } ! 252: vm_map_unlock(map); ! 253: } ! 254: ! 255: ! 256: /* ! 257: * Push a range of pages in a map. ! 258: */ ! 259: static void ! 260: set_policy(vm_map_t map, vm_offset_t start, vm_offset_t end, int policy) ! 261: { ! 262: vm_map_entry_t entry; ! 263: vm_object_t object; ! 264: vm_offset_t tend; ! 265: int offset; ! 266: ! 267: vm_map_lock_read(map); ! 268: ! 269: /* ! 270: * Push all the pages in this map. ! 271: */ ! 272: for (entry = vm_map_first_entry(map); ! 273: entry != vm_map_to_entry(map); ! 274: entry = entry->vme_next) ! 275: { ! 276: /* ! 277: * Recurse over sub-maps. ! 278: */ ! 279: if (entry->is_a_map || entry->is_sub_map) { ! 280: vm_map_t sub_map; ! 281: sub_map = entry->object.sub_map; ! 282: set_policy(sub_map, start, end, policy); ! 283: continue; ! 284: } ! 285: if (entry->vme_start > end || entry->vme_end <= start) ! 286: continue; ! 287: ! 288: /* ! 289: * Set the policy on the object ! 290: */ ! 291: object = entry->object.vm_object; ! 292: while (object != VM_OBJECT_NULL) { ! 293: object->policy = policy; ! 294: object = object->shadow; ! 295: } ! 296: } ! 297: vm_map_unlock(map); ! 298: } ! 299: ! 300: ! 301: /* ! 302: * Set the policy on a range of pages. We'd really like to do this on a ! 303: * per-object basis... maybe this should only be applied to pagers? ! 304: */ ! 305: kern_return_t ! 306: vm_set_policy(vm_map_t map, vm_address_t addr, vm_size_t size, int policy) ! 307: { ! 308: if (!map) ! 309: return KERN_FAILURE; ! 310: ! 311: if (size == 0) ! 312: size = map->max_offset - map->min_offset; ! 313: ! 314: if (addr == 0) ! 315: addr = map->min_offset; ! 316: ! 317: set_policy(map, addr, addr + size, policy); ! 318: return KERN_SUCCESS; ! 319: } ! 320: ! 321: ! 322: /* ! 323: * Fault a range of pages with a single disk transfer. Bypass all the normal ! 324: * vm_fault crap. ! 325: */ ! 326: kern_return_t ! 327: vm_fault_range(vm_map_t map, vm_address_t addr, vm_size_t size) ! 328: { ! 329: return KERN_INVALID_ARGUMENT; ! 330: } ! 331: ! 332: ! 333: /* ! 334: * Deactivate a range of pages. ! 335: */ ! 336: kern_return_t ! 337: vm_deactivate(vm_map_t map, vm_address_t addr, vm_size_t size, int temperature) ! 338: { ! 339: if (!map) ! 340: return KERN_FAILURE; ! 341: ! 342: if (size == 0) ! 343: size = map->max_offset - map->min_offset; ! 344: ! 345: if (addr == 0) ! 346: addr = map->min_offset; ! 347: ! 348: deactivate_range(map, addr, size, temperature); ! 349: return KERN_SUCCESS; ! 350: } ! 351: ! 352:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.