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