]> git.saurik.com Git - apple/xnu.git/blame - osfmk/vm/task_working_set.c
xnu-517.7.7.tar.gz
[apple/xnu.git] / osfmk / vm / task_working_set.c
CommitLineData
9bccf70c 1int startup_miss = 0;
0b4e3aa0 2/*
9bccf70c 3 * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved.
0b4e3aa0
A
4 *
5 * @APPLE_LICENSE_HEADER_START@
6 *
e5568f75
A
7 * The contents of this file constitute Original Code as defined in and
8 * are subject to the Apple Public Source License Version 1.1 (the
9 * "License"). You may not use this file except in compliance with the
10 * License. Please obtain a copy of the License at
11 * http://www.apple.com/publicsource and read it before using this file.
0b4e3aa0 12 *
e5568f75
A
13 * This Original Code and all software distributed under the License are
14 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
0b4e3aa0
A
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
e5568f75
A
17 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
18 * License for the specific language governing rights and limitations
19 * under the License.
0b4e3aa0
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23/*
24 */
25/*
26 * File: vm/task_working_set.c
27 * Author: Chris Youngworth
28 * Date: 2001
29 *
30 * Working set detection and maintainence module
31 */
32
33
9bccf70c
A
34#include <mach/mach_types.h>
35#include <mach/shared_memory_server.h>
0b4e3aa0 36#include <vm/task_working_set.h>
9bccf70c 37#include <vm/vm_kern.h>
0b4e3aa0
A
38#include <vm/vm_map.h>
39#include <vm/vm_page.h>
40#include <vm/vm_pageout.h>
41#include <kern/sched.h>
42
43extern unsigned sched_tick;
9bccf70c
A
44extern zone_t lsf_zone;
45
46/* declarations for internal use only routines */
47
48tws_startup_t
49tws_create_startup_list(
50 tws_hash_t tws);
51
52unsigned int
53tws_startup_list_lookup(
54 tws_startup_t startup,
55 vm_offset_t addr);
56
57kern_return_t
58tws_internal_startup_send(
59 tws_hash_t tws);
60
61void
62tws_traverse_address_hash_list (
63 tws_hash_t tws,
64 unsigned int index,
65 vm_offset_t page_addr,
66 vm_object_t object,
67 vm_object_offset_t offset,
68 vm_map_t map,
69 tws_hash_ptr_t *target_ele,
70 tws_hash_ptr_t **previous_ptr,
71 tws_hash_ptr_t **free_list,
72 unsigned int exclusive_addr);
73
74void
75tws_traverse_object_hash_list (
76 tws_hash_t tws,
77 unsigned int index,
78 vm_object_t object,
79 vm_object_offset_t offset,
80 unsigned int page_mask,
81 tws_hash_ptr_t *target_ele,
82 tws_hash_ptr_t **previous_ptr,
83 tws_hash_ptr_t **free_list);
84
85tws_hash_ptr_t
86new_addr_hash(
87 tws_hash_t tws,
88 unsigned int set,
89 unsigned int index);
90
91tws_hash_ptr_t
92new_obj_hash(
93 tws_hash_t tws,
94 unsigned int set,
95 unsigned int index);
96
97int tws_test_for_community(
98 tws_hash_t tws,
99 vm_object_t object,
100 vm_object_offset_t offset,
101 unsigned int threshold,
102 unsigned int *page_mask);
0b4e3aa0
A
103
104/* Note: all of the routines below depend on the associated map lock for */
105/* synchronization, the map lock will be on when the routines are called */
106/* and on when they return */
107
108tws_hash_t
109tws_hash_create(
110 unsigned int lines,
111 unsigned int rows,
112 unsigned int style)
113{
114 tws_hash_t tws;
115 int i,j;
116
117
118 if ((style != TWS_HASH_STYLE_BASIC) &&
119 (style != TWS_HASH_STYLE_BASIC)) {
120 return((tws_hash_t)NULL);
121 }
122
123
124 tws = (tws_hash_t)(kalloc(sizeof(struct tws_hash)));
125 if(tws == (tws_hash_t)NULL)
126 return tws;
127
9bccf70c
A
128 if((tws->table[0] = (tws_hash_ptr_t *)
129 kalloc(sizeof(tws_hash_ptr_t) * lines * rows))
0b4e3aa0
A
130 == NULL) {
131 kfree((vm_offset_t)tws, sizeof(struct tws_hash));
132 return (tws_hash_t)NULL;
133 }
9bccf70c
A
134 if((tws->table_ele[0] = (tws_hash_ptr_t)
135 kalloc(sizeof(struct tws_hash_ptr) * lines * rows))
0b4e3aa0 136 == NULL) {
55e303ae 137 kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ptr_t)
9bccf70c
A
138 * lines * rows);
139 kfree((vm_offset_t)tws, sizeof(struct tws_hash));
140 return (tws_hash_t)NULL;
141 }
142 if((tws->alt_ele[0] = (tws_hash_ptr_t)
143 kalloc(sizeof(struct tws_hash_ptr) * lines * rows))
144 == NULL) {
145 kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ptr_t)
146 * lines * rows);
147 kfree((vm_offset_t)tws->table_ele[0],
148 sizeof(struct tws_hash_ptr)
149 * lines * rows);
150 kfree((vm_offset_t)tws, sizeof(struct tws_hash));
0b4e3aa0
A
151 return (tws_hash_t)NULL;
152 }
153 if((tws->cache[0] = (struct tws_hash_line *)
154 kalloc(sizeof(struct tws_hash_line) * lines))
155 == NULL) {
9bccf70c
A
156 kfree((vm_offset_t)tws->table[0], sizeof(tws_hash_ptr_t)
157 * lines * rows);
158 kfree((vm_offset_t)tws->table_ele[0],
159 sizeof(struct tws_hash_ptr)
160 * lines * rows);
161 kfree((vm_offset_t)tws->alt_ele[0], sizeof(struct tws_hash_ptr)
162 * lines * rows);
0b4e3aa0 163 kfree((vm_offset_t)tws, sizeof(struct tws_hash));
0b4e3aa0
A
164 return (tws_hash_t)NULL;
165 }
9bccf70c
A
166 tws->free_hash_ele[0] = (tws_hash_ptr_t)0;
167 tws->obj_free_count[0] = 0;
168 tws->addr_free_count[0] = 0;
0b4e3aa0
A
169
170 /* most defaults are such that a bzero will initialize */
9bccf70c
A
171 bzero((char *)tws->table[0],sizeof(tws_hash_ptr_t)
172 * lines * rows);
173 bzero((char *)tws->table_ele[0],sizeof(struct tws_hash_ptr)
174 * lines * rows);
175 bzero((char *)tws->alt_ele[0],sizeof(struct tws_hash_ptr)
176 * lines * rows);
0b4e3aa0
A
177 bzero((char *)tws->cache[0], sizeof(struct tws_hash_line)
178 * lines);
179
180 mutex_init(&tws->lock, ETAP_VM_MAP);
181 tws->style = style;
182 tws->current_line = 0;
183 tws->pageout_count = 0;
184 tws->line_count = 0;
9bccf70c
A
185 tws->startup_cache = NULL;
186 tws->startup_name = NULL;
0b4e3aa0
A
187 tws->number_of_lines = lines;
188 tws->number_of_elements = rows;
189 tws->expansion_count = 1;
190 tws->lookup_count = 0;
191 tws->insert_count = 0;
192 tws->time_of_creation = sched_tick;
193
194 return tws;
195}
196
197int newtest = 0;
198void
199tws_hash_line_clear(
200 tws_hash_t tws,
201 tws_hash_line_t hash_line,
202 boolean_t live)
203{
204 struct tws_hash_ele *hash_ele;
9bccf70c
A
205 struct tws_hash_ptr **trailer;
206 struct tws_hash_ptr **free_list;
207 tws_hash_ele_t addr_ele;
0b4e3aa0
A
208 int index;
209 unsigned int i, j, k;
0b4e3aa0
A
210 int dump_pmap;
211 int hash_loop;
212
213
214 if(tws->line_count < tws->number_of_lines) {
215 tws->line_count++;
216 dump_pmap = 1;
217 } else {
218 if(tws->pageout_count != vm_pageout_scan_event_counter) {
219 tws->pageout_count =
220 vm_pageout_scan_event_counter;
221 tws->line_count = 0;
222 dump_pmap = 1;
223 } else {
224 dump_pmap = 0;
225 }
226 }
227 hash_line->ele_count = 0;
0b4e3aa0 228
9bccf70c
A
229 for (i=0; i<tws->number_of_elements; i++) {
230 hash_loop = 0;
231 hash_ele = &(hash_line->list[i]);
232 if(hash_ele->object != 0) {
233
234 vm_object_offset_t local_off = 0;
235 tws_hash_ptr_t cache_ele;
236
237 index = alt_tws_hash(
238 hash_ele->page_addr & TWS_HASH_OFF_MASK,
239 tws->number_of_elements,
240 tws->number_of_lines);
241
242 tws_traverse_address_hash_list(tws, index,
243 hash_ele->page_addr, hash_ele->object,
244 hash_ele->offset, hash_ele->map,
245 &cache_ele, &trailer, &free_list, 0);
246 if(cache_ele != NULL) {
247 addr_ele = (tws_hash_ele_t)((unsigned int)
248 (cache_ele->element) & ~TWS_ADDR_HASH);
249 if(addr_ele != hash_ele)
250 panic("tws_hash_line_clear:"
251 " out of sync\n");
252 cache_ele->element = 0;
253 *trailer = cache_ele->next;
254 cache_ele->next = *free_list;
255 *free_list = cache_ele;
256 }
257
258 index = alt_tws_hash(
259 (hash_ele->page_addr - 0x1f000)
260 & TWS_HASH_OFF_MASK,
261 tws->number_of_elements,
262 tws->number_of_lines);
263
264 tws_traverse_address_hash_list(tws, index,
265 hash_ele->page_addr, hash_ele->object,
266 hash_ele->offset, hash_ele->map,
267 &cache_ele, &trailer, &free_list, 0);
268
269 if(cache_ele != NULL) {
270 addr_ele = (tws_hash_ele_t)((unsigned int)
271 (cache_ele->element) & ~TWS_ADDR_HASH);
272 if(addr_ele != hash_ele)
273 panic("tws_hash_line_clear: "
274 "out of sync\n");
275 cache_ele->element = 0;
276 *trailer = cache_ele->next;
277 cache_ele->next = *free_list;
278 *free_list = cache_ele;
279 }
280
281
282 if((hash_ele->map != NULL) && (live)) {
283 vm_page_t p;
284
285 for (j = 0x1; j != 0; j = j<<1) {
286 if(j & hash_ele->page_cache) {
287 p = vm_page_lookup(hash_ele->object,
0b4e3aa0 288 hash_ele->offset + local_off);
9bccf70c
A
289 if((p != NULL) && (p->wire_count == 0)
290 && (dump_pmap == 1)) {
291 pmap_remove_some_phys((pmap_t)
292 vm_map_pmap(
55e303ae
A
293 current_map()),
294 p->phys_page);
9bccf70c
A
295 }
296 }
297 local_off += PAGE_SIZE_64;
0b4e3aa0 298 }
0b4e3aa0 299 }
9bccf70c
A
300
301 if(tws->style == TWS_HASH_STYLE_SIGNAL) {
302 vm_object_deallocate(hash_ele->object);
303 vm_map_deallocate(hash_ele->map);
304 }
0b4e3aa0 305
9bccf70c
A
306 index = do_tws_hash(hash_ele->object, hash_ele->offset,
307 tws->number_of_elements,
308 tws->number_of_lines);
0b4e3aa0 309
9bccf70c
A
310 tws_traverse_object_hash_list(tws,
311 index, hash_ele->object, hash_ele->offset,
312 0xFFFFFFFF, &cache_ele, &trailer, &free_list);
313 if((cache_ele != NULL) && (cache_ele->element == hash_ele)) {
314 cache_ele->element = 0;
315 *trailer = cache_ele->next;
316 cache_ele->next = *free_list;
317 *free_list = cache_ele;
0b4e3aa0 318 }
9bccf70c 319 hash_ele->object = 0;
0b4e3aa0 320 }
0b4e3aa0
A
321 }
322}
323
324kern_return_t
90556fb8 325tws_internal_lookup(
0b4e3aa0
A
326 tws_hash_t tws,
327 vm_object_offset_t offset,
328 vm_object_t object,
329 tws_hash_line_t *line)
330{
0b4e3aa0 331 int index;
0b4e3aa0 332 int loop;
9bccf70c
A
333 int set;
334 int ele_line;
335 vm_offset_t pagenum;
336 tws_hash_ptr_t cache_ele;
337 tws_hash_ptr_t *trailer;
338 tws_hash_ptr_t *free_list;
0b4e3aa0
A
339
340 /* don't cache private objects */
341 if(object->private)
342 return KERN_SUCCESS;
343
0b4e3aa0
A
344 index = do_tws_hash(object, offset,
345 tws->number_of_elements, tws->number_of_lines);
346 loop = 0;
347
348 tws->lookup_count++;
349 if(tws->lookup_count == 0)
350 tws->insert_count = 0;
9bccf70c
A
351 if(tws->startup_name != NULL) {
352 int age_of_cache;
353 age_of_cache = ((sched_tick
354 - tws->time_of_creation) >> SCHED_TICK_SHIFT);
355 if (age_of_cache > 35) {
9bccf70c
A
356 return KERN_OPERATION_TIMED_OUT;
357 }
358 }
0b4e3aa0 359
9bccf70c
A
360 if(tws->lookup_count > (4 * tws->expansion_count
361 * tws->number_of_elements * tws->number_of_lines) &&
362 (tws->lookup_count > (2 * tws->insert_count))) {
363 if(tws->startup_cache) {
364 int age_of_cache;
365 age_of_cache = ((sched_tick
366 - tws->time_of_creation) >> SCHED_TICK_SHIFT);
367 if (age_of_cache > 60) {
9bccf70c 368 return KERN_OPERATION_TIMED_OUT;
0b4e3aa0 369 }
9bccf70c 370 }
0b4e3aa0 371 }
9bccf70c
A
372
373 pagenum = (vm_offset_t)(offset & TWS_INDEX_MASK);
374 pagenum = pagenum >> 12;
375 pagenum = 1 << pagenum; /* get the appropriate page in 32 page block */
376 tws_traverse_object_hash_list(tws, index, object, offset, pagenum,
377 &cache_ele, &trailer, &free_list);
378 if(cache_ele != NULL) {
379 set = cache_ele->element->line/tws->number_of_lines;
380 ele_line = cache_ele->element->line - set;
381 *line = &tws->cache[set][ele_line];
9bccf70c
A
382 return KERN_SUCCESS;
383 }
384
0b4e3aa0 385 return KERN_FAILURE;
9bccf70c
A
386
387
0b4e3aa0
A
388}
389
90556fb8
A
390kern_return_t
391tws_lookup(
392 tws_hash_t tws,
393 vm_object_offset_t offset,
394 vm_object_t object,
395 tws_hash_line_t *line)
396{
397 kern_return_t kr;
398
399 if(!tws_lock_try(tws)) {
400 return KERN_FAILURE;
401 }
402 kr = tws_internal_lookup(tws,
403 offset, object, line);
404 tws_unlock(tws);
405 return kr;
406}
407
0b4e3aa0
A
408kern_return_t
409tws_expand_working_set(
410 vm_offset_t tws,
9bccf70c
A
411 int line_count,
412 boolean_t dump_data)
0b4e3aa0
A
413{
414 tws_hash_t new_tws;
415 tws_hash_t old_tws;
416 unsigned int i,j,k;
417 struct tws_hash temp;
418
419 old_tws = (tws_hash_t)tws;
420
421 /* Note we do an elaborate dance to preserve the header that */
422 /* task is pointing to. In this way we can avoid taking a task */
423 /* lock every time we want to access the tws */
424
425 if (old_tws->number_of_lines >= line_count) {
426 return KERN_FAILURE;
427 }
428 if((new_tws = tws_hash_create(line_count,
429 old_tws->number_of_elements, old_tws->style)) == 0) {
430 return(KERN_NO_SPACE);
431 }
432 tws_lock(old_tws);
433
9bccf70c
A
434 if(!dump_data) {
435 for(i = 0; i<old_tws->number_of_lines; i++) {
436 for(j = 0; j<old_tws->number_of_elements; j++) {
437 for(k = 0; k<old_tws->expansion_count; k++) {
438 tws_hash_ele_t entry;
439 vm_object_offset_t paddr;
440 unsigned int page_index;
441 entry = &old_tws->cache[k][i].list[j];
442 if(entry->object != 0) {
0b4e3aa0
A
443 paddr = 0;
444 for(page_index = 1; page_index != 0;
445 page_index = page_index << 1); {
446 if (entry->page_cache & page_index) {
447 tws_insert(new_tws,
448 entry->offset+paddr,
449 entry->object,
450 entry->page_addr+paddr,
451 entry->map);
452 }
453 paddr+=PAGE_SIZE;
454 }
455
9bccf70c
A
456 }
457 }
458 }
0b4e3aa0
A
459 }
460 }
461
462 temp.style = new_tws->style;
463 temp.current_line = new_tws->current_line;
464 temp.pageout_count = new_tws->pageout_count;
465 temp.line_count = new_tws->line_count;
466 temp.number_of_lines = new_tws->number_of_lines;
467 temp.number_of_elements = new_tws->number_of_elements;
468 temp.expansion_count = new_tws->expansion_count;
469 temp.lookup_count = new_tws->lookup_count;
470 temp.insert_count = new_tws->insert_count;
471 for(i = 0; i<new_tws->expansion_count; i++) {
9bccf70c
A
472 temp.obj_free_count[i] = new_tws->obj_free_count[i];
473 temp.addr_free_count[i] = new_tws->addr_free_count[i];
474 temp.free_hash_ele[i] = new_tws->free_hash_ele[i];
0b4e3aa0 475 temp.table[i] = new_tws->table[i];
9bccf70c
A
476 temp.table_ele[i] = new_tws->table_ele[i];
477 temp.alt_ele[i] = new_tws->alt_ele[i];
0b4e3aa0
A
478 temp.cache[i] = new_tws->cache[i];
479 }
480
481 new_tws->style = old_tws->style;
482 new_tws->current_line = old_tws->current_line;
483 new_tws->pageout_count = old_tws->pageout_count;
484 new_tws->line_count = old_tws->line_count;
485 new_tws->number_of_lines = old_tws->number_of_lines;
486 new_tws->number_of_elements = old_tws->number_of_elements;
487 new_tws->expansion_count = old_tws->expansion_count;
488 new_tws->lookup_count = old_tws->lookup_count;
489 new_tws->insert_count = old_tws->insert_count;
490 for(i = 0; i<old_tws->expansion_count; i++) {
9bccf70c
A
491 new_tws->obj_free_count[i] = old_tws->obj_free_count[i];
492 new_tws->addr_free_count[i] = old_tws->addr_free_count[i];
493 new_tws->free_hash_ele[i] = old_tws->free_hash_ele[i];
0b4e3aa0 494 new_tws->table[i] = old_tws->table[i];
9bccf70c
A
495 new_tws->table_ele[i] = old_tws->table_ele[i];
496 new_tws->alt_ele[i] = old_tws->alt_ele[i];
0b4e3aa0
A
497 new_tws->cache[i] = old_tws->cache[i];
498 }
499
500 old_tws->style = temp.style;
501 old_tws->current_line = temp.current_line;
502 old_tws->pageout_count = temp.pageout_count;
503 old_tws->line_count = temp.line_count;
504 old_tws->number_of_lines = temp.number_of_lines;
505 old_tws->number_of_elements = temp.number_of_elements;
506 old_tws->expansion_count = temp.expansion_count;
507 old_tws->lookup_count = temp.lookup_count;
508 old_tws->insert_count = temp.insert_count;
509 for(i = 0; i<temp.expansion_count; i++) {
9bccf70c
A
510 old_tws->obj_free_count[i] = temp.obj_free_count[i];;
511 old_tws->addr_free_count[i] = temp.addr_free_count[i];;
512 old_tws->free_hash_ele[i] = NULL;
0b4e3aa0 513 old_tws->table[i] = temp.table[i];
9bccf70c
A
514 old_tws->table_ele[i] = temp.table_ele[i];
515 old_tws->alt_ele[i] = temp.alt_ele[i];
0b4e3aa0
A
516 old_tws->cache[i] = temp.cache[i];
517 }
518
519 tws_hash_destroy(new_tws);
520 tws_unlock(old_tws);
521 return KERN_SUCCESS;
522}
523
9bccf70c
A
524tws_hash_t test_tws = 0;
525
0b4e3aa0
A
526kern_return_t
527tws_insert(
528 tws_hash_t tws,
529 vm_object_offset_t offset,
530 vm_object_t object,
531 vm_offset_t page_addr,
532 vm_map_t map)
533{
534 queue_t bucket;
0b4e3aa0
A
535 unsigned int index;
536 unsigned int alt_index;
9bccf70c 537 unsigned int index_enum[2];
0b4e3aa0 538 unsigned int ele_index;
9bccf70c
A
539 tws_hash_ptr_t cache_ele;
540 tws_hash_ptr_t obj_ele = NULL;
541 tws_hash_ptr_t addr_ele = NULL;
542 tws_hash_ptr_t *trailer;
543 tws_hash_ptr_t *free_list;
544 tws_hash_ele_t target_element = NULL;
0b4e3aa0 545 int i,k;
0b4e3aa0
A
546 int current_line;
547 int set;
9bccf70c
A
548 int ctr;
549 unsigned int startup_cache_line;
550 vm_offset_t startup_page_addr;
551 int cache_full = 0;
552 int ask_for_startup_cache_release = 0;
553
0b4e3aa0
A
554
555 if(!tws_lock_try(tws)) {
556 return KERN_FAILURE;
557 }
558 tws->insert_count++;
559 current_line = 0xFFFFFFFF;
560
9bccf70c
A
561 startup_cache_line = 0;
562 startup_page_addr =
563 page_addr - (offset - (offset & TWS_HASH_OFF_MASK));
564 if(tws->startup_cache) {
565 int age_of_cache;
566 age_of_cache = ((sched_tick - tws->time_of_creation)
567 >> SCHED_TICK_SHIFT);
568 startup_cache_line = tws_startup_list_lookup(
569 tws->startup_cache, startup_page_addr);
570if(tws == test_tws) {
571printf("cache_lookup, result = 0x%x, addr = 0x%x, object 0x%x, offset 0x%x%x\n", startup_cache_line, startup_page_addr, object, offset);
572}
573 if(age_of_cache > 60) {
574 ask_for_startup_cache_release = 1;
575 }
576 }
0b4e3aa0
A
577 /* This next bit of code, the and alternate hash */
578 /* are all made necessary because of IPC COW */
579
9bccf70c
A
580 /* Note: the use of page_addr modified by delta from offset */
581 /* frame base means we may miss some previous entries. However */
582 /* we will not miss the present entry. This is most important */
583 /* in avoiding duplication of entries against long lived non-cow */
584 /* objects */
585 index_enum[0] = alt_tws_hash(
586 page_addr & TWS_HASH_OFF_MASK,
0b4e3aa0
A
587 tws->number_of_elements, tws->number_of_lines);
588
9bccf70c
A
589 index_enum[1] = alt_tws_hash(
590 (page_addr - 0x1f000) & TWS_HASH_OFF_MASK,
591 tws->number_of_elements, tws->number_of_lines);
0b4e3aa0 592
9bccf70c
A
593 for(ctr = 0; ctr < 2;) {
594 tws_hash_ele_t resident;
595 tws_traverse_address_hash_list(tws,
596 index_enum[ctr], page_addr, NULL,
597 0, NULL,
598 &cache_ele, &trailer, &free_list, 1);
599 if(cache_ele != NULL) {
600 /* found one */
601 resident = (tws_hash_ele_t)((unsigned int)
602 cache_ele->element & ~TWS_ADDR_HASH);
603 if((object == resident->object) &&
604 resident->offset ==
605 (offset & TWS_HASH_OFF_MASK)) {
606 /* This is our object/offset */
607 resident->page_cache
608 |= startup_cache_line;
609 resident->page_cache |=
610 (1<<(((vm_offset_t)
611 (offset & TWS_INDEX_MASK))>>12));
612 tws_unlock(tws);
613 if(ask_for_startup_cache_release)
614 return KERN_OPERATION_TIMED_OUT;
615 return KERN_SUCCESS;
616 }
617 if((object->shadow ==
618 resident->object) &&
619 ((resident->offset
620 + object->shadow_offset)
621 == (offset & TWS_HASH_OFF_MASK))) {
622 /* if we just shadowed, inherit */
623 /* access pattern from parent */
624 startup_cache_line |=
625 resident->page_cache;
626 /* thow out old entry */
627 resident->page_cache = 0;
0b4e3aa0 628 break;
9bccf70c
A
629 } else {
630 resident->page_cache &=
631 ~(1<<(((vm_offset_t)(page_addr
632 - resident->page_addr))
633 >>12));
0b4e3aa0 634 }
9bccf70c
A
635 /* Throw out old entry if there are no */
636 /* more pages in cache */
637 if(resident->page_cache == 0) {
638 /* delete addr hash entry */
639 cache_ele->element = 0;
640 *trailer = cache_ele->next;
641 cache_ele->next = *free_list;
642 *free_list = cache_ele;
643 /* go after object hash */
644 index = do_tws_hash(
645 resident->object,
646 resident->offset,
647 tws->number_of_elements,
648 tws->number_of_lines);
649 tws_traverse_object_hash_list(tws,
650 index, resident->object,
651 resident->offset,
652 0xFFFFFFFF, &cache_ele,
653 &trailer, &free_list);
654 if(cache_ele != NULL) {
0b4e3aa0 655 if(tws->style ==
9bccf70c 656 TWS_HASH_STYLE_SIGNAL) {
0b4e3aa0 657 vm_object_deallocate(
9bccf70c 658 cache_ele->element->object);
0b4e3aa0 659 vm_map_deallocate(
9bccf70c
A
660 cache_ele->element->map);
661 }
662 current_line =
663 cache_ele->element->line;
664 set = current_line
665 /tws->number_of_lines;
666 current_line -= set *
667 tws->number_of_lines;
668 if(cache_ele->element->object != 0) {
669 cache_ele->element->object = 0;
670 tws->cache[set]
671 [current_line].ele_count--;
0b4e3aa0 672 }
9bccf70c
A
673 cache_ele->element = 0;
674 *trailer = cache_ele->next;
675 cache_ele->next = *free_list;
676 *free_list = cache_ele;
0b4e3aa0 677 }
0b4e3aa0 678 }
9bccf70c 679 continue;
0b4e3aa0 680 }
9bccf70c 681 ctr+=1;
0b4e3aa0
A
682 }
683
9bccf70c
A
684 /*
685 * We may or may not have a current line setting coming out of
686 * the code above. If we have a current line it means we can
687 * choose to back-fill the spot vacated by a previous entry.
688 * We have yet to do a definitive check using the original obj/off
689 * We will do that now and override the current line if we
690 * find an element
691 */
692
0b4e3aa0
A
693 index = do_tws_hash(object, offset,
694 tws->number_of_elements, tws->number_of_lines);
0b4e3aa0 695
9bccf70c 696 alt_index = index_enum[0];
0b4e3aa0 697
9bccf70c
A
698 tws_traverse_object_hash_list(tws, index, object, offset,
699 0xFFFFFFFF, &cache_ele, &trailer, &free_list);
700 if(cache_ele != NULL) {
701 obj_ele = cache_ele;
702 current_line = cache_ele->element->line;
703 set = current_line/tws->number_of_lines;
704 current_line -= set * tws->number_of_lines;
705 target_element = cache_ele->element;
706
707 /* Now check to see if we have a hash addr for it */
708 tws_traverse_address_hash_list(tws,
709 alt_index, obj_ele->element->page_addr,
710 obj_ele->element->object,
711 obj_ele->element->offset,
712 obj_ele->element->map,
713 &cache_ele, &trailer, &free_list, 0);
714 if(cache_ele != NULL) {
715 addr_ele = cache_ele;
716 } else {
717 addr_ele = new_addr_hash(tws, set, alt_index);
718 /* if cannot allocate just do without */
719 /* we'll get it next time around */
720 }
0b4e3aa0
A
721 }
722
9bccf70c 723
0b4e3aa0
A
724
725 if(tws->style == TWS_HASH_STYLE_SIGNAL) {
726 vm_object_reference(object);
727 vm_map_reference(map);
728 }
729
730 if(current_line == 0xFFFFFFFF) {
0b4e3aa0
A
731 current_line = tws->current_line;
732 set = current_line/tws->number_of_lines;
733 current_line = current_line - (set * tws->number_of_lines);
734
9bccf70c
A
735#ifdef notdef
736 if(cache_full) {
737 tws->current_line = tws->number_of_lines - 1;
738 }
739#endif
0b4e3aa0 740 if(tws->cache[set][current_line].ele_count
9bccf70c 741 >= tws->number_of_elements) {
0b4e3aa0
A
742 current_line++;
743 tws->current_line++;
744 if(current_line == tws->number_of_lines) {
745 set++;
746 current_line = 0;
747 if (set == tws->expansion_count) {
748 if((tws->lookup_count <
749 (2 * tws->insert_count)) &&
750 (set<TWS_HASH_EXPANSION_MAX)) {
751 tws->lookup_count = 0;
752 tws->insert_count = 0;
753 if(tws->number_of_lines
754 < TWS_HASH_LINE_COUNT) {
755 tws->current_line--;
756 tws_unlock(tws);
757 return KERN_NO_SPACE;
758 }
55e303ae
A
759 /* object persistence is guaranteed by */
760 /* an elevated paging or object */
761 /* reference count in the caller. */
762 vm_object_unlock(object);
9bccf70c
A
763 if((tws->table[set] = (tws_hash_ptr_t *)
764 kalloc(sizeof(tws_hash_ptr_t)
765 * tws->number_of_lines
0b4e3aa0
A
766 * tws->number_of_elements))
767 == NULL) {
768 set = 0;
9bccf70c
A
769 } else if((tws->table_ele[set] =
770 (tws_hash_ptr_t)
771 kalloc(sizeof(struct tws_hash_ptr)
772 * tws->number_of_lines
0b4e3aa0
A
773 * tws->number_of_elements))
774 == NULL) {
775 kfree((vm_offset_t)tws->table[set],
9bccf70c
A
776 sizeof(tws_hash_ptr_t)
777 * tws->number_of_lines
778 * tws->number_of_elements);
779 set = 0;
780 } else if((tws->alt_ele[set] =
781 (tws_hash_ptr_t)
782 kalloc(sizeof(struct tws_hash_ptr)
783 * tws->number_of_lines
784 * tws->number_of_elements))
785 == NULL) {
55e303ae
A
786 kfree((vm_offset_t)tws->table_ele[set],
787 sizeof(struct tws_hash_ptr)
9bccf70c
A
788 * tws->number_of_lines
789 * tws->number_of_elements);
790 kfree((vm_offset_t)tws->table[set],
55e303ae 791 sizeof(tws_hash_ptr_t)
9bccf70c 792 * tws->number_of_lines
0b4e3aa0
A
793 * tws->number_of_elements);
794 tws->table[set] = NULL;
795 set = 0;
796
797 } else if((tws->cache[set] =
798 (struct tws_hash_line *)
799 kalloc(sizeof
800 (struct tws_hash_line)
801 * tws->number_of_lines))
802 == NULL) {
55e303ae
A
803 kfree((vm_offset_t)tws->alt_ele[set],
804 sizeof(struct tws_hash_ptr)
9bccf70c
A
805 * tws->number_of_lines
806 * tws->number_of_elements);
55e303ae 807 kfree((vm_offset_t)tws->table_ele[set],
9bccf70c
A
808 sizeof(struct tws_hash_ptr)
809 * tws->number_of_lines
810 * tws->number_of_elements);
55e303ae
A
811 kfree((vm_offset_t)tws->table[set],
812 sizeof(tws_hash_ptr_t)
9bccf70c
A
813 * tws->number_of_lines
814 * tws->number_of_elements);
0b4e3aa0
A
815 tws->table[set] = NULL;
816 set = 0;
817
818 } else {
9bccf70c
A
819 tws->free_hash_ele[set] =
820 (tws_hash_ptr_t)0;
821 tws->obj_free_count[set] = 0;
822 tws->addr_free_count[set] = 0;
0b4e3aa0 823 bzero((char *)tws->table[set],
9bccf70c
A
824 sizeof(tws_hash_ptr_t)
825 * tws->number_of_lines
0b4e3aa0 826 * tws->number_of_elements);
9bccf70c
A
827 bzero((char *)tws->table_ele[set],
828 sizeof(struct tws_hash_ptr)
829 * tws->number_of_lines
830 * tws->number_of_elements);
831 bzero((char *)tws->alt_ele[set],
832 sizeof(struct tws_hash_ptr)
833 * tws->number_of_lines
0b4e3aa0
A
834 * tws->number_of_elements);
835 bzero((char *)tws->cache[set],
836 sizeof(struct tws_hash_line)
837 * tws->number_of_lines);
838 }
55e303ae 839 vm_object_lock(object);
0b4e3aa0 840 } else {
9bccf70c
A
841 int age_of_cache;
842 age_of_cache =
843 ((sched_tick -
844 tws->time_of_creation)
845 >> SCHED_TICK_SHIFT);
846
847 if((tws->startup_cache) &&
848 (age_of_cache > 60)) {
849 ask_for_startup_cache_release = 1;
850 }
851 if((tws->startup_name != NULL) &&
852 (age_of_cache > 15)) {
853 tws->current_line--;
854 tws_unlock(tws);
855 return KERN_OPERATION_TIMED_OUT;
856 }
857 if((tws->startup_name != NULL) &&
858 (age_of_cache < 15)) {
859 /* If we are creating a */
860 /* cache, don't lose the */
861 /* early info */
862 tws->current_line--;
863 tws_unlock(tws);
864 return KERN_FAILURE;
865 }
0b4e3aa0
A
866 tws->lookup_count = 0;
867 tws->insert_count = 0;
868 set = 0;
869 }
870 }
871 tws->current_line = set * tws->number_of_lines;
872 }
873 if(set < tws->expansion_count) {
874 tws_hash_line_clear(tws,
875 &(tws->cache[set][current_line]), TRUE);
876 if(tws->cache[set][current_line].ele_count
877 >= tws->number_of_elements) {
878 if(tws->style == TWS_HASH_STYLE_SIGNAL) {
879 vm_object_deallocate(object);
880 vm_map_deallocate(map);
881 }
882 tws_unlock(tws);
883 return KERN_FAILURE;
884 }
885 } else {
886 tws->expansion_count++;
887 }
888 }
889 }
890
9bccf70c
A
891
892 /* set object hash element */
893 if(obj_ele == NULL) {
894 obj_ele = new_obj_hash(tws, set, index);
895 if(obj_ele == NULL) {
896 tws->cache[set][current_line].ele_count
897 = tws->number_of_elements;
898 tws_unlock(tws);
899 return KERN_FAILURE;
0b4e3aa0 900 }
0b4e3aa0
A
901 }
902
9bccf70c
A
903 /* set address hash element */
904 if(addr_ele == NULL) {
905 addr_ele = new_addr_hash(tws, set, alt_index);
906 }
0b4e3aa0 907
9bccf70c
A
908 if(target_element == NULL) {
909 ele_index = 0;
910 for(i = 0; i<tws->number_of_elements; i++) {
911 if(tws->cache[set][current_line].
912 list[ele_index].object == 0) {
913 break;
914 }
915 ele_index++;
916 if(ele_index >= tws->number_of_elements)
917 ele_index = 0;
918
919 }
920
921 if(i == tws->number_of_elements)
922 panic("tws_insert: no free elements");
0b4e3aa0 923
9bccf70c
A
924 target_element =
925 &(tws->cache[set][current_line].list[ele_index]);
926
927 tws->cache[set][current_line].ele_count++;
928 }
929
930 obj_ele->element = target_element;
931 if(addr_ele) {
932 addr_ele->element = (tws_hash_ele_t)
933 (((unsigned int)target_element) | TWS_ADDR_HASH);
934 }
935 target_element->object = object;
936 target_element->offset = offset & TWS_HASH_OFF_MASK;
937 target_element->page_addr =
938 page_addr - (offset - (offset & TWS_HASH_OFF_MASK));
939 target_element->map = map;
940 target_element->line =
0b4e3aa0 941 current_line + (set * tws->number_of_lines);
9bccf70c
A
942 if(startup_cache_line) {
943 target_element->page_cache = startup_cache_line;
944 }
945 target_element->page_cache |=
0b4e3aa0
A
946 1<<(((vm_offset_t)(offset & TWS_INDEX_MASK))>>12);
947
0b4e3aa0
A
948
949 tws_unlock(tws);
9bccf70c
A
950 if(ask_for_startup_cache_release)
951 return KERN_OPERATION_TIMED_OUT;
0b4e3aa0
A
952 return KERN_SUCCESS;
953}
954
955/*
956 * tws_build_cluster
957 * lengthen the cluster of pages by the number of pages encountered in the
958 * working set up to the limit requested by the caller. The object needs
959 * to be locked on entry. The map does not because the tws_lookup function
960 * is used only to find if their is an entry in the cache. No transient
961 * data from the cache is de-referenced.
962 *
963 */
964#if MACH_PAGEMAP
965/*
966 * MACH page map - an optional optimization where a bit map is maintained
967 * by the VM subsystem for internal objects to indicate which pages of
968 * the object currently reside on backing store. This existence map
969 * duplicates information maintained by the vnode pager. It is
970 * created at the time of the first pageout against the object, i.e.
971 * at the same time pager for the object is created. The optimization
972 * is designed to eliminate pager interaction overhead, if it is
973 * 'known' that the page does not exist on backing store.
974 *
975 * LOOK_FOR() evaluates to TRUE if the page specified by object/offset is
976 * either marked as paged out in the existence map for the object or no
977 * existence map exists for the object. LOOK_FOR() is one of the
978 * criteria in the decision to invoke the pager. It is also used as one
979 * of the criteria to terminate the scan for adjacent pages in a clustered
980 * pagein operation. Note that LOOK_FOR() always evaluates to TRUE for
981 * permanent objects. Note also that if the pager for an internal object
982 * has not been created, the pager is not invoked regardless of the value
983 * of LOOK_FOR() and that clustered pagein scans are only done on an object
984 * for which a pager has been created.
985 *
986 * PAGED_OUT() evaluates to TRUE if the page specified by the object/offset
987 * is marked as paged out in the existence map for the object. PAGED_OUT()
988 * PAGED_OUT() is used to determine if a page has already been pushed
989 * into a copy object in order to avoid a redundant page out operation.
990 */
991#define LOOK_FOR(o, f) (vm_external_state_get((o)->existence_map, (f)) \
992 != VM_EXTERNAL_STATE_ABSENT)
993#define PAGED_OUT(o, f) (vm_external_state_get((o)->existence_map, (f)) \
994 == VM_EXTERNAL_STATE_EXISTS)
995#else /* MACH_PAGEMAP */
996/*
997 * If the MACH page map optimization is not enabled,
998 * LOOK_FOR() always evaluates to TRUE. The pager will always be
999 * invoked to resolve missing pages in an object, assuming the pager
1000 * has been created for the object. In a clustered page operation, the
1001 * absence of a page on backing backing store cannot be used to terminate
1002 * a scan for adjacent pages since that information is available only in
1003 * the pager. Hence pages that may not be paged out are potentially
1004 * included in a clustered request. The vnode pager is coded to deal
1005 * with any combination of absent/present pages in a clustered
1006 * pagein request. PAGED_OUT() always evaluates to FALSE, i.e. the pager
1007 * will always be invoked to push a dirty page into a copy object assuming
1008 * a pager has been created. If the page has already been pushed, the
1009 * pager will ingore the new request.
1010 */
1011#define LOOK_FOR(o, f) TRUE
1012#define PAGED_OUT(o, f) FALSE
1013#endif /* MACH_PAGEMAP */
1014
1015void
1016tws_build_cluster(
1017 tws_hash_t tws,
1018 vm_object_t object,
1019 vm_object_offset_t *start,
1020 vm_object_offset_t *end,
1021 vm_size_t max_length)
1022{
1023 tws_hash_line_t line;
1024 task_t task;
1025 vm_object_offset_t before = *start;
1026 vm_object_offset_t after = *end;
9bccf70c
A
1027 vm_object_offset_t original_start = *start;
1028 vm_object_offset_t original_end = *end;
0b4e3aa0
A
1029 vm_size_t length = (vm_size_t)(*end - *start);
1030 vm_page_t m;
1031 kern_return_t kret;
1032 vm_object_offset_t object_size;
9bccf70c
A
1033 int age_of_cache;
1034 int pre_heat_size;
1035 unsigned int ele_cache;
55e303ae
A
1036 unsigned int end_cache = 0;
1037 unsigned int start_cache = 0;
0b4e3aa0 1038
765c9de3 1039 if((object->private) || !(object->pager))
0b4e3aa0
A
1040 return;
1041
1042 if (!object->internal) {
1043 kret = vnode_pager_get_object_size(
1044 object->pager,
1045 &object_size);
1046 } else {
765c9de3 1047 object_size = object->size;
0b4e3aa0 1048 }
9bccf70c 1049
90556fb8
A
1050 if((!tws) || (!tws_lock_try(tws))) {
1051 return;
1052 }
1053
9bccf70c
A
1054 age_of_cache = ((sched_tick
1055 - tws->time_of_creation) >> SCHED_TICK_SHIFT);
1056
1057 /* When pre-heat files are not available, resort to speculation */
1058 /* based on size of file */
1059
1060 if(tws->startup_cache || object->internal || age_of_cache > 15 ||
1061 (age_of_cache > 5 &&
1062 vm_page_free_count < (vm_page_free_target * 2) )) {
1063 pre_heat_size = 0;
0b4e3aa0 1064 } else {
9bccf70c
A
1065 if (object_size > (vm_object_offset_t)(1024 * 1024))
1066 pre_heat_size = 8 * PAGE_SIZE;
1067 else if (object_size > (vm_object_offset_t)(128 * 1024))
1068 pre_heat_size = 4 * PAGE_SIZE;
1069 else
1070 pre_heat_size = 2 * PAGE_SIZE;
1071 }
1072
1073 if ((age_of_cache < 10) && (tws->startup_cache)) {
1074 if ((max_length >= ((*end - *start)
1075 + (32 * PAGE_SIZE))) &&
1076 (tws_test_for_community(tws, object,
1077 *start, 3, &ele_cache))) {
1078 int expanded;
1079 start_cache = ele_cache;
1080 *start = *start & TWS_HASH_OFF_MASK;
1081 *end = *start + (32 * PAGE_SIZE_64);
1082 if(*end > object_size) {
55e303ae 1083 *end = trunc_page_64(object_size);
9bccf70c
A
1084 max_length = 0;
1085 if(before >= *end) {
1086 *end = after;
1087 } else {
1088 end_cache = ele_cache;
1089 }
1090 } else {
1091 end_cache = ele_cache;
1092 }
1093 while (max_length > ((*end - *start)
1094 + (32 * PAGE_SIZE))) {
1095 expanded = 0;
1096 after = *end;
1097 before = *start - PAGE_SIZE_64;
1098 if((*end <= (object->size
1099 + (32 * PAGE_SIZE_64))) &&
1100 (tws_test_for_community(tws,
1101 object, after,
1102 5, &ele_cache))) {
1103 *end = after +
1104 (32 * PAGE_SIZE_64);
1105 if(*end > object_size) {
55e303ae 1106 *end = trunc_page_64(object_size);
9bccf70c
A
1107 max_length = 0;
1108 if(*start >= *end) {
1109 *end = after;
1110 }
1111 }
1112 end_cache = ele_cache;
1113 expanded = 1;
1114 }
1115 if (max_length > ((*end - *start)
1116 + (32 * PAGE_SIZE_64))) {
1117 break;
1118 }
1119 if((*start >= (32 * PAGE_SIZE_64)) &&
1120 (tws_test_for_community(tws, object,
1121 before, 5, &ele_cache))) {
1122 *start = before;
1123 start_cache = ele_cache;
1124 expanded = 1;
1125 }
1126 if(expanded == 0)
1127 break;
1128 }
1129
55e303ae 1130 if(start_cache != 0) {
9bccf70c
A
1131 unsigned int mask;
1132
1133 for (mask = 1; mask != 0; mask = mask << 1) {
1134 if (*start == original_start)
1135 break;
1136 if (!(start_cache & mask))
1137 *start += PAGE_SIZE_64;
1138 else
1139 break;
1140 }
1141 }
55e303ae 1142 if(end_cache != 0) {
9bccf70c
A
1143 unsigned int mask;
1144
1145 for (mask = 0x80000000;
1146 mask != 0; mask = mask >> 1) {
1147 if (*end == original_end)
1148 break;
1149 if(!(end_cache & mask))
1150 *end -= PAGE_SIZE_64;
1151 else
1152 break;
1153 }
1154 }
1155
1156 if (*start >= *end)
1157 panic("bad clipping occurred\n");
1158
90556fb8 1159 tws_unlock(tws);
9bccf70c
A
1160 return;
1161 }
0b4e3aa0
A
1162 }
1163
1164 while ((length < max_length) &&
1165 (object_size >=
765c9de3 1166 (after + PAGE_SIZE_64))) {
9bccf70c 1167 if(length >= pre_heat_size) {
90556fb8 1168 if(tws_internal_lookup(tws, after, object,
0b4e3aa0
A
1169 &line) != KERN_SUCCESS) {
1170 vm_object_offset_t extend;
1171
1172 extend = after + PAGE_SIZE_64;
90556fb8 1173 if(tws_internal_lookup(tws, extend, object,
0b4e3aa0
A
1174 &line) != KERN_SUCCESS) {
1175 break;
1176 }
9bccf70c
A
1177 }
1178 }
1179
1180 if ((object->existence_map != NULL)
1181 && (!LOOK_FOR(object, after))) {
0b4e3aa0 1182 break;
9bccf70c
A
1183 }
1184
1185 if (vm_page_lookup(object, after) != VM_PAGE_NULL) {
55e303ae
A
1186 /*
1187 * don't bridge resident pages
1188 */
1189 break;
0b4e3aa0 1190 }
9bccf70c 1191
0b4e3aa0
A
1192 if (object->internal) {
1193 /*
1194 * need to acquire a real page in
1195 * advance because this acts as
1196 * a throttling mechanism for
1197 * data_requests to the default
1198 * pager. If this fails, give up
1199 * trying to find any more pages
1200 * in the cluster and send off the
1201 * request for what we already have.
1202 */
1203 if ((m = vm_page_grab()) == VM_PAGE_NULL) {
1204 break;
1205 }
1206 } else if ((m = vm_page_grab_fictitious())
1207 == VM_PAGE_NULL) {
1208 break;
1209 }
1210 m->absent = TRUE;
1211 m->unusual = TRUE;
1212 m->clustered = TRUE;
1213 m->list_req_pending = TRUE;
1214
1215 vm_page_insert(m, object, after);
1216 object->absent_count++;
1217 after += PAGE_SIZE_64;
1218 length += PAGE_SIZE;
1219 }
1220 *end = after;
1221 while (length < max_length) {
1222 if (before == 0)
1223 break;
1224 before -= PAGE_SIZE_64;
1225
9bccf70c 1226 if(length >= pre_heat_size) {
90556fb8 1227 if(tws_internal_lookup(tws, before, object,
0b4e3aa0
A
1228 &line) != KERN_SUCCESS) {
1229 vm_object_offset_t extend;
1230
1231 extend = before;
1232 if (extend == 0)
1233 break;
1234 extend -= PAGE_SIZE_64;
90556fb8 1235 if(tws_internal_lookup(tws, extend, object,
0b4e3aa0
A
1236 &line) != KERN_SUCCESS) {
1237 break;
1238 }
9bccf70c
A
1239 }
1240 }
1241 if ((object->existence_map != NULL)
1242 && (!LOOK_FOR(object, before))) {
0b4e3aa0
A
1243 break;
1244 }
9bccf70c
A
1245
1246 if (vm_page_lookup(object, before) != VM_PAGE_NULL) {
55e303ae
A
1247 /*
1248 * don't bridge resident pages
1249 */
1250 break;
9bccf70c
A
1251 }
1252
0b4e3aa0
A
1253 if (object->internal) {
1254 /*
1255 * need to acquire a real page in
1256 * advance because this acts as
1257 * a throttling mechanism for
1258 * data_requests to the default
1259 * pager. If this fails, give up
1260 * trying to find any more pages
1261 * in the cluster and send off the
1262 * request for what we already have.
1263 */
1264 if ((m = vm_page_grab()) == VM_PAGE_NULL) {
1265 break;
1266 }
1267 } else if ((m = vm_page_grab_fictitious())
1268 == VM_PAGE_NULL) {
1269 break;
1270 }
1271 m->absent = TRUE;
1272 m->unusual = TRUE;
1273 m->clustered = TRUE;
1274 m->list_req_pending = TRUE;
1275
1276 vm_page_insert(m, object, before);
1277 object->absent_count++;
1278 *start -= PAGE_SIZE_64;
1279 length += PAGE_SIZE;
1280 }
90556fb8 1281 tws_unlock(tws);
0b4e3aa0
A
1282}
1283
1284tws_line_signal(
1285 tws_hash_t tws,
1286 vm_map_t map,
1287 tws_hash_line_t hash_line,
1288 vm_offset_t target_page)
1289{
1290 unsigned int i,j;
1291 vm_object_t object;
1292 vm_object_offset_t offset;
1293 vm_object_offset_t before;
1294 vm_object_offset_t after;
1295 struct tws_hash_ele *element;
1296 vm_page_t m,p;
1297 kern_return_t rc;
1298
1299 if(tws->style != TWS_HASH_STYLE_SIGNAL)
1300 return;
1301
1302 vm_map_lock(map);
1303 for (i=0; i<tws->number_of_elements; i++) {
1304
1305 vm_object_offset_t local_off = 0;
1306
1307 if(hash_line->list[i].object == 0)
1308 continue;
1309
1310 element = &hash_line->list[i];
1311
1312 if (element->page_addr == target_page)
1313 continue;
1314
1315 j = 1;
1316 while (j != 0) {
1317 if(j & element->page_cache)
1318 break;
1319 j << 1;
1320 local_off += PAGE_SIZE_64;
1321 }
1322 object = element->object;
1323 offset = element->offset + local_off;
1324
1325 /* first try a fast test to speed up no-op signal */
1326 if (((p = vm_page_lookup(object, offset)) != NULL)
1327 || (object->pager == NULL)
1328 || (object->shadow_severed)) {
1329 continue;
1330 }
1331
1332 if((!object->alive) ||
1333 (!object->pager_created) || (!object->pager_ready))
1334 continue;
1335
1336 if (object->internal) {
1337 if (object->existence_map == NULL) {
1338 if (object->shadow)
1339 continue;
1340 } else {
1341 if(!LOOK_FOR(object, offset))
1342 continue;
1343 }
1344 }
1345
1346 vm_object_reference(object);
1347 vm_map_unlock(map);
1348
1349 if(object->internal) {
1350 m = vm_page_grab();
1351 } else {
1352 m = vm_page_grab_fictitious();
1353 }
1354
1355 if(m == NULL) {
1356 vm_object_deallocate(object);
1357 vm_map_lock(map);
1358 continue;
1359 }
1360
1361 vm_object_lock(object);
1362 if (((p = vm_page_lookup(object, offset)) != NULL)
1363 || (object->pager == NULL)
1364 || (object->shadow_severed)) {
1365 VM_PAGE_FREE(m);
1366 vm_object_unlock(object);
1367 vm_object_deallocate(object);
1368 vm_map_lock(map);
1369 continue;
1370 }
1371
1372 vm_page_insert(m, object, offset);
1373
1374 if (object->absent_count > vm_object_absent_max) {
1375 VM_PAGE_FREE(m);
1376 vm_object_unlock(object);
1377 vm_object_deallocate(object);
1378 vm_map_lock(map);
1379 break;
1380 }
1381 m->list_req_pending = TRUE;
1382 m->absent = TRUE;
1383 m->unusual = TRUE;
1384 object->absent_count++;
1385
1386 before = offset;
1387 after = offset + PAGE_SIZE_64;
1388 tws_build_cluster(tws, object, &before, &after, 0x16000);
1389 vm_object_unlock(object);
1390
1391 rc = memory_object_data_request(object->pager,
1392 before + object->paging_offset,
1393 (vm_size_t)(after - before), VM_PROT_READ);
1394 if (rc != KERN_SUCCESS) {
1395 offset = before;
1396 vm_object_lock(object);
1397 while (offset < after) {
1398 m = vm_page_lookup(object, offset);
1399 if(m && m->absent && m->busy)
1400 VM_PAGE_FREE(m);
1401 offset += PAGE_SIZE;
1402 }
1403 vm_object_unlock(object);
1404 vm_object_deallocate(object);
1405 } else {
1406 vm_object_deallocate(object);
1407 }
1408 vm_map_lock(map);
1409 continue;
1410 }
1411 vm_map_unlock(map);
1412}
1413
9bccf70c
A
1414/* tws locked on entry */
1415
1416tws_startup_t
1417tws_create_startup_list(
1418 tws_hash_t tws)
1419{
1420
1421 tws_startup_t startup;
1422 unsigned int i,j,k;
1423 unsigned int total_elements;
1424 unsigned int startup_size;
1425 unsigned int sindex;
1426 unsigned int hash_index;
1427 tws_startup_ptr_t element;
1428
1429 total_elements = tws->expansion_count *
1430 (tws->number_of_lines * tws->number_of_elements);
1431
1432 startup_size = sizeof(struct tws_startup)
1433 + (total_elements * sizeof(tws_startup_ptr_t *))
1434 + (total_elements * sizeof(struct tws_startup_ptr))
1435 + (total_elements * sizeof(struct tws_startup_ele));
1436 startup = (tws_startup_t)(kalloc(startup_size));
1437
1438 if(startup == NULL)
1439 return startup;
1440
1441 bzero((char *) startup, startup_size);
1442
1443 startup->table = (tws_startup_ptr_t *)
1444 (((int)startup) + (sizeof(struct tws_startup)));
1445 startup->ele = (struct tws_startup_ptr *)
1446 (((vm_offset_t)startup->table) +
1447 (total_elements * sizeof(tws_startup_ptr_t)));
1448
1449 startup->array = (struct tws_startup_ele *)
1450 (((vm_offset_t)startup->ele) +
1451 (total_elements * sizeof(struct tws_startup_ptr)));
1452
1453 startup->tws_hash_size = startup_size;
1454 startup->ele_count = 0; /* burn first hash ele, else we can't tell from zero */
1455 startup->array_size = total_elements;
1456 startup->hash_count = 1;
1457
1458 sindex = 0;
1459
1460
1461 for(i = 0; i<tws->number_of_lines; i++) {
1462 for(j = 0; j<tws->number_of_elements; j++) {
1463 for(k = 0; k<tws->expansion_count; k++) {
1464 tws_hash_ele_t entry;
1465 unsigned int hash_retry;
1466 vm_offset_t addr;
1467
1468 entry = &tws->cache[k][i].list[j];
1469 addr = entry->page_addr;
1470 hash_retry = 0;
1471 if(entry->object != 0) {
1472 /* get a hash element */
1473 hash_index = do_startup_hash(addr,
1474 startup->array_size);
1475
1476 if(startup->hash_count < total_elements) {
1477 element = &(startup->ele[startup->hash_count]);
1478 startup->hash_count += 1;
1479 } else {
1480 /* exit we're out of elements */
1481 break;
1482 }
1483 /* place the hash element */
1484 element->next = startup->table[hash_index];
1485 startup->table[hash_index] = (tws_startup_ptr_t)
1486 ((int)element - (int)&startup->ele[0]);
1487
1488 /* set entry OFFSET in hash element */
1489 element->element = (tws_startup_ele_t)
1490 ((int)&startup->array[sindex] -
1491 (int)&startup->array[0]);
1492
1493 startup->array[sindex].page_addr = entry->page_addr;
1494 startup->array[sindex].page_cache = entry->page_cache;
1495 startup->ele_count++;
1496 sindex++;
1497
1498 }
1499 }
1500 }
1501 }
1502
1503 return startup;
1504}
1505
1506
1507/*
1508 * Returns an entire cache line. The line is deleted from the startup
1509 * cache on return. The caller can check startup->ele_count for an empty
1510 * list. Access synchronization is the responsibility of the caller.
1511 */
1512
1513unsigned int
1514tws_startup_list_lookup(
1515 tws_startup_t startup,
1516 vm_offset_t addr)
1517{
1518 unsigned int hash_index;
1519 unsigned int page_cache_bits;
1520 unsigned int startup_shift;
1521 tws_startup_ele_t entry;
1522 vm_offset_t next_addr;
1523 tws_startup_ptr_t element;
1524 tws_startup_ptr_t base_ele;
1525 tws_startup_ptr_t *previous_ptr;
1526
1527 page_cache_bits = 0;
1528
1529 hash_index = do_startup_hash(addr, startup->array_size);
1530
1531 if(((unsigned int)&(startup->table[hash_index])) >= startup->tws_hash_size) {
1532 return page_cache_bits = 0;
1533 }
1534 element = (tws_startup_ptr_t)((int)startup->table[hash_index] +
1535 (int)&startup->ele[0]);
1536 base_ele = element;
1537 previous_ptr = &(startup->table[hash_index]);
1538 while(element > &startup->ele[0]) {
1539 if (((int)element + sizeof(struct tws_startup_ptr))
1540 > ((int)startup + startup->tws_hash_size)) {
1541 return page_cache_bits;
1542 }
1543 entry = (tws_startup_ele_t)
1544 ((int)element->element
1545 + (int)&startup->array[0]);
1546 if((((int)entry + sizeof(struct tws_startup_ele))
1547 > ((int)startup + startup->tws_hash_size))
1548 || ((int)entry < (int)startup)) {
1549 return page_cache_bits;
1550 }
1551 if ((addr >= entry->page_addr) &&
1552 (addr <= (entry->page_addr + 0x1F000))) {
1553 startup_shift = (addr - entry->page_addr)>>12;
1554 page_cache_bits |= entry->page_cache >> startup_shift;
1555 /* don't dump the pages, unless the addresses */
1556 /* line up perfectly. The cache may be used */
1557 /* by other mappings */
1558 entry->page_cache &= (1 << startup_shift) - 1;
1559 if(addr == entry->page_addr) {
1560 if(base_ele == element) {
1561 base_ele = (tws_startup_ptr_t)
1562 ((int)element->next
1563 + (int)&startup->ele[0]);
1564 startup->table[hash_index] = element->next;
1565 element = base_ele;
1566 } else {
1567 *previous_ptr = element->next;
1568 element = (tws_startup_ptr_t)
1569 ((int)*previous_ptr
1570 + (int)&startup->ele[0]);
1571 }
1572 entry->page_addr = 0;
1573 startup->ele_count--;
1574 continue;
1575 }
1576 }
1577 next_addr = addr + 0x1F000;
1578 if ((next_addr >= entry->page_addr) &&
1579 (next_addr <= (entry->page_addr + 0x1F000))) {
1580 startup_shift = (next_addr - entry->page_addr)>>12;
1581 page_cache_bits |= entry->page_cache << (0x1F - startup_shift);
1582 entry->page_cache &= ~((1 << (startup_shift + 1)) - 1);
1583 if(entry->page_cache == 0) {
1584 if(base_ele == element) {
1585 base_ele = (tws_startup_ptr_t)
1586 ((int)element->next
1587 + (int)&startup->ele[0]);
1588 startup->table[hash_index] = element->next;
1589 element = base_ele;
1590 } else {
1591 *previous_ptr = element->next;
1592 element = (tws_startup_ptr_t)
1593 ((int)*previous_ptr
1594 + (int)&startup->ele[0]);
1595 }
1596 entry->page_addr = 0;
1597 startup->ele_count--;
1598 continue;
1599 }
1600 }
1601 previous_ptr = &(element->next);
1602 element = (tws_startup_ptr_t)
1603 ((int) element->next + (int) &startup->ele[0]);
1604 }
1605
1606 return page_cache_bits;
1607}
1608
1609kern_return_t
1610tws_send_startup_info(
1611 task_t task)
1612{
1613
1614 tws_hash_t tws;
1615 tws_startup_t scache;
1616
1617 task_lock(task);
1618 tws = (tws_hash_t)task->dynamic_working_set;
1619 task_unlock(task);
1620 if(tws == NULL) {
1621 return KERN_FAILURE;
1622 }
1623 return tws_internal_startup_send(tws);
1624}
1625
1626
1627kern_return_t
1628tws_internal_startup_send(
1629 tws_hash_t tws)
1630{
1631
1632 tws_startup_t scache;
1633
1634 if(tws == NULL) {
1635 return KERN_FAILURE;
1636 }
1637 tws_lock(tws);
1638 /* used to signal write or release depending on state of tws */
1639 if(tws->startup_cache) {
1640 vm_offset_t startup_buf;
1641 vm_size_t size;
1642 startup_buf = (vm_offset_t)tws->startup_cache;
1643 size = tws->startup_cache->tws_hash_size;
1644 tws->startup_cache = 0;
1645 tws_unlock(tws);
1646 kmem_free(kernel_map, startup_buf, size);
1647 return KERN_SUCCESS;
1648 }
1649 if(tws->startup_name == NULL) {
1650 tws_unlock(tws);
1651 return KERN_FAILURE;
1652 }
1653 scache = tws_create_startup_list(tws);
1654 if(scache == NULL)
1655 return KERN_FAILURE;
1656 bsd_write_page_cache_file(tws->uid, tws->startup_name,
1657 scache, scache->tws_hash_size,
1658 tws->mod, tws->fid);
1659 kfree((vm_offset_t)scache, scache->tws_hash_size);
1660 kfree((vm_offset_t) tws->startup_name, tws->startup_name_length);
1661 tws->startup_name = NULL;
1662 tws_unlock(tws);
1663 return KERN_SUCCESS;
1664}
1665
1666kern_return_t
1667tws_handle_startup_file(
1668 task_t task,
1669 unsigned int uid,
1670 char *app_name,
1671 vm_offset_t app_vp,
1672 boolean_t *new_info)
1673
1674{
1675 tws_startup_t startup;
1676 vm_offset_t cache_size;
1677 kern_return_t error;
1678 int fid;
1679 int mod;
1680
1681 *new_info = FALSE;
1682 /* don't pre-heat kernel task */
1683 if(task == kernel_task)
1684 return KERN_SUCCESS;
1685 error = bsd_read_page_cache_file(uid, &fid,
1686 &mod, app_name,
1687 app_vp, &startup,
1688 &cache_size);
1689 if(error) {
1690 return KERN_FAILURE;
1691 }
1692 if(startup == NULL) {
1693 /* Entry for app does not exist, make */
1694 /* one */
1695 /* we will want our own copy of the shared */
1696 /* regions to pick up a true picture of all */
1697 /* the pages we will touch. */
1698 if((lsf_zone->count * lsf_zone->elem_size)
1699 > (lsf_zone->max_size >> 1)) {
1700 /* We don't want to run out of shared memory */
1701 /* map entries by starting too many private versions */
1702 /* of the shared library structures */
1703 return KERN_SUCCESS;
1704 }
1705 *new_info = TRUE;
55e303ae 1706
9bccf70c
A
1707 error = tws_write_startup_file(task,
1708 fid, mod, app_name, uid);
1709 if(error)
1710 return error;
9bccf70c
A
1711
1712 } else {
1713 error = tws_read_startup_file(task,
1714 (tws_startup_t)startup,
1715 cache_size);
1716 if(error) {
1717 kmem_free(kernel_map,
1718 (vm_offset_t)startup, cache_size);
1719 return error;
1720 }
1721 }
1722 return KERN_SUCCESS;
1723}
1724
1725kern_return_t
1726tws_write_startup_file(
1727 task_t task,
1728 int fid,
1729 int mod,
1730 char *name,
1731 unsigned int uid)
1732{
1733 tws_hash_t tws;
1734 unsigned int string_length;
1735
1736 string_length = strlen(name);
1737
1738 task_lock(task);
1739 tws = (tws_hash_t)task->dynamic_working_set;
1740
1741 task_unlock(task);
1742 if(tws == NULL) {
1743 /* create a dynamic working set of normal size */
1744 task_working_set_create(task, 0,
1745 0, TWS_HASH_STYLE_DEFAULT);
1746 }
1747 tws_lock(tws);
1748
1749 if(tws->startup_name != NULL) {
1750 tws_unlock(tws);
1751 return KERN_FAILURE;
1752 }
1753
1754 tws->startup_name = (char *)
1755 kalloc((string_length + 1) * (sizeof(char)));
1756 if(tws->startup_name == NULL) {
1757 tws_unlock(tws);
1758 return KERN_FAILURE;
1759 }
1760
1761 bcopy(name, (char *)tws->startup_name, string_length + 1);
1762 tws->startup_name_length = (string_length + 1) * sizeof(char);
1763 tws->uid = uid;
1764 tws->fid = fid;
1765 tws->mod = mod;
1766
1767 tws_unlock(tws);
1768 return KERN_SUCCESS;
1769}
1770
1771kern_return_t
1772tws_read_startup_file(
1773 task_t task,
1774 tws_startup_t startup,
1775 vm_offset_t cache_size)
1776{
1777 tws_hash_t tws;
1778 int error;
1779 int lines;
1780 int old_exp_count;
1781
1782 task_lock(task);
1783 tws = (tws_hash_t)task->dynamic_working_set;
1784
1785 if(cache_size < sizeof(struct tws_hash)) {
1786 task_unlock(task);
1787 kmem_free(kernel_map, (vm_offset_t)startup, cache_size);
1788 return(KERN_SUCCESS);
1789 }
1790
1791 /* create a dynamic working set to match file size */
1792 lines = (cache_size - sizeof(struct tws_hash))/TWS_ARRAY_SIZE;
1793 /* we now need to divide out element size and word size */
1794 /* all fields are 4 bytes. There are 8 bytes in each hash element */
1795 /* entry, 4 bytes in each table ptr location and 8 bytes in each */
1796 /* page_cache entry, making a total of 20 bytes for each entry */
1797 lines = (lines/(20));
1798 if(lines <= TWS_SMALL_HASH_LINE_COUNT) {
1799 lines = TWS_SMALL_HASH_LINE_COUNT;
1800 task_unlock(task);
1801 kmem_free(kernel_map, (vm_offset_t)startup, cache_size);
1802 return(KERN_SUCCESS);
1803 } else {
1804 old_exp_count = lines/TWS_HASH_LINE_COUNT;
1805 if((old_exp_count * TWS_HASH_LINE_COUNT) != lines) {
1806 lines = (old_exp_count + 1)
1807 * TWS_HASH_LINE_COUNT;
1808 }
1809 if(tws == NULL) {
1810 task_working_set_create(task, lines,
1811 0, TWS_HASH_STYLE_DEFAULT);
1812 task_unlock(task);
1813 } else {
1814 task_unlock(task);
1815 tws_expand_working_set(
1816 (vm_offset_t)tws, lines, TRUE);
1817 }
1818 }
1819
1820
1821 tws_lock(tws);
1822
1823 if(tws->startup_cache != NULL) {
1824 tws_unlock(tws);
1825 return KERN_FAILURE;
1826 }
1827
1828
1829 /* now need to fix up internal table pointers */
1830 startup->table = (tws_startup_ptr_t *)
1831 (((int)startup) + (sizeof(struct tws_startup)));
1832 startup->ele = (struct tws_startup_ptr *)
1833 (((vm_offset_t)startup->table) +
1834 (startup->array_size * sizeof(tws_startup_ptr_t)));
1835 startup->array = (struct tws_startup_ele *)
1836 (((vm_offset_t)startup->ele) +
1837 (startup->array_size * sizeof(struct tws_startup_ptr)));
1838 /* the allocation size and file size should be the same */
1839 /* just in case their not, make sure we dealloc correctly */
1840 startup->tws_hash_size = cache_size;
1841
9bccf70c
A
1842 tws->startup_cache = startup;
1843 tws_unlock(tws);
1844 return KERN_SUCCESS;
1845}
0b4e3aa0
A
1846
1847
90556fb8
A
1848void
1849tws_hash_ws_flush(tws_hash_t tws) {
1850 tws_startup_t scache;
1851 if(tws == NULL) {
1852 return;
1853 }
1854 tws_lock(tws);
1855 if(tws->startup_name != NULL) {
1856 scache = tws_create_startup_list(tws);
1857 if(scache == NULL) {
1858 /* dump the name cache, we'll */
1859 /* get it next time */
1860 kfree((vm_offset_t)
1861 tws->startup_name,
1862 tws->startup_name_length);
1863 tws->startup_name = NULL;
1864 tws_unlock(tws);
1865 return;
1866 }
1867 bsd_write_page_cache_file(tws->uid, tws->startup_name,
1868 scache, scache->tws_hash_size,
1869 tws->mod, tws->fid);
1870 kfree((vm_offset_t)scache,
1871 scache->tws_hash_size);
1872 kfree((vm_offset_t)
1873 tws->startup_name,
1874 tws->startup_name_length);
1875 tws->startup_name = NULL;
1876 }
1877 tws_unlock(tws);
1878 return;
1879}
1880
0b4e3aa0
A
1881void
1882tws_hash_destroy(tws_hash_t tws)
1883{
1884 int i,k;
1885 vm_size_t cache_size;
1886
9bccf70c
A
1887 if(tws->startup_cache != NULL) {
1888 kmem_free(kernel_map,
1889 (vm_offset_t)tws->startup_cache,
1890 tws->startup_cache->tws_hash_size);
1891 tws->startup_cache = NULL;
1892 }
1893 if(tws->startup_name != NULL) {
1894 tws_internal_startup_send(tws);
1895 }
0b4e3aa0
A
1896 for (i=0; i<tws->number_of_lines; i++) {
1897 for(k=0; k<tws->expansion_count; k++) {
1898 /* clear the object refs */
1899 tws_hash_line_clear(tws, &(tws->cache[k][i]), FALSE);
1900 }
1901 }
1902 i = 0;
1903 while (i < tws->expansion_count) {
1904
9bccf70c
A
1905 kfree((vm_offset_t)tws->table[i], sizeof(tws_hash_ptr_t)
1906 * tws->number_of_lines
1907 * tws->number_of_elements);
1908 kfree((vm_offset_t)tws->table_ele[i],
1909 sizeof(struct tws_hash_ptr)
1910 * tws->number_of_lines
0b4e3aa0 1911 * tws->number_of_elements);
9bccf70c
A
1912 kfree((vm_offset_t)tws->alt_ele[i],
1913 sizeof(struct tws_hash_ptr)
1914 * tws->number_of_lines
0b4e3aa0
A
1915 * tws->number_of_elements);
1916 kfree((vm_offset_t)tws->cache[i], sizeof(struct tws_hash_line)
1917 * tws->number_of_lines);
1918 i++;
1919 }
9bccf70c
A
1920 if(tws->startup_name != NULL) {
1921 kfree((vm_offset_t)tws->startup_name,
1922 tws->startup_name_length);
1923 }
0b4e3aa0
A
1924 kfree((vm_offset_t)tws, sizeof(struct tws_hash));
1925}
1926
1927void
1928tws_hash_clear(tws_hash_t tws)
1929{
1930 int i, k;
1931
1932 for (i=0; i<tws->number_of_lines; i++) {
1933 for(k=0; k<tws->expansion_count; k++) {
1934 /* clear the object refs */
1935 tws_hash_line_clear(tws, &(tws->cache[k][i]), FALSE);
1936 }
1937 }
1938}
1939
1940kern_return_t
1941task_working_set_create(
1942 task_t task,
1943 unsigned int lines,
1944 unsigned int rows,
1945 unsigned int style)
1946{
1947
1948 if (lines == 0) {
1949 lines = TWS_HASH_LINE_COUNT;
1950 }
1951 if (rows == 0) {
1952 rows = TWS_ARRAY_SIZE;
1953 }
1954 if (style == TWS_HASH_STYLE_DEFAULT) {
1955 style = TWS_HASH_STYLE_BASIC;
1956 }
1957 task_lock(task);
1958 if(task->dynamic_working_set != 0) {
1959 task_unlock(task);
1960 return(KERN_FAILURE);
1961 } else if((task->dynamic_working_set
1962 = (vm_offset_t) tws_hash_create(lines, rows, style)) == 0) {
1963 task_unlock(task);
1964 return(KERN_NO_SPACE);
1965 }
1966 task_unlock(task);
1967 return KERN_SUCCESS;
1968}
9bccf70c
A
1969
1970
1971/* Internal use only routines */
1972
1973
1974/*
1975 * internal sub-function for address space lookup
1976 * returns the target element and the address of the
1977 * previous pointer The previous pointer is the address
1978 * of the pointer pointing to the target element.
1979 * TWS must be locked
1980 */
1981
1982void
1983tws_traverse_address_hash_list (
1984 tws_hash_t tws,
1985 unsigned int index,
1986 vm_offset_t page_addr,
1987 vm_object_t object,
1988 vm_object_offset_t offset,
1989 vm_map_t map,
1990 tws_hash_ptr_t *target_ele,
1991 tws_hash_ptr_t **previous_ptr,
1992 tws_hash_ptr_t **free_list,
1993 unsigned int exclusive_addr)
1994{
1995 int k;
1996 tws_hash_ptr_t cache_ele;
1997 tws_hash_ptr_t base_ele;
1998
1999 *target_ele = NULL;
2000 *previous_ptr = NULL;
2001
2002 for(k=0; k<tws->expansion_count; k++) {
2003 tws_hash_ele_t ele;
2004 cache_ele = tws->table[k][index];
2005 base_ele = cache_ele;
2006 *previous_ptr = (tws_hash_ptr_t *)&(tws->table[k][index]);
2007 while(cache_ele != NULL) {
2008 if(((unsigned int)
2009 cache_ele->element & TWS_ADDR_HASH) == 0) {
2010 *previous_ptr = (tws_hash_ptr_t *)&(cache_ele->next);
2011 cache_ele = cache_ele->next;
2012 continue;
2013 }
2014 ele = (tws_hash_ele_t)((unsigned int)
2015 cache_ele->element & ~TWS_ADDR_HASH);
2016 if ((ele == 0) || (ele->object == 0)) {
2017 /* A little clean-up of empty elements */
2018 cache_ele->element = 0;
2019 if(base_ele == cache_ele) {
2020 base_ele = cache_ele->next;
2021 tws->table[k][index] = cache_ele->next;
2022 cache_ele->next = tws->free_hash_ele[k];
2023 tws->free_hash_ele[k] = cache_ele;
2024 cache_ele = base_ele;
2025 } else {
2026 **previous_ptr = cache_ele->next;
2027 cache_ele->next = tws->free_hash_ele[k];
2028 tws->free_hash_ele[k] = cache_ele;
2029 cache_ele = **previous_ptr;
2030 }
2031 continue;
2032 }
2033
2034 if ((ele->page_addr <= page_addr)
2035 && (page_addr <= (ele->page_addr +
2036 (vm_offset_t)TWS_INDEX_MASK))
2037 && ((object == NULL)
2038 || ((object == ele->object)
2039 && (offset == ele->offset)
2040 && (map == ele->map)))) {
2041 if(exclusive_addr) {
2042 int delta;
2043 delta = ((page_addr - ele->page_addr)
2044 >> 12);
2045 if((1 << delta) & ele->page_cache) {
2046 /* We've found a match */
2047 *target_ele = cache_ele;
2048 *free_list =
2049 (tws_hash_ptr_t *)
2050 &(tws->free_hash_ele[k]);
2051 return;
2052 }
2053 } else {
2054 /* We've found a match */
2055 *target_ele = cache_ele;
2056 *free_list = (tws_hash_ptr_t *)
2057 &(tws->free_hash_ele[k]);
2058 return;
2059 }
2060 }
2061 *previous_ptr = (tws_hash_ptr_t *)&(cache_ele->next);
2062 cache_ele = cache_ele->next;
2063 }
2064 }
2065}
2066
2067
2068/*
2069 * internal sub-function for object space lookup
2070 * returns the target element and the address of the
2071 * previous pointer The previous pointer is the address
2072 * of the pointer pointing to the target element.
2073 * TWS must be locked
2074 */
2075
2076
2077void
2078tws_traverse_object_hash_list (
2079 tws_hash_t tws,
2080 unsigned int index,
2081 vm_object_t object,
2082 vm_object_offset_t offset,
2083 unsigned int page_mask,
2084 tws_hash_ptr_t *target_ele,
2085 tws_hash_ptr_t **previous_ptr,
2086 tws_hash_ptr_t **free_list)
2087{
2088 int k;
2089 tws_hash_ptr_t cache_ele;
2090 tws_hash_ptr_t base_ele;
2091
2092 *target_ele = NULL;
2093 *previous_ptr = NULL;
2094
2095 for(k=0; k<tws->expansion_count; k++) {
2096 cache_ele = tws->table[k][index];
2097 base_ele = cache_ele;
2098 *previous_ptr = &(tws->table[k][index]);
2099 while(cache_ele != NULL) {
2100 if((((unsigned int)cache_ele->element)
2101 & TWS_ADDR_HASH) != 0) {
2102 *previous_ptr = &(cache_ele->next);
2103 cache_ele = cache_ele->next;
2104 continue;
2105 }
2106 if ((cache_ele->element == 0) ||
2107 (cache_ele->element->object == 0)) {
2108 /* A little clean-up of empty elements */
2109 cache_ele->element = 0;
2110 if(base_ele == cache_ele) {
2111 base_ele = cache_ele->next;
2112 tws->table[k][index] = cache_ele->next;
2113 cache_ele->next = tws->free_hash_ele[k];
2114 tws->free_hash_ele[k] = cache_ele;
2115 cache_ele = tws->table[k][index];
2116 } else {
2117 **previous_ptr = cache_ele->next;
2118 cache_ele->next = tws->free_hash_ele[k];
2119 tws->free_hash_ele[k] = cache_ele;
2120 cache_ele = **previous_ptr;
2121 }
2122 continue;
2123 }
2124 if ((cache_ele->element->object == object)
2125 && (cache_ele->element->offset ==
2126 (offset - (offset & ~TWS_HASH_OFF_MASK)))) {
2127 if((cache_ele->element->page_cache & page_mask)
2128 || (page_mask == 0xFFFFFFFF)) {
2129 /* We've found a match */
2130 *target_ele = cache_ele;
2131 *free_list = &(tws->free_hash_ele[k]);
2132 return;
2133 }
2134 }
2135 *previous_ptr = (tws_hash_ptr_t *)&(cache_ele->next);
2136 cache_ele = cache_ele->next;
2137 }
2138 }
2139}
2140
2141
2142/*
2143 * For a given object/offset, discover whether the indexed 32 page frame
2144 * containing the object/offset exists and if their are at least threshold
2145 * pages present. Returns true if population meets threshold.
2146 */
2147int
2148tws_test_for_community(
2149 tws_hash_t tws,
2150 vm_object_t object,
2151 vm_object_offset_t offset,
2152 unsigned int threshold,
2153 unsigned int *page_mask)
2154{
2155 int index;
2156 tws_hash_ptr_t cache_ele;
2157 tws_hash_ptr_t *trailer;
2158 tws_hash_ptr_t *free_list;
2159 int community = 0;
2160
2161 index = do_tws_hash(object, offset,
2162 tws->number_of_elements, tws->number_of_lines);
2163 tws_traverse_object_hash_list(tws, index, object, offset, 0xFFFFFFFF,
2164 &cache_ele, &trailer, &free_list);
2165
2166 if(cache_ele != NULL) {
2167 int i;
2168 int ctr;
2169 ctr = 0;
2170 for(i=1; i!=0; i=i<<1) {
2171 if(i & cache_ele->element->page_cache)
2172 ctr++;
2173 if(ctr == threshold) {
2174 community = 1;
2175 *page_mask = cache_ele->element->page_cache;
2176 break;
2177 }
2178 }
2179 }
2180
2181 return community;
2182
2183}
2184
2185
2186/*
2187 * Gets new hash element for object hash from free pools
2188 * TWS must be locked
2189 */
2190
2191tws_hash_ptr_t
2192new_obj_hash(
2193 tws_hash_t tws,
2194 unsigned int set,
2195 unsigned int index)
2196{
2197 tws_hash_ptr_t element;
2198
2199 if(tws->obj_free_count[set] < tws->number_of_lines * tws->number_of_elements) {
2200 element = &(tws->table_ele[set][tws->obj_free_count[set]]);
2201 tws->obj_free_count[set]+=1;
2202 } else if(tws->free_hash_ele[set] == NULL) {
2203 return NULL;
2204 } else {
2205 element = tws->free_hash_ele[set];
2206 if(element == NULL)
2207 return element;
2208 tws->free_hash_ele[set] = tws->free_hash_ele[set]->next;
2209 }
2210 element->element = 0;
2211 element->next = tws->table[set][index];
2212 tws->table[set][index] = element;
2213 return element;
2214}
2215
2216/*
2217 * Gets new hash element for addr hash from free pools
2218 * TWS must be locked
2219 */
2220
2221tws_hash_ptr_t
2222new_addr_hash(
2223 tws_hash_t tws,
2224 unsigned int set,
2225 unsigned int index)
2226{
2227 tws_hash_ptr_t element;
2228
2229 if(tws->addr_free_count[set]
2230 < tws->number_of_lines * tws->number_of_elements) {
2231 element = &(tws->alt_ele[set][tws->addr_free_count[set]]);
2232 tws->addr_free_count[set]+=1;
2233 } else if(tws->free_hash_ele[set] == NULL) {
2234 return NULL;
2235 } else {
2236 element = tws->free_hash_ele[set];
2237 if(element == NULL)
2238 return element;
2239 tws->free_hash_ele[set] = tws->free_hash_ele[set]->next;
2240 }
2241 element->element = (tws_hash_ele_t)TWS_ADDR_HASH;
2242 element->next = tws->table[set][index];
2243 tws->table[set][index] = element;
2244 return element;
2245}