3 * Copyright (c) 2002,2000 Apple Computer, Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
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.
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
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
18 * License for the specific language governing rights and limitations
21 * @APPLE_LICENSE_HEADER_END@
26 * File: vm/task_working_set.c
27 * Author: Chris Youngworth
30 * Working set detection and maintainence module
34 #include <mach/mach_types.h>
35 #include <mach/shared_memory_server.h>
36 #include <vm/task_working_set.h>
37 #include <vm/vm_kern.h>
38 #include <vm/vm_map.h>
39 #include <vm/vm_page.h>
40 #include <vm/vm_pageout.h>
41 #include <kern/sched.h>
43 extern unsigned sched_tick
;
44 extern zone_t lsf_zone
;
46 /* declarations for internal use only routines */
49 tws_create_startup_list(
53 tws_startup_list_lookup(
54 tws_startup_t startup
,
58 tws_internal_startup_send(
62 tws_traverse_address_hash_list (
65 vm_offset_t page_addr
,
67 vm_object_offset_t offset
,
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
);
75 tws_traverse_object_hash_list (
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
);
97 int tws_test_for_community(
100 vm_object_offset_t offset
,
101 unsigned int threshold
,
102 unsigned int *page_mask
);
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 */
118 if ((style
!= TWS_HASH_STYLE_BASIC
) &&
119 (style
!= TWS_HASH_STYLE_BASIC
)) {
120 return((tws_hash_t
)NULL
);
124 tws
= (tws_hash_t
)(kalloc(sizeof(struct tws_hash
)));
125 if(tws
== (tws_hash_t
)NULL
)
128 if((tws
->table
[0] = (tws_hash_ptr_t
*)
129 kalloc(sizeof(tws_hash_ptr_t
) * lines
* rows
))
131 kfree((vm_offset_t
)tws
, sizeof(struct tws_hash
));
132 return (tws_hash_t
)NULL
;
134 if((tws
->table_ele
[0] = (tws_hash_ptr_t
)
135 kalloc(sizeof(struct tws_hash_ptr
) * lines
* rows
))
137 kfree((vm_offset_t
)tws
->table
[0], sizeof(tws_hash_ele_t
)
139 kfree((vm_offset_t
)tws
, sizeof(struct tws_hash
));
140 return (tws_hash_t
)NULL
;
142 if((tws
->alt_ele
[0] = (tws_hash_ptr_t
)
143 kalloc(sizeof(struct tws_hash_ptr
) * lines
* rows
))
145 kfree((vm_offset_t
)tws
->table
[0], sizeof(tws_hash_ptr_t
)
147 kfree((vm_offset_t
)tws
->table_ele
[0],
148 sizeof(struct tws_hash_ptr
)
150 kfree((vm_offset_t
)tws
, sizeof(struct tws_hash
));
151 return (tws_hash_t
)NULL
;
153 if((tws
->cache
[0] = (struct tws_hash_line
*)
154 kalloc(sizeof(struct tws_hash_line
) * lines
))
156 kfree((vm_offset_t
)tws
->table
[0], sizeof(tws_hash_ptr_t
)
158 kfree((vm_offset_t
)tws
->table_ele
[0],
159 sizeof(struct tws_hash_ptr
)
161 kfree((vm_offset_t
)tws
->alt_ele
[0], sizeof(struct tws_hash_ptr
)
163 kfree((vm_offset_t
)tws
, sizeof(struct tws_hash
));
164 return (tws_hash_t
)NULL
;
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;
170 /* most defaults are such that a bzero will initialize */
171 bzero((char *)tws
->table
[0],sizeof(tws_hash_ptr_t
)
173 bzero((char *)tws
->table_ele
[0],sizeof(struct tws_hash_ptr
)
175 bzero((char *)tws
->alt_ele
[0],sizeof(struct tws_hash_ptr
)
177 bzero((char *)tws
->cache
[0], sizeof(struct tws_hash_line
)
180 mutex_init(&tws
->lock
, ETAP_VM_MAP
);
182 tws
->current_line
= 0;
183 tws
->pageout_count
= 0;
185 tws
->startup_cache
= NULL
;
186 tws
->startup_name
= NULL
;
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
;
201 tws_hash_line_t hash_line
,
204 struct tws_hash_ele
*hash_ele
;
205 struct tws_hash_ptr
**trailer
;
206 struct tws_hash_ptr
**free_list
;
207 tws_hash_ele_t addr_ele
;
209 unsigned int i
, j
, k
;
214 if(tws
->line_count
< tws
->number_of_lines
) {
218 if(tws
->pageout_count
!= vm_pageout_scan_event_counter
) {
220 vm_pageout_scan_event_counter
;
227 hash_line
->ele_count
= 0;
229 for (i
=0; i
<tws
->number_of_elements
; i
++) {
231 hash_ele
= &(hash_line
->list
[i
]);
232 if(hash_ele
->object
!= 0) {
234 vm_object_offset_t local_off
= 0;
235 tws_hash_ptr_t cache_ele
;
237 index
= alt_tws_hash(
238 hash_ele
->page_addr
& TWS_HASH_OFF_MASK
,
239 tws
->number_of_elements
,
240 tws
->number_of_lines
);
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:"
252 cache_ele
->element
= 0;
253 *trailer
= cache_ele
->next
;
254 cache_ele
->next
= *free_list
;
255 *free_list
= cache_ele
;
258 index
= alt_tws_hash(
259 (hash_ele
->page_addr
- 0x1f000)
261 tws
->number_of_elements
,
262 tws
->number_of_lines
);
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);
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: "
275 cache_ele
->element
= 0;
276 *trailer
= cache_ele
->next
;
277 cache_ele
->next
= *free_list
;
278 *free_list
= cache_ele
;
282 if((hash_ele
->map
!= NULL
) && (live
)) {
285 for (j
= 0x1; j
!= 0; j
= j
<<1) {
286 if(j
& hash_ele
->page_cache
) {
287 p
= vm_page_lookup(hash_ele
->object
,
288 hash_ele
->offset
+ local_off
);
289 if((p
!= NULL
) && (p
->wire_count
== 0)
290 && (dump_pmap
== 1)) {
291 pmap_remove_some_phys((pmap_t
)
297 local_off
+= PAGE_SIZE_64
;
301 if(tws
->style
== TWS_HASH_STYLE_SIGNAL
) {
302 vm_object_deallocate(hash_ele
->object
);
303 vm_map_deallocate(hash_ele
->map
);
306 index
= do_tws_hash(hash_ele
->object
, hash_ele
->offset
,
307 tws
->number_of_elements
,
308 tws
->number_of_lines
);
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
;
319 hash_ele
->object
= 0;
327 vm_object_offset_t offset
,
329 tws_hash_line_t
*line
)
336 tws_hash_ptr_t cache_ele
;
337 tws_hash_ptr_t
*trailer
;
338 tws_hash_ptr_t
*free_list
;
340 /* don't cache private objects */
344 if(!tws_lock_try(tws
)) {
348 index
= do_tws_hash(object
, offset
,
349 tws
->number_of_elements
, tws
->number_of_lines
);
353 if(tws
->lookup_count
== 0)
354 tws
->insert_count
= 0;
355 if(tws
->startup_name
!= NULL
) {
357 age_of_cache
= ((sched_tick
358 - tws
->time_of_creation
) >> SCHED_TICK_SHIFT
);
359 if (age_of_cache
> 35) {
361 return KERN_OPERATION_TIMED_OUT
;
365 if(tws
->lookup_count
> (4 * tws
->expansion_count
366 * tws
->number_of_elements
* tws
->number_of_lines
) &&
367 (tws
->lookup_count
> (2 * tws
->insert_count
))) {
368 if(tws
->startup_cache
) {
370 age_of_cache
= ((sched_tick
371 - tws
->time_of_creation
) >> SCHED_TICK_SHIFT
);
372 if (age_of_cache
> 60) {
374 return KERN_OPERATION_TIMED_OUT
;
379 pagenum
= (vm_offset_t
)(offset
& TWS_INDEX_MASK
);
380 pagenum
= pagenum
>> 12;
381 pagenum
= 1 << pagenum
; /* get the appropriate page in 32 page block */
382 tws_traverse_object_hash_list(tws
, index
, object
, offset
, pagenum
,
383 &cache_ele
, &trailer
, &free_list
);
384 if(cache_ele
!= NULL
) {
385 set
= cache_ele
->element
->line
/tws
->number_of_lines
;
386 ele_line
= cache_ele
->element
->line
- set
;
387 *line
= &tws
->cache
[set
][ele_line
];
399 tws_expand_working_set(
407 struct tws_hash temp
;
409 old_tws
= (tws_hash_t
)tws
;
411 /* Note we do an elaborate dance to preserve the header that */
412 /* task is pointing to. In this way we can avoid taking a task */
413 /* lock every time we want to access the tws */
415 if (old_tws
->number_of_lines
>= line_count
) {
418 if((new_tws
= tws_hash_create(line_count
,
419 old_tws
->number_of_elements
, old_tws
->style
)) == 0) {
420 return(KERN_NO_SPACE
);
425 for(i
= 0; i
<old_tws
->number_of_lines
; i
++) {
426 for(j
= 0; j
<old_tws
->number_of_elements
; j
++) {
427 for(k
= 0; k
<old_tws
->expansion_count
; k
++) {
428 tws_hash_ele_t entry
;
429 vm_object_offset_t paddr
;
430 unsigned int page_index
;
431 entry
= &old_tws
->cache
[k
][i
].list
[j
];
432 if(entry
->object
!= 0) {
434 for(page_index
= 1; page_index
!= 0;
435 page_index
= page_index
<< 1); {
436 if (entry
->page_cache
& page_index
) {
440 entry
->page_addr
+paddr
,
452 temp
.style
= new_tws
->style
;
453 temp
.current_line
= new_tws
->current_line
;
454 temp
.pageout_count
= new_tws
->pageout_count
;
455 temp
.line_count
= new_tws
->line_count
;
456 temp
.number_of_lines
= new_tws
->number_of_lines
;
457 temp
.number_of_elements
= new_tws
->number_of_elements
;
458 temp
.expansion_count
= new_tws
->expansion_count
;
459 temp
.lookup_count
= new_tws
->lookup_count
;
460 temp
.insert_count
= new_tws
->insert_count
;
461 for(i
= 0; i
<new_tws
->expansion_count
; i
++) {
462 temp
.obj_free_count
[i
] = new_tws
->obj_free_count
[i
];
463 temp
.addr_free_count
[i
] = new_tws
->addr_free_count
[i
];
464 temp
.free_hash_ele
[i
] = new_tws
->free_hash_ele
[i
];
465 temp
.table
[i
] = new_tws
->table
[i
];
466 temp
.table_ele
[i
] = new_tws
->table_ele
[i
];
467 temp
.alt_ele
[i
] = new_tws
->alt_ele
[i
];
468 temp
.cache
[i
] = new_tws
->cache
[i
];
471 new_tws
->style
= old_tws
->style
;
472 new_tws
->current_line
= old_tws
->current_line
;
473 new_tws
->pageout_count
= old_tws
->pageout_count
;
474 new_tws
->line_count
= old_tws
->line_count
;
475 new_tws
->number_of_lines
= old_tws
->number_of_lines
;
476 new_tws
->number_of_elements
= old_tws
->number_of_elements
;
477 new_tws
->expansion_count
= old_tws
->expansion_count
;
478 new_tws
->lookup_count
= old_tws
->lookup_count
;
479 new_tws
->insert_count
= old_tws
->insert_count
;
480 for(i
= 0; i
<old_tws
->expansion_count
; i
++) {
481 new_tws
->obj_free_count
[i
] = old_tws
->obj_free_count
[i
];
482 new_tws
->addr_free_count
[i
] = old_tws
->addr_free_count
[i
];
483 new_tws
->free_hash_ele
[i
] = old_tws
->free_hash_ele
[i
];
484 new_tws
->table
[i
] = old_tws
->table
[i
];
485 new_tws
->table_ele
[i
] = old_tws
->table_ele
[i
];
486 new_tws
->alt_ele
[i
] = old_tws
->alt_ele
[i
];
487 new_tws
->cache
[i
] = old_tws
->cache
[i
];
490 old_tws
->style
= temp
.style
;
491 old_tws
->current_line
= temp
.current_line
;
492 old_tws
->pageout_count
= temp
.pageout_count
;
493 old_tws
->line_count
= temp
.line_count
;
494 old_tws
->number_of_lines
= temp
.number_of_lines
;
495 old_tws
->number_of_elements
= temp
.number_of_elements
;
496 old_tws
->expansion_count
= temp
.expansion_count
;
497 old_tws
->lookup_count
= temp
.lookup_count
;
498 old_tws
->insert_count
= temp
.insert_count
;
499 for(i
= 0; i
<temp
.expansion_count
; i
++) {
500 old_tws
->obj_free_count
[i
] = temp
.obj_free_count
[i
];;
501 old_tws
->addr_free_count
[i
] = temp
.addr_free_count
[i
];;
502 old_tws
->free_hash_ele
[i
] = NULL
;
503 old_tws
->table
[i
] = temp
.table
[i
];
504 old_tws
->table_ele
[i
] = temp
.table_ele
[i
];
505 old_tws
->alt_ele
[i
] = temp
.alt_ele
[i
];
506 old_tws
->cache
[i
] = temp
.cache
[i
];
509 tws_hash_destroy(new_tws
);
514 tws_hash_t test_tws
= 0;
519 vm_object_offset_t offset
,
521 vm_offset_t page_addr
,
526 unsigned int alt_index
;
527 unsigned int index_enum
[2];
528 unsigned int ele_index
;
529 tws_hash_ptr_t cache_ele
;
530 tws_hash_ptr_t obj_ele
= NULL
;
531 tws_hash_ptr_t addr_ele
= NULL
;
532 tws_hash_ptr_t
*trailer
;
533 tws_hash_ptr_t
*free_list
;
534 tws_hash_ele_t target_element
= NULL
;
539 unsigned int startup_cache_line
;
540 vm_offset_t startup_page_addr
;
542 int ask_for_startup_cache_release
= 0;
545 if(!tws_lock_try(tws
)) {
549 current_line
= 0xFFFFFFFF;
551 startup_cache_line
= 0;
553 page_addr
- (offset
- (offset
& TWS_HASH_OFF_MASK
));
554 if(tws
->startup_cache
) {
556 age_of_cache
= ((sched_tick
- tws
->time_of_creation
)
557 >> SCHED_TICK_SHIFT
);
558 startup_cache_line
= tws_startup_list_lookup(
559 tws
->startup_cache
, startup_page_addr
);
560 if(tws
== test_tws
) {
561 printf("cache_lookup, result = 0x%x, addr = 0x%x, object 0x%x, offset 0x%x%x\n", startup_cache_line
, startup_page_addr
, object
, offset
);
563 if(age_of_cache
> 60) {
564 ask_for_startup_cache_release
= 1;
567 if((tws
->startup_name
!= NULL
) && (tws
->mod
== 0)) {
568 /* Ensure as good a working set as possible */
569 pmap_remove(map
->pmap
, 0, GLOBAL_SHARED_TEXT_SEGMENT
);
570 pmap_remove(map
->pmap
,
571 GLOBAL_SHARED_DATA_SEGMENT
572 + SHARED_DATA_REGION_SIZE
, 0xFFFFF000);
575 /* This next bit of code, the and alternate hash */
576 /* are all made necessary because of IPC COW */
578 /* Note: the use of page_addr modified by delta from offset */
579 /* frame base means we may miss some previous entries. However */
580 /* we will not miss the present entry. This is most important */
581 /* in avoiding duplication of entries against long lived non-cow */
583 index_enum
[0] = alt_tws_hash(
584 page_addr
& TWS_HASH_OFF_MASK
,
585 tws
->number_of_elements
, tws
->number_of_lines
);
587 index_enum
[1] = alt_tws_hash(
588 (page_addr
- 0x1f000) & TWS_HASH_OFF_MASK
,
589 tws
->number_of_elements
, tws
->number_of_lines
);
591 for(ctr
= 0; ctr
< 2;) {
592 tws_hash_ele_t resident
;
593 tws_traverse_address_hash_list(tws
,
594 index_enum
[ctr
], page_addr
, NULL
,
596 &cache_ele
, &trailer
, &free_list
, 1);
597 if(cache_ele
!= NULL
) {
599 resident
= (tws_hash_ele_t
)((unsigned int)
600 cache_ele
->element
& ~TWS_ADDR_HASH
);
601 if((object
== resident
->object
) &&
603 (offset
& TWS_HASH_OFF_MASK
)) {
604 /* This is our object/offset */
606 |= startup_cache_line
;
607 resident
->page_cache
|=
609 (offset
& TWS_INDEX_MASK
))>>12));
611 if(ask_for_startup_cache_release
)
612 return KERN_OPERATION_TIMED_OUT
;
615 if((object
->shadow
==
618 + object
->shadow_offset
)
619 == (offset
& TWS_HASH_OFF_MASK
))) {
620 /* if we just shadowed, inherit */
621 /* access pattern from parent */
622 startup_cache_line
|=
623 resident
->page_cache
;
624 /* thow out old entry */
625 resident
->page_cache
= 0;
628 resident
->page_cache
&=
629 ~(1<<(((vm_offset_t
)(page_addr
630 - resident
->page_addr
))
633 /* Throw out old entry if there are no */
634 /* more pages in cache */
635 if(resident
->page_cache
== 0) {
636 /* delete addr hash entry */
637 cache_ele
->element
= 0;
638 *trailer
= cache_ele
->next
;
639 cache_ele
->next
= *free_list
;
640 *free_list
= cache_ele
;
641 /* go after object hash */
645 tws
->number_of_elements
,
646 tws
->number_of_lines
);
647 tws_traverse_object_hash_list(tws
,
648 index
, resident
->object
,
650 0xFFFFFFFF, &cache_ele
,
651 &trailer
, &free_list
);
652 if(cache_ele
!= NULL
) {
654 TWS_HASH_STYLE_SIGNAL
) {
655 vm_object_deallocate(
656 cache_ele
->element
->object
);
658 cache_ele
->element
->map
);
661 cache_ele
->element
->line
;
663 /tws
->number_of_lines
;
664 current_line
-= set
*
665 tws
->number_of_lines
;
666 if(cache_ele
->element
->object
!= 0) {
667 cache_ele
->element
->object
= 0;
669 [current_line
].ele_count
--;
671 cache_ele
->element
= 0;
672 *trailer
= cache_ele
->next
;
673 cache_ele
->next
= *free_list
;
674 *free_list
= cache_ele
;
683 * We may or may not have a current line setting coming out of
684 * the code above. If we have a current line it means we can
685 * choose to back-fill the spot vacated by a previous entry.
686 * We have yet to do a definitive check using the original obj/off
687 * We will do that now and override the current line if we
691 index
= do_tws_hash(object
, offset
,
692 tws
->number_of_elements
, tws
->number_of_lines
);
694 alt_index
= index_enum
[0];
696 tws_traverse_object_hash_list(tws
, index
, object
, offset
,
697 0xFFFFFFFF, &cache_ele
, &trailer
, &free_list
);
698 if(cache_ele
!= NULL
) {
700 current_line
= cache_ele
->element
->line
;
701 set
= current_line
/tws
->number_of_lines
;
702 current_line
-= set
* tws
->number_of_lines
;
703 target_element
= cache_ele
->element
;
705 /* Now check to see if we have a hash addr for it */
706 tws_traverse_address_hash_list(tws
,
707 alt_index
, obj_ele
->element
->page_addr
,
708 obj_ele
->element
->object
,
709 obj_ele
->element
->offset
,
710 obj_ele
->element
->map
,
711 &cache_ele
, &trailer
, &free_list
, 0);
712 if(cache_ele
!= NULL
) {
713 addr_ele
= cache_ele
;
715 addr_ele
= new_addr_hash(tws
, set
, alt_index
);
716 /* if cannot allocate just do without */
717 /* we'll get it next time around */
723 if(tws
->style
== TWS_HASH_STYLE_SIGNAL
) {
724 vm_object_reference(object
);
725 vm_map_reference(map
);
728 if(current_line
== 0xFFFFFFFF) {
729 current_line
= tws
->current_line
;
730 set
= current_line
/tws
->number_of_lines
;
731 current_line
= current_line
- (set
* tws
->number_of_lines
);
735 tws
->current_line
= tws
->number_of_lines
- 1;
738 if(tws
->cache
[set
][current_line
].ele_count
739 >= tws
->number_of_elements
) {
742 if(current_line
== tws
->number_of_lines
) {
745 if (set
== tws
->expansion_count
) {
746 if((tws
->lookup_count
<
747 (2 * tws
->insert_count
)) &&
748 (set
<TWS_HASH_EXPANSION_MAX
)) {
749 tws
->lookup_count
= 0;
750 tws
->insert_count
= 0;
751 if(tws
->number_of_lines
752 < TWS_HASH_LINE_COUNT
) {
755 return KERN_NO_SPACE
;
757 if((tws
->table
[set
] = (tws_hash_ptr_t
*)
758 kalloc(sizeof(tws_hash_ptr_t
)
759 * tws
->number_of_lines
760 * tws
->number_of_elements
))
763 } else if((tws
->table_ele
[set
] =
765 kalloc(sizeof(struct tws_hash_ptr
)
766 * tws
->number_of_lines
767 * tws
->number_of_elements
))
769 kfree((vm_offset_t
)tws
->table
[set
],
770 sizeof(tws_hash_ptr_t
)
771 * tws
->number_of_lines
772 * tws
->number_of_elements
);
774 } else if((tws
->alt_ele
[set
] =
776 kalloc(sizeof(struct tws_hash_ptr
)
777 * tws
->number_of_lines
778 * tws
->number_of_elements
))
780 kfree((vm_offset_t
)tws
->table_ele
[set
],
781 sizeof(tws_hash_ptr_t
)
782 * tws
->number_of_lines
783 * tws
->number_of_elements
);
784 kfree((vm_offset_t
)tws
->table
[set
],
785 sizeof(struct tws_hash_ptr
)
786 * tws
->number_of_lines
787 * tws
->number_of_elements
);
788 tws
->table
[set
] = NULL
;
791 } else if((tws
->cache
[set
] =
792 (struct tws_hash_line
*)
794 (struct tws_hash_line
)
795 * tws
->number_of_lines
))
797 kfree((vm_offset_t
)tws
->table
[set
],
798 sizeof(tws_hash_ptr_t
)
799 * tws
->number_of_lines
800 * tws
->number_of_elements
);
801 kfree((vm_offset_t
)tws
->table_ele
[set
],
802 sizeof(struct tws_hash_ptr
)
803 * tws
->number_of_lines
804 * tws
->number_of_elements
);
805 kfree((vm_offset_t
)tws
->alt_ele
[set
],
806 sizeof(struct tws_hash_ptr
)
807 * tws
->number_of_lines
808 * tws
->number_of_elements
);
809 tws
->table
[set
] = NULL
;
813 tws
->free_hash_ele
[set
] =
815 tws
->obj_free_count
[set
] = 0;
816 tws
->addr_free_count
[set
] = 0;
817 bzero((char *)tws
->table
[set
],
818 sizeof(tws_hash_ptr_t
)
819 * tws
->number_of_lines
820 * tws
->number_of_elements
);
821 bzero((char *)tws
->table_ele
[set
],
822 sizeof(struct tws_hash_ptr
)
823 * tws
->number_of_lines
824 * tws
->number_of_elements
);
825 bzero((char *)tws
->alt_ele
[set
],
826 sizeof(struct tws_hash_ptr
)
827 * tws
->number_of_lines
828 * tws
->number_of_elements
);
829 bzero((char *)tws
->cache
[set
],
830 sizeof(struct tws_hash_line
)
831 * tws
->number_of_lines
);
837 tws
->time_of_creation
)
838 >> SCHED_TICK_SHIFT
);
840 if((tws
->startup_cache
) &&
841 (age_of_cache
> 60)) {
842 ask_for_startup_cache_release
= 1;
844 if((tws
->startup_name
!= NULL
) &&
845 (age_of_cache
> 15)) {
848 return KERN_OPERATION_TIMED_OUT
;
850 if((tws
->startup_name
!= NULL
) &&
851 (age_of_cache
< 15)) {
852 /* If we are creating a */
853 /* cache, don't lose the */
859 tws
->lookup_count
= 0;
860 tws
->insert_count
= 0;
864 tws
->current_line
= set
* tws
->number_of_lines
;
866 if(set
< tws
->expansion_count
) {
867 tws_hash_line_clear(tws
,
868 &(tws
->cache
[set
][current_line
]), TRUE
);
869 if(tws
->cache
[set
][current_line
].ele_count
870 >= tws
->number_of_elements
) {
871 if(tws
->style
== TWS_HASH_STYLE_SIGNAL
) {
872 vm_object_deallocate(object
);
873 vm_map_deallocate(map
);
879 tws
->expansion_count
++;
885 /* set object hash element */
886 if(obj_ele
== NULL
) {
887 obj_ele
= new_obj_hash(tws
, set
, index
);
888 if(obj_ele
== NULL
) {
889 tws
->cache
[set
][current_line
].ele_count
890 = tws
->number_of_elements
;
896 /* set address hash element */
897 if(addr_ele
== NULL
) {
898 addr_ele
= new_addr_hash(tws
, set
, alt_index
);
901 if(target_element
== NULL
) {
903 for(i
= 0; i
<tws
->number_of_elements
; i
++) {
904 if(tws
->cache
[set
][current_line
].
905 list
[ele_index
].object
== 0) {
909 if(ele_index
>= tws
->number_of_elements
)
914 if(i
== tws
->number_of_elements
)
915 panic("tws_insert: no free elements");
918 &(tws
->cache
[set
][current_line
].list
[ele_index
]);
920 tws
->cache
[set
][current_line
].ele_count
++;
923 obj_ele
->element
= target_element
;
925 addr_ele
->element
= (tws_hash_ele_t
)
926 (((unsigned int)target_element
) | TWS_ADDR_HASH
);
928 target_element
->object
= object
;
929 target_element
->offset
= offset
& TWS_HASH_OFF_MASK
;
930 target_element
->page_addr
=
931 page_addr
- (offset
- (offset
& TWS_HASH_OFF_MASK
));
932 target_element
->map
= map
;
933 target_element
->line
=
934 current_line
+ (set
* tws
->number_of_lines
);
935 if(startup_cache_line
) {
936 target_element
->page_cache
= startup_cache_line
;
938 target_element
->page_cache
|=
939 1<<(((vm_offset_t
)(offset
& TWS_INDEX_MASK
))>>12);
943 if(ask_for_startup_cache_release
)
944 return KERN_OPERATION_TIMED_OUT
;
950 * lengthen the cluster of pages by the number of pages encountered in the
951 * working set up to the limit requested by the caller. The object needs
952 * to be locked on entry. The map does not because the tws_lookup function
953 * is used only to find if their is an entry in the cache. No transient
954 * data from the cache is de-referenced.
959 * MACH page map - an optional optimization where a bit map is maintained
960 * by the VM subsystem for internal objects to indicate which pages of
961 * the object currently reside on backing store. This existence map
962 * duplicates information maintained by the vnode pager. It is
963 * created at the time of the first pageout against the object, i.e.
964 * at the same time pager for the object is created. The optimization
965 * is designed to eliminate pager interaction overhead, if it is
966 * 'known' that the page does not exist on backing store.
968 * LOOK_FOR() evaluates to TRUE if the page specified by object/offset is
969 * either marked as paged out in the existence map for the object or no
970 * existence map exists for the object. LOOK_FOR() is one of the
971 * criteria in the decision to invoke the pager. It is also used as one
972 * of the criteria to terminate the scan for adjacent pages in a clustered
973 * pagein operation. Note that LOOK_FOR() always evaluates to TRUE for
974 * permanent objects. Note also that if the pager for an internal object
975 * has not been created, the pager is not invoked regardless of the value
976 * of LOOK_FOR() and that clustered pagein scans are only done on an object
977 * for which a pager has been created.
979 * PAGED_OUT() evaluates to TRUE if the page specified by the object/offset
980 * is marked as paged out in the existence map for the object. PAGED_OUT()
981 * PAGED_OUT() is used to determine if a page has already been pushed
982 * into a copy object in order to avoid a redundant page out operation.
984 #define LOOK_FOR(o, f) (vm_external_state_get((o)->existence_map, (f)) \
985 != VM_EXTERNAL_STATE_ABSENT)
986 #define PAGED_OUT(o, f) (vm_external_state_get((o)->existence_map, (f)) \
987 == VM_EXTERNAL_STATE_EXISTS)
988 #else /* MACH_PAGEMAP */
990 * If the MACH page map optimization is not enabled,
991 * LOOK_FOR() always evaluates to TRUE. The pager will always be
992 * invoked to resolve missing pages in an object, assuming the pager
993 * has been created for the object. In a clustered page operation, the
994 * absence of a page on backing backing store cannot be used to terminate
995 * a scan for adjacent pages since that information is available only in
996 * the pager. Hence pages that may not be paged out are potentially
997 * included in a clustered request. The vnode pager is coded to deal
998 * with any combination of absent/present pages in a clustered
999 * pagein request. PAGED_OUT() always evaluates to FALSE, i.e. the pager
1000 * will always be invoked to push a dirty page into a copy object assuming
1001 * a pager has been created. If the page has already been pushed, the
1002 * pager will ingore the new request.
1004 #define LOOK_FOR(o, f) TRUE
1005 #define PAGED_OUT(o, f) FALSE
1006 #endif /* MACH_PAGEMAP */
1012 vm_object_offset_t
*start
,
1013 vm_object_offset_t
*end
,
1014 vm_size_t max_length
)
1016 tws_hash_line_t line
;
1018 vm_object_offset_t before
= *start
;
1019 vm_object_offset_t after
= *end
;
1020 vm_object_offset_t original_start
= *start
;
1021 vm_object_offset_t original_end
= *end
;
1022 vm_size_t length
= (vm_size_t
)(*end
- *start
);
1025 vm_object_offset_t object_size
;
1028 unsigned int ele_cache
;
1029 unsigned int end_cache
= NULL
;
1030 unsigned int start_cache
= NULL
;
1032 if((object
->private) || !(object
->pager
))
1035 if (!object
->internal
) {
1036 kret
= vnode_pager_get_object_size(
1040 object_size
= object
->size
;
1043 age_of_cache
= ((sched_tick
1044 - tws
->time_of_creation
) >> SCHED_TICK_SHIFT
);
1046 /* When pre-heat files are not available, resort to speculation */
1047 /* based on size of file */
1049 if(tws
->startup_cache
|| object
->internal
|| age_of_cache
> 15 ||
1050 (age_of_cache
> 5 &&
1051 vm_page_free_count
< (vm_page_free_target
* 2) )) {
1054 if (object_size
> (vm_object_offset_t
)(1024 * 1024))
1055 pre_heat_size
= 8 * PAGE_SIZE
;
1056 else if (object_size
> (vm_object_offset_t
)(128 * 1024))
1057 pre_heat_size
= 4 * PAGE_SIZE
;
1059 pre_heat_size
= 2 * PAGE_SIZE
;
1062 if ((age_of_cache
< 10) && (tws
->startup_cache
)) {
1063 if ((max_length
>= ((*end
- *start
)
1064 + (32 * PAGE_SIZE
))) &&
1065 (tws_test_for_community(tws
, object
,
1066 *start
, 3, &ele_cache
))) {
1068 start_cache
= ele_cache
;
1069 *start
= *start
& TWS_HASH_OFF_MASK
;
1070 *end
= *start
+ (32 * PAGE_SIZE_64
);
1071 if(*end
> object_size
) {
1072 *end
= trunc_page(object_size
);
1074 if(before
>= *end
) {
1077 end_cache
= ele_cache
;
1080 end_cache
= ele_cache
;
1082 while (max_length
> ((*end
- *start
)
1083 + (32 * PAGE_SIZE
))) {
1086 before
= *start
- PAGE_SIZE_64
;
1087 if((*end
<= (object
->size
1088 + (32 * PAGE_SIZE_64
))) &&
1089 (tws_test_for_community(tws
,
1093 (32 * PAGE_SIZE_64
);
1094 if(*end
> object_size
) {
1095 *end
= trunc_page(object_size
);
1097 if(*start
>= *end
) {
1101 end_cache
= ele_cache
;
1104 if (max_length
> ((*end
- *start
)
1105 + (32 * PAGE_SIZE_64
))) {
1108 if((*start
>= (32 * PAGE_SIZE_64
)) &&
1109 (tws_test_for_community(tws
, object
,
1110 before
, 5, &ele_cache
))) {
1112 start_cache
= ele_cache
;
1119 if(start_cache
!= NULL
) {
1122 for (mask
= 1; mask
!= 0; mask
= mask
<< 1) {
1123 if (*start
== original_start
)
1125 if (!(start_cache
& mask
))
1126 *start
+= PAGE_SIZE_64
;
1131 if(end_cache
!= NULL
) {
1134 for (mask
= 0x80000000;
1135 mask
!= 0; mask
= mask
>> 1) {
1136 if (*end
== original_end
)
1138 if(!(end_cache
& mask
))
1139 *end
-= PAGE_SIZE_64
;
1146 panic("bad clipping occurred\n");
1152 while ((length
< max_length
) &&
1154 (after
+ PAGE_SIZE_64
))) {
1155 if(length
>= pre_heat_size
) {
1156 if(tws_lookup(tws
, after
, object
,
1157 &line
) != KERN_SUCCESS
) {
1158 vm_object_offset_t extend
;
1160 extend
= after
+ PAGE_SIZE_64
;
1161 if(tws_lookup(tws
, extend
, object
,
1162 &line
) != KERN_SUCCESS
) {
1168 if ((object
->existence_map
!= NULL
)
1169 && (!LOOK_FOR(object
, after
))) {
1173 if (vm_page_lookup(object
, after
) != VM_PAGE_NULL
) {
1174 /* we can bridge resident pages */
1175 after
+= PAGE_SIZE_64
;
1176 length
+= PAGE_SIZE
;
1180 if (object
->internal
) {
1182 * need to acquire a real page in
1183 * advance because this acts as
1184 * a throttling mechanism for
1185 * data_requests to the default
1186 * pager. If this fails, give up
1187 * trying to find any more pages
1188 * in the cluster and send off the
1189 * request for what we already have.
1191 if ((m
= vm_page_grab()) == VM_PAGE_NULL
) {
1194 } else if ((m
= vm_page_grab_fictitious())
1200 m
->clustered
= TRUE
;
1201 m
->list_req_pending
= TRUE
;
1203 vm_page_insert(m
, object
, after
);
1204 object
->absent_count
++;
1205 after
+= PAGE_SIZE_64
;
1206 length
+= PAGE_SIZE
;
1209 while (length
< max_length
) {
1212 before
-= PAGE_SIZE_64
;
1214 if(length
>= pre_heat_size
) {
1215 if(tws_lookup(tws
, before
, object
,
1216 &line
) != KERN_SUCCESS
) {
1217 vm_object_offset_t extend
;
1222 extend
-= PAGE_SIZE_64
;
1223 if(tws_lookup(tws
, extend
, object
,
1224 &line
) != KERN_SUCCESS
) {
1229 if ((object
->existence_map
!= NULL
)
1230 && (!LOOK_FOR(object
, before
))) {
1234 if (vm_page_lookup(object
, before
) != VM_PAGE_NULL
) {
1235 /* we can bridge resident pages */
1236 *start
-= PAGE_SIZE_64
;
1237 length
+= PAGE_SIZE
;
1241 if (object
->internal
) {
1243 * need to acquire a real page in
1244 * advance because this acts as
1245 * a throttling mechanism for
1246 * data_requests to the default
1247 * pager. If this fails, give up
1248 * trying to find any more pages
1249 * in the cluster and send off the
1250 * request for what we already have.
1252 if ((m
= vm_page_grab()) == VM_PAGE_NULL
) {
1255 } else if ((m
= vm_page_grab_fictitious())
1261 m
->clustered
= TRUE
;
1262 m
->list_req_pending
= TRUE
;
1264 vm_page_insert(m
, object
, before
);
1265 object
->absent_count
++;
1266 *start
-= PAGE_SIZE_64
;
1267 length
+= PAGE_SIZE
;
1274 tws_hash_line_t hash_line
,
1275 vm_offset_t target_page
)
1279 vm_object_offset_t offset
;
1280 vm_object_offset_t before
;
1281 vm_object_offset_t after
;
1282 struct tws_hash_ele
*element
;
1286 if(tws
->style
!= TWS_HASH_STYLE_SIGNAL
)
1290 for (i
=0; i
<tws
->number_of_elements
; i
++) {
1292 vm_object_offset_t local_off
= 0;
1294 if(hash_line
->list
[i
].object
== 0)
1297 element
= &hash_line
->list
[i
];
1299 if (element
->page_addr
== target_page
)
1304 if(j
& element
->page_cache
)
1307 local_off
+= PAGE_SIZE_64
;
1309 object
= element
->object
;
1310 offset
= element
->offset
+ local_off
;
1312 /* first try a fast test to speed up no-op signal */
1313 if (((p
= vm_page_lookup(object
, offset
)) != NULL
)
1314 || (object
->pager
== NULL
)
1315 || (object
->shadow_severed
)) {
1319 if((!object
->alive
) ||
1320 (!object
->pager_created
) || (!object
->pager_ready
))
1323 if (object
->internal
) {
1324 if (object
->existence_map
== NULL
) {
1328 if(!LOOK_FOR(object
, offset
))
1333 vm_object_reference(object
);
1336 if(object
->internal
) {
1339 m
= vm_page_grab_fictitious();
1343 vm_object_deallocate(object
);
1348 vm_object_lock(object
);
1349 if (((p
= vm_page_lookup(object
, offset
)) != NULL
)
1350 || (object
->pager
== NULL
)
1351 || (object
->shadow_severed
)) {
1353 vm_object_unlock(object
);
1354 vm_object_deallocate(object
);
1359 vm_page_insert(m
, object
, offset
);
1361 if (object
->absent_count
> vm_object_absent_max
) {
1363 vm_object_unlock(object
);
1364 vm_object_deallocate(object
);
1368 m
->list_req_pending
= TRUE
;
1371 object
->absent_count
++;
1374 after
= offset
+ PAGE_SIZE_64
;
1375 tws_build_cluster(tws
, object
, &before
, &after
, 0x16000);
1376 vm_object_unlock(object
);
1378 rc
= memory_object_data_request(object
->pager
,
1379 before
+ object
->paging_offset
,
1380 (vm_size_t
)(after
- before
), VM_PROT_READ
);
1381 if (rc
!= KERN_SUCCESS
) {
1383 vm_object_lock(object
);
1384 while (offset
< after
) {
1385 m
= vm_page_lookup(object
, offset
);
1386 if(m
&& m
->absent
&& m
->busy
)
1388 offset
+= PAGE_SIZE
;
1390 vm_object_unlock(object
);
1391 vm_object_deallocate(object
);
1393 vm_object_deallocate(object
);
1401 /* tws locked on entry */
1404 tws_create_startup_list(
1408 tws_startup_t startup
;
1410 unsigned int total_elements
;
1411 unsigned int startup_size
;
1412 unsigned int sindex
;
1413 unsigned int hash_index
;
1414 tws_startup_ptr_t element
;
1416 total_elements
= tws
->expansion_count
*
1417 (tws
->number_of_lines
* tws
->number_of_elements
);
1419 startup_size
= sizeof(struct tws_startup
)
1420 + (total_elements
* sizeof(tws_startup_ptr_t
*))
1421 + (total_elements
* sizeof(struct tws_startup_ptr
))
1422 + (total_elements
* sizeof(struct tws_startup_ele
));
1423 startup
= (tws_startup_t
)(kalloc(startup_size
));
1428 bzero((char *) startup
, startup_size
);
1430 startup
->table
= (tws_startup_ptr_t
*)
1431 (((int)startup
) + (sizeof(struct tws_startup
)));
1432 startup
->ele
= (struct tws_startup_ptr
*)
1433 (((vm_offset_t
)startup
->table
) +
1434 (total_elements
* sizeof(tws_startup_ptr_t
)));
1436 startup
->array
= (struct tws_startup_ele
*)
1437 (((vm_offset_t
)startup
->ele
) +
1438 (total_elements
* sizeof(struct tws_startup_ptr
)));
1440 startup
->tws_hash_size
= startup_size
;
1441 startup
->ele_count
= 0; /* burn first hash ele, else we can't tell from zero */
1442 startup
->array_size
= total_elements
;
1443 startup
->hash_count
= 1;
1448 for(i
= 0; i
<tws
->number_of_lines
; i
++) {
1449 for(j
= 0; j
<tws
->number_of_elements
; j
++) {
1450 for(k
= 0; k
<tws
->expansion_count
; k
++) {
1451 tws_hash_ele_t entry
;
1452 unsigned int hash_retry
;
1455 entry
= &tws
->cache
[k
][i
].list
[j
];
1456 addr
= entry
->page_addr
;
1458 if(entry
->object
!= 0) {
1459 /* get a hash element */
1460 hash_index
= do_startup_hash(addr
,
1461 startup
->array_size
);
1463 if(startup
->hash_count
< total_elements
) {
1464 element
= &(startup
->ele
[startup
->hash_count
]);
1465 startup
->hash_count
+= 1;
1467 /* exit we're out of elements */
1470 /* place the hash element */
1471 element
->next
= startup
->table
[hash_index
];
1472 startup
->table
[hash_index
] = (tws_startup_ptr_t
)
1473 ((int)element
- (int)&startup
->ele
[0]);
1475 /* set entry OFFSET in hash element */
1476 element
->element
= (tws_startup_ele_t
)
1477 ((int)&startup
->array
[sindex
] -
1478 (int)&startup
->array
[0]);
1480 startup
->array
[sindex
].page_addr
= entry
->page_addr
;
1481 startup
->array
[sindex
].page_cache
= entry
->page_cache
;
1482 startup
->ele_count
++;
1495 * Returns an entire cache line. The line is deleted from the startup
1496 * cache on return. The caller can check startup->ele_count for an empty
1497 * list. Access synchronization is the responsibility of the caller.
1501 tws_startup_list_lookup(
1502 tws_startup_t startup
,
1505 unsigned int hash_index
;
1506 unsigned int page_cache_bits
;
1507 unsigned int startup_shift
;
1508 tws_startup_ele_t entry
;
1509 vm_offset_t next_addr
;
1510 tws_startup_ptr_t element
;
1511 tws_startup_ptr_t base_ele
;
1512 tws_startup_ptr_t
*previous_ptr
;
1514 page_cache_bits
= 0;
1516 hash_index
= do_startup_hash(addr
, startup
->array_size
);
1518 if(((unsigned int)&(startup
->table
[hash_index
])) >= startup
->tws_hash_size
) {
1519 return page_cache_bits
= 0;
1521 element
= (tws_startup_ptr_t
)((int)startup
->table
[hash_index
] +
1522 (int)&startup
->ele
[0]);
1524 previous_ptr
= &(startup
->table
[hash_index
]);
1525 while(element
> &startup
->ele
[0]) {
1526 if (((int)element
+ sizeof(struct tws_startup_ptr
))
1527 > ((int)startup
+ startup
->tws_hash_size
)) {
1528 return page_cache_bits
;
1530 entry
= (tws_startup_ele_t
)
1531 ((int)element
->element
1532 + (int)&startup
->array
[0]);
1533 if((((int)entry
+ sizeof(struct tws_startup_ele
))
1534 > ((int)startup
+ startup
->tws_hash_size
))
1535 || ((int)entry
< (int)startup
)) {
1536 return page_cache_bits
;
1538 if ((addr
>= entry
->page_addr
) &&
1539 (addr
<= (entry
->page_addr
+ 0x1F000))) {
1540 startup_shift
= (addr
- entry
->page_addr
)>>12;
1541 page_cache_bits
|= entry
->page_cache
>> startup_shift
;
1542 /* don't dump the pages, unless the addresses */
1543 /* line up perfectly. The cache may be used */
1544 /* by other mappings */
1545 entry
->page_cache
&= (1 << startup_shift
) - 1;
1546 if(addr
== entry
->page_addr
) {
1547 if(base_ele
== element
) {
1548 base_ele
= (tws_startup_ptr_t
)
1550 + (int)&startup
->ele
[0]);
1551 startup
->table
[hash_index
] = element
->next
;
1554 *previous_ptr
= element
->next
;
1555 element
= (tws_startup_ptr_t
)
1557 + (int)&startup
->ele
[0]);
1559 entry
->page_addr
= 0;
1560 startup
->ele_count
--;
1564 next_addr
= addr
+ 0x1F000;
1565 if ((next_addr
>= entry
->page_addr
) &&
1566 (next_addr
<= (entry
->page_addr
+ 0x1F000))) {
1567 startup_shift
= (next_addr
- entry
->page_addr
)>>12;
1568 page_cache_bits
|= entry
->page_cache
<< (0x1F - startup_shift
);
1569 entry
->page_cache
&= ~((1 << (startup_shift
+ 1)) - 1);
1570 if(entry
->page_cache
== 0) {
1571 if(base_ele
== element
) {
1572 base_ele
= (tws_startup_ptr_t
)
1574 + (int)&startup
->ele
[0]);
1575 startup
->table
[hash_index
] = element
->next
;
1578 *previous_ptr
= element
->next
;
1579 element
= (tws_startup_ptr_t
)
1581 + (int)&startup
->ele
[0]);
1583 entry
->page_addr
= 0;
1584 startup
->ele_count
--;
1588 previous_ptr
= &(element
->next
);
1589 element
= (tws_startup_ptr_t
)
1590 ((int) element
->next
+ (int) &startup
->ele
[0]);
1593 return page_cache_bits
;
1597 tws_send_startup_info(
1602 tws_startup_t scache
;
1605 tws
= (tws_hash_t
)task
->dynamic_working_set
;
1608 return KERN_FAILURE
;
1610 return tws_internal_startup_send(tws
);
1615 tws_internal_startup_send(
1619 tws_startup_t scache
;
1622 return KERN_FAILURE
;
1625 /* used to signal write or release depending on state of tws */
1626 if(tws
->startup_cache
) {
1627 vm_offset_t startup_buf
;
1629 startup_buf
= (vm_offset_t
)tws
->startup_cache
;
1630 size
= tws
->startup_cache
->tws_hash_size
;
1631 tws
->startup_cache
= 0;
1633 kmem_free(kernel_map
, startup_buf
, size
);
1634 return KERN_SUCCESS
;
1636 if(tws
->startup_name
== NULL
) {
1638 return KERN_FAILURE
;
1640 scache
= tws_create_startup_list(tws
);
1642 return KERN_FAILURE
;
1643 bsd_write_page_cache_file(tws
->uid
, tws
->startup_name
,
1644 scache
, scache
->tws_hash_size
,
1645 tws
->mod
, tws
->fid
);
1646 kfree((vm_offset_t
)scache
, scache
->tws_hash_size
);
1647 kfree((vm_offset_t
) tws
->startup_name
, tws
->startup_name_length
);
1648 tws
->startup_name
= NULL
;
1650 return KERN_SUCCESS
;
1654 tws_handle_startup_file(
1659 boolean_t
*new_info
)
1662 tws_startup_t startup
;
1663 vm_offset_t cache_size
;
1664 kern_return_t error
;
1669 /* don't pre-heat kernel task */
1670 if(task
== kernel_task
)
1671 return KERN_SUCCESS
;
1672 error
= bsd_read_page_cache_file(uid
, &fid
,
1677 return KERN_FAILURE
;
1679 if(startup
== NULL
) {
1680 /* Entry for app does not exist, make */
1682 /* we will want our own copy of the shared */
1683 /* regions to pick up a true picture of all */
1684 /* the pages we will touch. */
1685 if((lsf_zone
->count
* lsf_zone
->elem_size
)
1686 > (lsf_zone
->max_size
>> 1)) {
1687 /* We don't want to run out of shared memory */
1688 /* map entries by starting too many private versions */
1689 /* of the shared library structures */
1690 return KERN_SUCCESS
;
1693 error
= tws_write_startup_file(task
,
1694 fid
, mod
, app_name
, uid
);
1697 /* use the mod in the write case as an init */
1702 error
= tws_read_startup_file(task
,
1703 (tws_startup_t
)startup
,
1706 kmem_free(kernel_map
,
1707 (vm_offset_t
)startup
, cache_size
);
1711 return KERN_SUCCESS
;
1715 tws_write_startup_file(
1723 unsigned int string_length
;
1725 string_length
= strlen(name
);
1728 tws
= (tws_hash_t
)task
->dynamic_working_set
;
1732 /* create a dynamic working set of normal size */
1733 task_working_set_create(task
, 0,
1734 0, TWS_HASH_STYLE_DEFAULT
);
1738 if(tws
->startup_name
!= NULL
) {
1740 return KERN_FAILURE
;
1743 tws
->startup_name
= (char *)
1744 kalloc((string_length
+ 1) * (sizeof(char)));
1745 if(tws
->startup_name
== NULL
) {
1747 return KERN_FAILURE
;
1750 bcopy(name
, (char *)tws
->startup_name
, string_length
+ 1);
1751 tws
->startup_name_length
= (string_length
+ 1) * sizeof(char);
1757 return KERN_SUCCESS
;
1761 tws_read_startup_file(
1763 tws_startup_t startup
,
1764 vm_offset_t cache_size
)
1772 tws
= (tws_hash_t
)task
->dynamic_working_set
;
1774 if(cache_size
< sizeof(struct tws_hash
)) {
1776 kmem_free(kernel_map
, (vm_offset_t
)startup
, cache_size
);
1777 return(KERN_SUCCESS
);
1780 /* create a dynamic working set to match file size */
1781 lines
= (cache_size
- sizeof(struct tws_hash
))/TWS_ARRAY_SIZE
;
1782 /* we now need to divide out element size and word size */
1783 /* all fields are 4 bytes. There are 8 bytes in each hash element */
1784 /* entry, 4 bytes in each table ptr location and 8 bytes in each */
1785 /* page_cache entry, making a total of 20 bytes for each entry */
1786 lines
= (lines
/(20));
1787 if(lines
<= TWS_SMALL_HASH_LINE_COUNT
) {
1788 lines
= TWS_SMALL_HASH_LINE_COUNT
;
1790 kmem_free(kernel_map
, (vm_offset_t
)startup
, cache_size
);
1791 return(KERN_SUCCESS
);
1793 old_exp_count
= lines
/TWS_HASH_LINE_COUNT
;
1794 if((old_exp_count
* TWS_HASH_LINE_COUNT
) != lines
) {
1795 lines
= (old_exp_count
+ 1)
1796 * TWS_HASH_LINE_COUNT
;
1799 task_working_set_create(task
, lines
,
1800 0, TWS_HASH_STYLE_DEFAULT
);
1804 tws_expand_working_set(
1805 (vm_offset_t
)tws
, lines
, TRUE
);
1812 if(tws
->startup_cache
!= NULL
) {
1814 return KERN_FAILURE
;
1818 /* now need to fix up internal table pointers */
1819 startup
->table
= (tws_startup_ptr_t
*)
1820 (((int)startup
) + (sizeof(struct tws_startup
)));
1821 startup
->ele
= (struct tws_startup_ptr
*)
1822 (((vm_offset_t
)startup
->table
) +
1823 (startup
->array_size
* sizeof(tws_startup_ptr_t
)));
1824 startup
->array
= (struct tws_startup_ele
*)
1825 (((vm_offset_t
)startup
->ele
) +
1826 (startup
->array_size
* sizeof(struct tws_startup_ptr
)));
1827 /* the allocation size and file size should be the same */
1828 /* just in case their not, make sure we dealloc correctly */
1829 startup
->tws_hash_size
= cache_size
;
1832 tws
->startup_cache
= startup
;
1834 return KERN_SUCCESS
;
1839 tws_hash_destroy(tws_hash_t tws
)
1842 vm_size_t cache_size
;
1844 if(tws
->startup_cache
!= NULL
) {
1845 kmem_free(kernel_map
,
1846 (vm_offset_t
)tws
->startup_cache
,
1847 tws
->startup_cache
->tws_hash_size
);
1848 tws
->startup_cache
= NULL
;
1850 if(tws
->startup_name
!= NULL
) {
1851 tws_internal_startup_send(tws
);
1853 for (i
=0; i
<tws
->number_of_lines
; i
++) {
1854 for(k
=0; k
<tws
->expansion_count
; k
++) {
1855 /* clear the object refs */
1856 tws_hash_line_clear(tws
, &(tws
->cache
[k
][i
]), FALSE
);
1860 while (i
< tws
->expansion_count
) {
1862 kfree((vm_offset_t
)tws
->table
[i
], sizeof(tws_hash_ptr_t
)
1863 * tws
->number_of_lines
1864 * tws
->number_of_elements
);
1865 kfree((vm_offset_t
)tws
->table_ele
[i
],
1866 sizeof(struct tws_hash_ptr
)
1867 * tws
->number_of_lines
1868 * tws
->number_of_elements
);
1869 kfree((vm_offset_t
)tws
->alt_ele
[i
],
1870 sizeof(struct tws_hash_ptr
)
1871 * tws
->number_of_lines
1872 * tws
->number_of_elements
);
1873 kfree((vm_offset_t
)tws
->cache
[i
], sizeof(struct tws_hash_line
)
1874 * tws
->number_of_lines
);
1877 if(tws
->startup_name
!= NULL
) {
1878 kfree((vm_offset_t
)tws
->startup_name
,
1879 tws
->startup_name_length
);
1881 kfree((vm_offset_t
)tws
, sizeof(struct tws_hash
));
1885 tws_hash_clear(tws_hash_t tws
)
1889 for (i
=0; i
<tws
->number_of_lines
; i
++) {
1890 for(k
=0; k
<tws
->expansion_count
; k
++) {
1891 /* clear the object refs */
1892 tws_hash_line_clear(tws
, &(tws
->cache
[k
][i
]), FALSE
);
1898 task_working_set_create(
1906 lines
= TWS_HASH_LINE_COUNT
;
1909 rows
= TWS_ARRAY_SIZE
;
1911 if (style
== TWS_HASH_STYLE_DEFAULT
) {
1912 style
= TWS_HASH_STYLE_BASIC
;
1915 if(task
->dynamic_working_set
!= 0) {
1917 return(KERN_FAILURE
);
1918 } else if((task
->dynamic_working_set
1919 = (vm_offset_t
) tws_hash_create(lines
, rows
, style
)) == 0) {
1921 return(KERN_NO_SPACE
);
1924 return KERN_SUCCESS
;
1928 /* Internal use only routines */
1932 * internal sub-function for address space lookup
1933 * returns the target element and the address of the
1934 * previous pointer The previous pointer is the address
1935 * of the pointer pointing to the target element.
1936 * TWS must be locked
1940 tws_traverse_address_hash_list (
1943 vm_offset_t page_addr
,
1945 vm_object_offset_t offset
,
1947 tws_hash_ptr_t
*target_ele
,
1948 tws_hash_ptr_t
**previous_ptr
,
1949 tws_hash_ptr_t
**free_list
,
1950 unsigned int exclusive_addr
)
1953 tws_hash_ptr_t cache_ele
;
1954 tws_hash_ptr_t base_ele
;
1957 *previous_ptr
= NULL
;
1959 for(k
=0; k
<tws
->expansion_count
; k
++) {
1961 cache_ele
= tws
->table
[k
][index
];
1962 base_ele
= cache_ele
;
1963 *previous_ptr
= (tws_hash_ptr_t
*)&(tws
->table
[k
][index
]);
1964 while(cache_ele
!= NULL
) {
1966 cache_ele
->element
& TWS_ADDR_HASH
) == 0) {
1967 *previous_ptr
= (tws_hash_ptr_t
*)&(cache_ele
->next
);
1968 cache_ele
= cache_ele
->next
;
1971 ele
= (tws_hash_ele_t
)((unsigned int)
1972 cache_ele
->element
& ~TWS_ADDR_HASH
);
1973 if ((ele
== 0) || (ele
->object
== 0)) {
1974 /* A little clean-up of empty elements */
1975 cache_ele
->element
= 0;
1976 if(base_ele
== cache_ele
) {
1977 base_ele
= cache_ele
->next
;
1978 tws
->table
[k
][index
] = cache_ele
->next
;
1979 cache_ele
->next
= tws
->free_hash_ele
[k
];
1980 tws
->free_hash_ele
[k
] = cache_ele
;
1981 cache_ele
= base_ele
;
1983 **previous_ptr
= cache_ele
->next
;
1984 cache_ele
->next
= tws
->free_hash_ele
[k
];
1985 tws
->free_hash_ele
[k
] = cache_ele
;
1986 cache_ele
= **previous_ptr
;
1991 if ((ele
->page_addr
<= page_addr
)
1992 && (page_addr
<= (ele
->page_addr
+
1993 (vm_offset_t
)TWS_INDEX_MASK
))
1994 && ((object
== NULL
)
1995 || ((object
== ele
->object
)
1996 && (offset
== ele
->offset
)
1997 && (map
== ele
->map
)))) {
1998 if(exclusive_addr
) {
2000 delta
= ((page_addr
- ele
->page_addr
)
2002 if((1 << delta
) & ele
->page_cache
) {
2003 /* We've found a match */
2004 *target_ele
= cache_ele
;
2007 &(tws
->free_hash_ele
[k
]);
2011 /* We've found a match */
2012 *target_ele
= cache_ele
;
2013 *free_list
= (tws_hash_ptr_t
*)
2014 &(tws
->free_hash_ele
[k
]);
2018 *previous_ptr
= (tws_hash_ptr_t
*)&(cache_ele
->next
);
2019 cache_ele
= cache_ele
->next
;
2026 * internal sub-function for object space lookup
2027 * returns the target element and the address of the
2028 * previous pointer The previous pointer is the address
2029 * of the pointer pointing to the target element.
2030 * TWS must be locked
2035 tws_traverse_object_hash_list (
2039 vm_object_offset_t offset
,
2040 unsigned int page_mask
,
2041 tws_hash_ptr_t
*target_ele
,
2042 tws_hash_ptr_t
**previous_ptr
,
2043 tws_hash_ptr_t
**free_list
)
2046 tws_hash_ptr_t cache_ele
;
2047 tws_hash_ptr_t base_ele
;
2050 *previous_ptr
= NULL
;
2052 for(k
=0; k
<tws
->expansion_count
; k
++) {
2053 cache_ele
= tws
->table
[k
][index
];
2054 base_ele
= cache_ele
;
2055 *previous_ptr
= &(tws
->table
[k
][index
]);
2056 while(cache_ele
!= NULL
) {
2057 if((((unsigned int)cache_ele
->element
)
2058 & TWS_ADDR_HASH
) != 0) {
2059 *previous_ptr
= &(cache_ele
->next
);
2060 cache_ele
= cache_ele
->next
;
2063 if ((cache_ele
->element
== 0) ||
2064 (cache_ele
->element
->object
== 0)) {
2065 /* A little clean-up of empty elements */
2066 cache_ele
->element
= 0;
2067 if(base_ele
== cache_ele
) {
2068 base_ele
= cache_ele
->next
;
2069 tws
->table
[k
][index
] = cache_ele
->next
;
2070 cache_ele
->next
= tws
->free_hash_ele
[k
];
2071 tws
->free_hash_ele
[k
] = cache_ele
;
2072 cache_ele
= tws
->table
[k
][index
];
2074 **previous_ptr
= cache_ele
->next
;
2075 cache_ele
->next
= tws
->free_hash_ele
[k
];
2076 tws
->free_hash_ele
[k
] = cache_ele
;
2077 cache_ele
= **previous_ptr
;
2081 if ((cache_ele
->element
->object
== object
)
2082 && (cache_ele
->element
->offset
==
2083 (offset
- (offset
& ~TWS_HASH_OFF_MASK
)))) {
2084 if((cache_ele
->element
->page_cache
& page_mask
)
2085 || (page_mask
== 0xFFFFFFFF)) {
2086 /* We've found a match */
2087 *target_ele
= cache_ele
;
2088 *free_list
= &(tws
->free_hash_ele
[k
]);
2092 *previous_ptr
= (tws_hash_ptr_t
*)&(cache_ele
->next
);
2093 cache_ele
= cache_ele
->next
;
2100 * For a given object/offset, discover whether the indexed 32 page frame
2101 * containing the object/offset exists and if their are at least threshold
2102 * pages present. Returns true if population meets threshold.
2105 tws_test_for_community(
2108 vm_object_offset_t offset
,
2109 unsigned int threshold
,
2110 unsigned int *page_mask
)
2113 tws_hash_ptr_t cache_ele
;
2114 tws_hash_ptr_t
*trailer
;
2115 tws_hash_ptr_t
*free_list
;
2118 index
= do_tws_hash(object
, offset
,
2119 tws
->number_of_elements
, tws
->number_of_lines
);
2120 tws_traverse_object_hash_list(tws
, index
, object
, offset
, 0xFFFFFFFF,
2121 &cache_ele
, &trailer
, &free_list
);
2123 if(cache_ele
!= NULL
) {
2127 for(i
=1; i
!=0; i
=i
<<1) {
2128 if(i
& cache_ele
->element
->page_cache
)
2130 if(ctr
== threshold
) {
2132 *page_mask
= cache_ele
->element
->page_cache
;
2144 * Gets new hash element for object hash from free pools
2145 * TWS must be locked
2154 tws_hash_ptr_t element
;
2156 if(tws
->obj_free_count
[set
] < tws
->number_of_lines
* tws
->number_of_elements
) {
2157 element
= &(tws
->table_ele
[set
][tws
->obj_free_count
[set
]]);
2158 tws
->obj_free_count
[set
]+=1;
2159 } else if(tws
->free_hash_ele
[set
] == NULL
) {
2162 element
= tws
->free_hash_ele
[set
];
2165 tws
->free_hash_ele
[set
] = tws
->free_hash_ele
[set
]->next
;
2167 element
->element
= 0;
2168 element
->next
= tws
->table
[set
][index
];
2169 tws
->table
[set
][index
] = element
;
2174 * Gets new hash element for addr hash from free pools
2175 * TWS must be locked
2184 tws_hash_ptr_t element
;
2186 if(tws
->addr_free_count
[set
]
2187 < tws
->number_of_lines
* tws
->number_of_elements
) {
2188 element
= &(tws
->alt_ele
[set
][tws
->addr_free_count
[set
]]);
2189 tws
->addr_free_count
[set
]+=1;
2190 } else if(tws
->free_hash_ele
[set
] == NULL
) {
2193 element
= tws
->free_hash_ele
[set
];
2196 tws
->free_hash_ele
[set
] = tws
->free_hash_ele
[set
]->next
;
2198 element
->element
= (tws_hash_ele_t
)TWS_ADDR_HASH
;
2199 element
->next
= tws
->table
[set
][index
];
2200 tws
->table
[set
][index
] = element
;