]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/zalloc.c
f1d703433fdd88f82af08ed53c710750b8ab40a2
[apple/xnu.git] / osfmk / kern / zalloc.c
1 /*
2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
14 * agreement.
15 *
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
18 * file.
19 *
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
27 *
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
29 */
30 /*
31 * @OSF_COPYRIGHT@
32 */
33 /*
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
36 * All Rights Reserved.
37 *
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
43 *
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
47 *
48 * Carnegie Mellon requests users of this software to return to
49 *
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
54 *
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
57 */
58 /*
59 */
60 /*
61 * File: kern/zalloc.c
62 * Author: Avadis Tevanian, Jr.
63 *
64 * Zone-based memory allocator. A zone is a collection of fixed size
65 * data blocks for which quick allocation/deallocation is possible.
66 */
67 #include <zone_debug.h>
68 #include <norma_vm.h>
69 #include <mach_kdb.h>
70
71 #include <mach/mach_types.h>
72 #include <mach/vm_param.h>
73 #include <mach/kern_return.h>
74 #include <mach/mach_host_server.h>
75 #include <mach/machine/vm_types.h>
76 #include <mach_debug/zone_info.h>
77
78 #include <kern/kern_types.h>
79 #include <kern/assert.h>
80 #include <kern/host.h>
81 #include <kern/macro_help.h>
82 #include <kern/sched.h>
83 #include <kern/lock.h>
84 #include <kern/sched_prim.h>
85 #include <kern/misc_protos.h>
86 #include <kern/thread_call.h>
87 #include <kern/zalloc.h>
88 #include <kern/kalloc.h>
89
90 #include <vm/pmap.h>
91 #include <vm/vm_map.h>
92 #include <vm/vm_kern.h>
93 #include <vm/vm_page.h>
94
95 #include <machine/machparam.h>
96
97 #if defined(__ppc__)
98 /* for fake zone stat routines */
99 #include <ppc/savearea.h>
100 #include <ppc/mappings.h>
101 #endif
102
103 #if MACH_ASSERT
104 /* Detect use of zone elt after freeing it by two methods:
105 * (1) Range-check the free-list "next" ptr for sanity.
106 * (2) Store the ptr in two different words, and compare them against
107 * each other when re-using the zone elt, to detect modifications;
108 */
109
110 #if defined(__alpha)
111
112 #define is_kernel_data_addr(a) \
113 (!(a) || (IS_SYS_VA(a) && !((a) & (sizeof(long)-1))))
114
115 #else /* !defined(__alpha) */
116
117 #define is_kernel_data_addr(a) \
118 (!(a) || ((a) >= VM_MIN_KERNEL_ADDRESS && !((a) & 0x3)))
119
120 #endif /* defined(__alpha) */
121
122 /* Should we set all words of the zone element to an illegal address
123 * when it is freed, to help catch usage after freeing? The down-side
124 * is that this obscures the identity of the freed element.
125 */
126 boolean_t zfree_clear = FALSE;
127
128 #define ADD_TO_ZONE(zone, element) \
129 MACRO_BEGIN \
130 if (zfree_clear) \
131 { unsigned int i; \
132 for (i=1; \
133 i < zone->elem_size/sizeof(vm_offset_t) - 1; \
134 i++) \
135 ((vm_offset_t *)(element))[i] = 0xdeadbeef; \
136 } \
137 ((vm_offset_t *)(element))[0] = (zone)->free_elements; \
138 (zone)->free_elements = (vm_offset_t) (element); \
139 (zone)->count--; \
140 MACRO_END
141
142 #define REMOVE_FROM_ZONE(zone, ret, type) \
143 MACRO_BEGIN \
144 (ret) = (type) (zone)->free_elements; \
145 if ((ret) != (type) 0) { \
146 if (!is_kernel_data_addr(((vm_offset_t *)(ret))[0])) { \
147 panic("A freed zone element has been modified.\n"); \
148 } \
149 (zone)->count++; \
150 (zone)->free_elements = *((vm_offset_t *)(ret)); \
151 } \
152 MACRO_END
153 #else /* MACH_ASSERT */
154
155 #define ADD_TO_ZONE(zone, element) \
156 MACRO_BEGIN \
157 *((vm_offset_t *)(element)) = (zone)->free_elements; \
158 (zone)->free_elements = (vm_offset_t) (element); \
159 (zone)->count--; \
160 MACRO_END
161
162 #define REMOVE_FROM_ZONE(zone, ret, type) \
163 MACRO_BEGIN \
164 (ret) = (type) (zone)->free_elements; \
165 if ((ret) != (type) 0) { \
166 (zone)->count++; \
167 (zone)->free_elements = *((vm_offset_t *)(ret)); \
168 } \
169 MACRO_END
170
171 #endif /* MACH_ASSERT */
172
173 #if ZONE_DEBUG
174 #define zone_debug_enabled(z) z->active_zones.next
175 #define ROUNDUP(x,y) ((((x)+(y)-1)/(y))*(y))
176 #define ZONE_DEBUG_OFFSET ROUNDUP(sizeof(queue_chain_t),16)
177 #endif /* ZONE_DEBUG */
178
179 /*
180 * Support for garbage collection of unused zone pages:
181 */
182
183 struct zone_page_table_entry {
184 struct zone_page_table_entry *link;
185 short alloc_count;
186 short collect_count;
187 };
188
189 /* Forwards */
190 void zone_page_init(
191 vm_offset_t addr,
192 vm_size_t size,
193 int value);
194
195 void zone_page_alloc(
196 vm_offset_t addr,
197 vm_size_t size);
198
199 void zone_page_free_element(
200 struct zone_page_table_entry **free_pages,
201 vm_offset_t addr,
202 vm_size_t size);
203
204 void zone_page_collect(
205 vm_offset_t addr,
206 vm_size_t size);
207
208 boolean_t zone_page_collectable(
209 vm_offset_t addr,
210 vm_size_t size);
211
212 void zone_page_keep(
213 vm_offset_t addr,
214 vm_size_t size);
215
216 void zalloc_async(
217 thread_call_param_t p0,
218 thread_call_param_t p1);
219
220
221 #if ZONE_DEBUG && MACH_KDB
222 int zone_count(
223 zone_t z,
224 int tail);
225 #endif /* ZONE_DEBUG && MACH_KDB */
226
227 vm_map_t zone_map = VM_MAP_NULL;
228
229 zone_t zone_zone = ZONE_NULL; /* the zone containing other zones */
230
231 /*
232 * The VM system gives us an initial chunk of memory.
233 * It has to be big enough to allocate the zone_zone
234 */
235
236 vm_offset_t zdata;
237 vm_size_t zdata_size;
238
239 #define lock_zone(zone) \
240 MACRO_BEGIN \
241 mutex_lock(&(zone)->lock); \
242 MACRO_END
243
244 #define unlock_zone(zone) \
245 MACRO_BEGIN \
246 mutex_unlock(&(zone)->lock); \
247 MACRO_END
248
249 #define zone_wakeup(zone) thread_wakeup((event_t)(zone))
250 #define zone_sleep(zone) \
251 thread_sleep_mutex((event_t)(zone), \
252 &(zone)->lock, \
253 THREAD_UNINT)
254
255 #define lock_zone_init(zone) \
256 MACRO_BEGIN \
257 mutex_init(&zone->lock, 0); \
258 MACRO_END
259
260 #define lock_try_zone(zone) mutex_try(&zone->lock)
261
262 kern_return_t zget_space(
263 vm_offset_t size,
264 vm_offset_t *result);
265
266 decl_simple_lock_data(,zget_space_lock)
267 vm_offset_t zalloc_next_space;
268 vm_offset_t zalloc_end_of_space;
269 vm_size_t zalloc_wasted_space;
270
271 /*
272 * Garbage collection map information
273 */
274 struct zone_page_table_entry * zone_page_table;
275 vm_offset_t zone_map_min_address;
276 vm_offset_t zone_map_max_address;
277 unsigned int zone_pages;
278
279 /*
280 * Exclude more than one concurrent garbage collection
281 */
282 decl_mutex_data(, zone_gc_lock)
283
284 #define from_zone_map(addr, size) \
285 ((vm_offset_t)(addr) >= zone_map_min_address && \
286 ((vm_offset_t)(addr) + size -1) < zone_map_max_address)
287
288 #define ZONE_PAGE_USED 0
289 #define ZONE_PAGE_UNUSED -1
290
291
292 /*
293 * Protects first_zone, last_zone, num_zones,
294 * and the next_zone field of zones.
295 */
296 decl_simple_lock_data(, all_zones_lock)
297 zone_t first_zone;
298 zone_t *last_zone;
299 unsigned int num_zones;
300
301 boolean_t zone_gc_allowed = TRUE;
302 boolean_t zone_gc_forced = FALSE;
303 unsigned zone_gc_last_tick = 0;
304 unsigned zone_gc_max_rate = 0; /* in ticks */
305
306
307 /*
308 * zinit initializes a new zone. The zone data structures themselves
309 * are stored in a zone, which is initially a static structure that
310 * is initialized by zone_init.
311 */
312 zone_t
313 zinit(
314 vm_size_t size, /* the size of an element */
315 vm_size_t max, /* maximum memory to use */
316 vm_size_t alloc, /* allocation size */
317 const char *name) /* a name for the zone */
318 {
319 zone_t z;
320
321 if (zone_zone == ZONE_NULL) {
322 if (zget_space(sizeof(struct zone), (vm_offset_t *)&z)
323 != KERN_SUCCESS)
324 return(ZONE_NULL);
325 } else
326 z = (zone_t) zalloc(zone_zone);
327 if (z == ZONE_NULL)
328 return(ZONE_NULL);
329
330 /*
331 * Round off all the parameters appropriately.
332 */
333 if (size < sizeof(z->free_elements))
334 size = sizeof(z->free_elements);
335 size = ((size-1) + sizeof(z->free_elements)) -
336 ((size-1) % sizeof(z->free_elements));
337 if (alloc == 0)
338 alloc = PAGE_SIZE;
339 alloc = round_page(alloc);
340 max = round_page(max);
341 /*
342 * we look for an allocation size with less than 1% waste
343 * up to 5 pages in size...
344 * otherwise, we look for an allocation size with least fragmentation
345 * in the range of 1 - 5 pages
346 * This size will be used unless
347 * the user suggestion is larger AND has less fragmentation
348 */
349 { vm_size_t best, waste; unsigned int i;
350 best = PAGE_SIZE;
351 waste = best % size;
352
353 for (i = 1; i <= 5; i++) {
354 vm_size_t tsize, twaste;
355
356 tsize = i * PAGE_SIZE;
357
358 if ((tsize % size) < (tsize / 100)) {
359 alloc = tsize;
360 goto use_this_allocation;
361 }
362 twaste = tsize % size;
363 if (twaste < waste)
364 best = tsize, waste = twaste;
365 }
366 if (alloc <= best || (alloc % size >= waste))
367 alloc = best;
368 }
369 use_this_allocation:
370 if (max && (max < alloc))
371 max = alloc;
372
373 z->free_elements = 0;
374 z->cur_size = 0;
375 z->max_size = max;
376 z->elem_size = size;
377 z->alloc_size = alloc;
378 z->zone_name = name;
379 z->count = 0;
380 z->doing_alloc = FALSE;
381 z->doing_gc = FALSE;
382 z->exhaustible = FALSE;
383 z->collectable = TRUE;
384 z->allows_foreign = FALSE;
385 z->expandable = TRUE;
386 z->waiting = FALSE;
387 z->async_pending = FALSE;
388
389 #if ZONE_DEBUG
390 z->active_zones.next = z->active_zones.prev = 0;
391 zone_debug_enable(z);
392 #endif /* ZONE_DEBUG */
393 lock_zone_init(z);
394
395 /*
396 * Add the zone to the all-zones list.
397 */
398
399 z->next_zone = ZONE_NULL;
400 thread_call_setup(&z->call_async_alloc, zalloc_async, z);
401 simple_lock(&all_zones_lock);
402 *last_zone = z;
403 last_zone = &z->next_zone;
404 num_zones++;
405 simple_unlock(&all_zones_lock);
406
407 return(z);
408 }
409
410 /*
411 * Cram the given memory into the specified zone.
412 */
413 void
414 zcram(
415 register zone_t zone,
416 void *newaddr,
417 vm_size_t size)
418 {
419 register vm_size_t elem_size;
420 vm_offset_t newmem = (vm_offset_t) newaddr;
421
422 /* Basic sanity checks */
423 assert(zone != ZONE_NULL && newmem != (vm_offset_t)0);
424 assert(!zone->collectable || zone->allows_foreign
425 || (from_zone_map(newmem, size)));
426
427 elem_size = zone->elem_size;
428
429 lock_zone(zone);
430 while (size >= elem_size) {
431 ADD_TO_ZONE(zone, newmem);
432 if (from_zone_map(newmem, elem_size))
433 zone_page_alloc(newmem, elem_size);
434 zone->count++; /* compensate for ADD_TO_ZONE */
435 size -= elem_size;
436 newmem += elem_size;
437 zone->cur_size += elem_size;
438 }
439 unlock_zone(zone);
440 }
441
442 /*
443 * Contiguous space allocator for non-paged zones. Allocates "size" amount
444 * of memory from zone_map.
445 */
446
447 kern_return_t
448 zget_space(
449 vm_offset_t size,
450 vm_offset_t *result)
451 {
452 vm_offset_t new_space = 0;
453 vm_size_t space_to_add = 0;
454
455 simple_lock(&zget_space_lock);
456 while ((zalloc_next_space + size) > zalloc_end_of_space) {
457 /*
458 * Add at least one page to allocation area.
459 */
460
461 space_to_add = round_page(size);
462
463 if (new_space == 0) {
464 kern_return_t retval;
465 /*
466 * Memory cannot be wired down while holding
467 * any locks that the pageout daemon might
468 * need to free up pages. [Making the zget_space
469 * lock a complex lock does not help in this
470 * regard.]
471 *
472 * Unlock and allocate memory. Because several
473 * threads might try to do this at once, don't
474 * use the memory before checking for available
475 * space again.
476 */
477
478 simple_unlock(&zget_space_lock);
479
480 retval = kernel_memory_allocate(zone_map, &new_space,
481 space_to_add, 0, KMA_KOBJECT|KMA_NOPAGEWAIT);
482 if (retval != KERN_SUCCESS)
483 return(retval);
484 zone_page_init(new_space, space_to_add,
485 ZONE_PAGE_USED);
486 simple_lock(&zget_space_lock);
487 continue;
488 }
489
490
491 /*
492 * Memory was allocated in a previous iteration.
493 *
494 * Check whether the new region is contiguous
495 * with the old one.
496 */
497
498 if (new_space != zalloc_end_of_space) {
499 /*
500 * Throw away the remainder of the
501 * old space, and start a new one.
502 */
503 zalloc_wasted_space +=
504 zalloc_end_of_space - zalloc_next_space;
505 zalloc_next_space = new_space;
506 }
507
508 zalloc_end_of_space = new_space + space_to_add;
509
510 new_space = 0;
511 }
512 *result = zalloc_next_space;
513 zalloc_next_space += size;
514 simple_unlock(&zget_space_lock);
515
516 if (new_space != 0)
517 kmem_free(zone_map, new_space, space_to_add);
518
519 return(KERN_SUCCESS);
520 }
521
522
523 /*
524 * Steal memory for the zone package. Called from
525 * vm_page_bootstrap().
526 */
527 void
528 zone_steal_memory(void)
529 {
530 zdata_size = round_page(128*sizeof(struct zone));
531 zdata = (vm_offset_t)((char *)pmap_steal_memory(zdata_size) - (char *)0);
532 }
533
534
535 /*
536 * Fill a zone with enough memory to contain at least nelem elements.
537 * Memory is obtained with kmem_alloc_wired from the kernel_map.
538 * Return the number of elements actually put into the zone, which may
539 * be more than the caller asked for since the memory allocation is
540 * rounded up to a full page.
541 */
542 int
543 zfill(
544 zone_t zone,
545 int nelem)
546 {
547 kern_return_t kr;
548 vm_size_t size;
549 vm_offset_t memory;
550 int nalloc;
551
552 assert(nelem > 0);
553 if (nelem <= 0)
554 return 0;
555 size = nelem * zone->elem_size;
556 size = round_page(size);
557 kr = kmem_alloc_wired(kernel_map, &memory, size);
558 if (kr != KERN_SUCCESS)
559 return 0;
560
561 zone_change(zone, Z_FOREIGN, TRUE);
562 zcram(zone, (void *)memory, size);
563 nalloc = size / zone->elem_size;
564 assert(nalloc >= nelem);
565
566 return nalloc;
567 }
568
569 /*
570 * Initialize the "zone of zones" which uses fixed memory allocated
571 * earlier in memory initialization. zone_bootstrap is called
572 * before zone_init.
573 */
574 void
575 zone_bootstrap(void)
576 {
577 vm_size_t zone_zone_size;
578 vm_offset_t zone_zone_space;
579
580 simple_lock_init(&all_zones_lock, 0);
581
582 first_zone = ZONE_NULL;
583 last_zone = &first_zone;
584 num_zones = 0;
585
586 simple_lock_init(&zget_space_lock, 0);
587 zalloc_next_space = zdata;
588 zalloc_end_of_space = zdata + zdata_size;
589 zalloc_wasted_space = 0;
590
591 /* assertion: nobody else called zinit before us */
592 assert(zone_zone == ZONE_NULL);
593 zone_zone = zinit(sizeof(struct zone), 128 * sizeof(struct zone),
594 sizeof(struct zone), "zones");
595 zone_change(zone_zone, Z_COLLECT, FALSE);
596 zone_zone_size = zalloc_end_of_space - zalloc_next_space;
597 zget_space(zone_zone_size, &zone_zone_space);
598 zcram(zone_zone, (void *)zone_zone_space, zone_zone_size);
599 }
600
601 void
602 zone_init(
603 vm_size_t max_zonemap_size)
604 {
605 kern_return_t retval;
606 vm_offset_t zone_min;
607 vm_offset_t zone_max;
608 vm_size_t zone_table_size;
609
610 retval = kmem_suballoc(kernel_map, &zone_min, max_zonemap_size,
611 FALSE, VM_FLAGS_ANYWHERE, &zone_map);
612
613 if (retval != KERN_SUCCESS)
614 panic("zone_init: kmem_suballoc failed");
615 zone_max = zone_min + round_page(max_zonemap_size);
616 /*
617 * Setup garbage collection information:
618 */
619 zone_table_size = atop_32(zone_max - zone_min) *
620 sizeof(struct zone_page_table_entry);
621 if (kmem_alloc_wired(zone_map, (vm_offset_t *) &zone_page_table,
622 zone_table_size) != KERN_SUCCESS)
623 panic("zone_init");
624 zone_min = (vm_offset_t)zone_page_table + round_page(zone_table_size);
625 zone_pages = atop_32(zone_max - zone_min);
626 zone_map_min_address = zone_min;
627 zone_map_max_address = zone_max;
628 mutex_init(&zone_gc_lock, 0);
629 zone_page_init(zone_min, zone_max - zone_min, ZONE_PAGE_UNUSED);
630 }
631
632
633 /*
634 * zalloc returns an element from the specified zone.
635 */
636 void *
637 zalloc_canblock(
638 register zone_t zone,
639 boolean_t canblock)
640 {
641 vm_offset_t addr;
642 kern_return_t retval;
643
644 assert(zone != ZONE_NULL);
645
646 lock_zone(zone);
647
648 REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
649
650 while ((addr == 0) && canblock && (zone->doing_gc)) {
651 zone->waiting = TRUE;
652 zone_sleep(zone);
653 REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
654 }
655
656 while ((addr == 0) && canblock) {
657 /*
658 * If nothing was there, try to get more
659 */
660 if (zone->doing_alloc) {
661 /*
662 * Someone is allocating memory for this zone.
663 * Wait for it to show up, then try again.
664 */
665 zone->waiting = TRUE;
666 zone_sleep(zone);
667 }
668 else {
669 if ((zone->cur_size + zone->elem_size) >
670 zone->max_size) {
671 if (zone->exhaustible)
672 break;
673 if (zone->expandable) {
674 /*
675 * We're willing to overflow certain
676 * zones, but not without complaining.
677 *
678 * This is best used in conjunction
679 * with the collectable flag. What we
680 * want is an assurance we can get the
681 * memory back, assuming there's no
682 * leak.
683 */
684 zone->max_size += (zone->max_size >> 1);
685 } else {
686 unlock_zone(zone);
687
688 panic("zalloc: zone \"%s\" empty.", zone->zone_name);
689 }
690 }
691 zone->doing_alloc = TRUE;
692 unlock_zone(zone);
693
694 if (zone->collectable) {
695 vm_offset_t space;
696 vm_size_t alloc_size;
697 boolean_t retry = FALSE;
698
699 for (;;) {
700
701 if (vm_pool_low() || retry == TRUE)
702 alloc_size =
703 round_page(zone->elem_size);
704 else
705 alloc_size = zone->alloc_size;
706
707 retval = kernel_memory_allocate(zone_map,
708 &space, alloc_size, 0,
709 KMA_KOBJECT|KMA_NOPAGEWAIT);
710 if (retval == KERN_SUCCESS) {
711 zone_page_init(space, alloc_size,
712 ZONE_PAGE_USED);
713 zcram(zone, (void *)space, alloc_size);
714
715 break;
716 } else if (retval != KERN_RESOURCE_SHORTAGE) {
717 /* would like to cause a zone_gc() */
718 if (retry == TRUE)
719 panic("zalloc: \"%s\" (%d elements) retry fail %d", zone->zone_name, zone->count, retval);
720 retry = TRUE;
721 } else {
722 break;
723 }
724 }
725 lock_zone(zone);
726 zone->doing_alloc = FALSE;
727 if (zone->waiting) {
728 zone->waiting = FALSE;
729 zone_wakeup(zone);
730 }
731 REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
732 if (addr == 0 &&
733 retval == KERN_RESOURCE_SHORTAGE) {
734 unlock_zone(zone);
735
736 VM_PAGE_WAIT();
737 lock_zone(zone);
738 }
739 } else {
740 vm_offset_t space;
741 retval = zget_space(zone->elem_size, &space);
742
743 lock_zone(zone);
744 zone->doing_alloc = FALSE;
745 if (zone->waiting) {
746 zone->waiting = FALSE;
747 thread_wakeup((event_t)zone);
748 }
749 if (retval == KERN_SUCCESS) {
750 zone->count++;
751 zone->cur_size += zone->elem_size;
752 #if ZONE_DEBUG
753 if (zone_debug_enabled(zone)) {
754 enqueue_tail(&zone->active_zones, (queue_entry_t)space);
755 }
756 #endif
757 unlock_zone(zone);
758 zone_page_alloc(space, zone->elem_size);
759 #if ZONE_DEBUG
760 if (zone_debug_enabled(zone))
761 space += ZONE_DEBUG_OFFSET;
762 #endif
763 return((void *)space);
764 }
765 if (retval == KERN_RESOURCE_SHORTAGE) {
766 unlock_zone(zone);
767
768 VM_PAGE_WAIT();
769 lock_zone(zone);
770 } else {
771 panic("zalloc: \"%s\" (%d elements) zget_space returned %d", zone->zone_name, zone->count, retval);
772 }
773 }
774 }
775 if (addr == 0)
776 REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
777 }
778
779 if ((addr == 0) && !canblock && (zone->async_pending == FALSE) && (!vm_pool_low())) {
780 zone->async_pending = TRUE;
781 unlock_zone(zone);
782 thread_call_enter(&zone->call_async_alloc);
783 lock_zone(zone);
784 REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
785 }
786
787 #if ZONE_DEBUG
788 if (addr && zone_debug_enabled(zone)) {
789 enqueue_tail(&zone->active_zones, (queue_entry_t)addr);
790 addr += ZONE_DEBUG_OFFSET;
791 }
792 #endif
793
794 unlock_zone(zone);
795
796 return((void *)addr);
797 }
798
799
800 void *
801 zalloc(
802 register zone_t zone)
803 {
804 return( zalloc_canblock(zone, TRUE) );
805 }
806
807 void *
808 zalloc_noblock(
809 register zone_t zone)
810 {
811 return( zalloc_canblock(zone, FALSE) );
812 }
813
814 void
815 zalloc_async(
816 thread_call_param_t p0,
817 __unused thread_call_param_t p1)
818 {
819 void *elt;
820
821 elt = zalloc_canblock((zone_t)p0, TRUE);
822 zfree((zone_t)p0, elt);
823 lock_zone(((zone_t)p0));
824 ((zone_t)p0)->async_pending = FALSE;
825 unlock_zone(((zone_t)p0));
826 }
827
828
829 /*
830 * zget returns an element from the specified zone
831 * and immediately returns nothing if there is nothing there.
832 *
833 * This form should be used when you can not block (like when
834 * processing an interrupt).
835 */
836 void *
837 zget(
838 register zone_t zone)
839 {
840 register vm_offset_t addr;
841
842 assert( zone != ZONE_NULL );
843
844 if (!lock_try_zone(zone))
845 return NULL;
846
847 REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
848 #if ZONE_DEBUG
849 if (addr && zone_debug_enabled(zone)) {
850 enqueue_tail(&zone->active_zones, (queue_entry_t)addr);
851 addr += ZONE_DEBUG_OFFSET;
852 }
853 #endif /* ZONE_DEBUG */
854 unlock_zone(zone);
855
856 return((void *) addr);
857 }
858
859 /* Keep this FALSE by default. Large memory machine run orders of magnitude
860 slower in debug mode when true. Use debugger to enable if needed */
861 /* static */ boolean_t zone_check = FALSE;
862
863 static zone_t zone_last_bogus_zone = ZONE_NULL;
864 static vm_offset_t zone_last_bogus_elem = 0;
865
866 void
867 zfree(
868 register zone_t zone,
869 void *addr)
870 {
871 vm_offset_t elem = (vm_offset_t) addr;
872
873 #if MACH_ASSERT
874 /* Basic sanity checks */
875 if (zone == ZONE_NULL || elem == (vm_offset_t)0)
876 panic("zfree: NULL");
877 /* zone_gc assumes zones are never freed */
878 if (zone == zone_zone)
879 panic("zfree: freeing to zone_zone breaks zone_gc!");
880 #endif
881
882 if (zone->collectable && !zone->allows_foreign &&
883 !from_zone_map(elem, zone->elem_size)) {
884 #if MACH_ASSERT
885 panic("zfree: non-allocated memory in collectable zone!");
886 #endif
887 zone_last_bogus_zone = zone;
888 zone_last_bogus_elem = elem;
889 return;
890 }
891
892 lock_zone(zone);
893 #if ZONE_DEBUG
894 if (zone_debug_enabled(zone)) {
895 queue_t tmp_elem;
896
897 elem -= ZONE_DEBUG_OFFSET;
898 if (zone_check) {
899 /* check the zone's consistency */
900
901 for (tmp_elem = queue_first(&zone->active_zones);
902 !queue_end(tmp_elem, &zone->active_zones);
903 tmp_elem = queue_next(tmp_elem))
904 if (elem == (vm_offset_t)tmp_elem)
905 break;
906 if (elem != (vm_offset_t)tmp_elem)
907 panic("zfree()ing element from wrong zone");
908 }
909 remqueue(&zone->active_zones, (queue_t) elem);
910 }
911 #endif /* ZONE_DEBUG */
912 if (zone_check) {
913 vm_offset_t this;
914
915 /* check the zone's consistency */
916
917 for (this = zone->free_elements;
918 this != 0;
919 this = * (vm_offset_t *) this)
920 if (!pmap_kernel_va(this) || this == elem)
921 panic("zfree");
922 }
923 ADD_TO_ZONE(zone, elem);
924
925 /*
926 * If elements have one or more pages, and memory is low,
927 * request to run the garbage collection in the zone the next
928 * time the pageout thread runs.
929 */
930 if (zone->elem_size >= PAGE_SIZE &&
931 vm_pool_low()){
932 zone_gc_forced = TRUE;
933 }
934 unlock_zone(zone);
935 }
936
937
938 /* Change a zone's flags.
939 * This routine must be called immediately after zinit.
940 */
941 void
942 zone_change(
943 zone_t zone,
944 unsigned int item,
945 boolean_t value)
946 {
947 assert( zone != ZONE_NULL );
948 assert( value == TRUE || value == FALSE );
949
950 switch(item){
951 case Z_EXHAUST:
952 zone->exhaustible = value;
953 break;
954 case Z_COLLECT:
955 zone->collectable = value;
956 break;
957 case Z_EXPAND:
958 zone->expandable = value;
959 break;
960 case Z_FOREIGN:
961 zone->allows_foreign = value;
962 break;
963 #if MACH_ASSERT
964 default:
965 panic("Zone_change: Wrong Item Type!");
966 /* break; */
967 #endif
968 }
969 lock_zone_init(zone);
970 }
971
972 /*
973 * Return the expected number of free elements in the zone.
974 * This calculation will be incorrect if items are zfree'd that
975 * were never zalloc'd/zget'd. The correct way to stuff memory
976 * into a zone is by zcram.
977 */
978
979 integer_t
980 zone_free_count(zone_t zone)
981 {
982 integer_t free_count;
983
984 lock_zone(zone);
985 free_count = zone->cur_size/zone->elem_size - zone->count;
986 unlock_zone(zone);
987
988 assert(free_count >= 0);
989
990 return(free_count);
991 }
992
993 /*
994 * zprealloc preallocates wired memory, exanding the specified
995 * zone to the specified size
996 */
997 void
998 zprealloc(
999 zone_t zone,
1000 vm_size_t size)
1001 {
1002 vm_offset_t addr;
1003
1004 if (size != 0) {
1005 if (kmem_alloc_wired(zone_map, &addr, size) != KERN_SUCCESS)
1006 panic("zprealloc");
1007 zone_page_init(addr, size, ZONE_PAGE_USED);
1008 zcram(zone, (void *)addr, size);
1009 }
1010 }
1011
1012 /*
1013 * Zone garbage collection subroutines
1014 */
1015
1016 boolean_t
1017 zone_page_collectable(
1018 vm_offset_t addr,
1019 vm_size_t size)
1020 {
1021 struct zone_page_table_entry *zp;
1022 natural_t i, j;
1023
1024 #if MACH_ASSERT
1025 if (!from_zone_map(addr, size))
1026 panic("zone_page_collectable");
1027 #endif
1028
1029 i = atop_32(addr-zone_map_min_address);
1030 j = atop_32((addr+size-1) - zone_map_min_address);
1031
1032 for (zp = zone_page_table + i; i <= j; zp++, i++)
1033 if (zp->collect_count == zp->alloc_count)
1034 return (TRUE);
1035
1036 return (FALSE);
1037 }
1038
1039 void
1040 zone_page_keep(
1041 vm_offset_t addr,
1042 vm_size_t size)
1043 {
1044 struct zone_page_table_entry *zp;
1045 natural_t i, j;
1046
1047 #if MACH_ASSERT
1048 if (!from_zone_map(addr, size))
1049 panic("zone_page_keep");
1050 #endif
1051
1052 i = atop_32(addr-zone_map_min_address);
1053 j = atop_32((addr+size-1) - zone_map_min_address);
1054
1055 for (zp = zone_page_table + i; i <= j; zp++, i++)
1056 zp->collect_count = 0;
1057 }
1058
1059 void
1060 zone_page_collect(
1061 vm_offset_t addr,
1062 vm_size_t size)
1063 {
1064 struct zone_page_table_entry *zp;
1065 natural_t i, j;
1066
1067 #if MACH_ASSERT
1068 if (!from_zone_map(addr, size))
1069 panic("zone_page_collect");
1070 #endif
1071
1072 i = atop_32(addr-zone_map_min_address);
1073 j = atop_32((addr+size-1) - zone_map_min_address);
1074
1075 for (zp = zone_page_table + i; i <= j; zp++, i++)
1076 ++zp->collect_count;
1077 }
1078
1079 void
1080 zone_page_init(
1081 vm_offset_t addr,
1082 vm_size_t size,
1083 int value)
1084 {
1085 struct zone_page_table_entry *zp;
1086 natural_t i, j;
1087
1088 #if MACH_ASSERT
1089 if (!from_zone_map(addr, size))
1090 panic("zone_page_init");
1091 #endif
1092
1093 i = atop_32(addr-zone_map_min_address);
1094 j = atop_32((addr+size-1) - zone_map_min_address);
1095
1096 for (zp = zone_page_table + i; i <= j; zp++, i++) {
1097 zp->alloc_count = value;
1098 zp->collect_count = 0;
1099 }
1100 }
1101
1102 void
1103 zone_page_alloc(
1104 vm_offset_t addr,
1105 vm_size_t size)
1106 {
1107 struct zone_page_table_entry *zp;
1108 natural_t i, j;
1109
1110 #if MACH_ASSERT
1111 if (!from_zone_map(addr, size))
1112 panic("zone_page_alloc");
1113 #endif
1114
1115 i = atop_32(addr-zone_map_min_address);
1116 j = atop_32((addr+size-1) - zone_map_min_address);
1117
1118 for (zp = zone_page_table + i; i <= j; zp++, i++) {
1119 /*
1120 * Set alloc_count to (ZONE_PAGE_USED + 1) if
1121 * it was previously set to ZONE_PAGE_UNUSED.
1122 */
1123 if (zp->alloc_count == ZONE_PAGE_UNUSED)
1124 zp->alloc_count = 1;
1125 else
1126 ++zp->alloc_count;
1127 }
1128 }
1129
1130 void
1131 zone_page_free_element(
1132 struct zone_page_table_entry **free_pages,
1133 vm_offset_t addr,
1134 vm_size_t size)
1135 {
1136 struct zone_page_table_entry *zp;
1137 natural_t i, j;
1138
1139 #if MACH_ASSERT
1140 if (!from_zone_map(addr, size))
1141 panic("zone_page_free_element");
1142 #endif
1143
1144 i = atop_32(addr-zone_map_min_address);
1145 j = atop_32((addr+size-1) - zone_map_min_address);
1146
1147 for (zp = zone_page_table + i; i <= j; zp++, i++) {
1148 if (zp->collect_count > 0)
1149 --zp->collect_count;
1150 if (--zp->alloc_count == 0) {
1151 zp->alloc_count = ZONE_PAGE_UNUSED;
1152 zp->collect_count = 0;
1153
1154 zp->link = *free_pages;
1155 *free_pages = zp;
1156 }
1157 }
1158 }
1159
1160
1161 /* This is used for walking through a zone's free element list.
1162 */
1163 struct zone_free_element {
1164 struct zone_free_element * next;
1165 };
1166
1167 struct {
1168 uint32_t pgs_freed;
1169
1170 uint32_t elems_collected,
1171 elems_freed,
1172 elems_kept;
1173 } zgc_stats;
1174
1175 /* Zone garbage collection
1176 *
1177 * zone_gc will walk through all the free elements in all the
1178 * zones that are marked collectable looking for reclaimable
1179 * pages. zone_gc is called by consider_zone_gc when the system
1180 * begins to run out of memory.
1181 */
1182 void
1183 zone_gc(void)
1184 {
1185 unsigned int max_zones;
1186 zone_t z;
1187 unsigned int i;
1188 struct zone_page_table_entry *zp, *zone_free_pages;
1189
1190 mutex_lock(&zone_gc_lock);
1191
1192 simple_lock(&all_zones_lock);
1193 max_zones = num_zones;
1194 z = first_zone;
1195 simple_unlock(&all_zones_lock);
1196
1197 #if MACH_ASSERT
1198 for (i = 0; i < zone_pages; i++)
1199 assert(zone_page_table[i].collect_count == 0);
1200 #endif /* MACH_ASSERT */
1201
1202 zone_free_pages = NULL;
1203
1204 for (i = 0; i < max_zones; i++, z = z->next_zone) {
1205 unsigned int n, m;
1206 vm_size_t elt_size, size_freed;
1207 struct zone_free_element *elt, *base_elt, *base_prev, *prev, *scan, *keep, *tail;
1208
1209 assert(z != ZONE_NULL);
1210
1211 if (!z->collectable)
1212 continue;
1213
1214 lock_zone(z);
1215
1216 elt_size = z->elem_size;
1217
1218 /*
1219 * Do a quick feasability check before we scan the zone:
1220 * skip unless there is likelihood of getting pages back
1221 * (i.e we need a whole allocation block's worth of free
1222 * elements before we can garbage collect) and
1223 * the zone has more than 10 percent of it's elements free
1224 */
1225 if (((z->cur_size - z->count * elt_size) <= (2 * z->alloc_size)) ||
1226 ((z->cur_size - z->count * elt_size) <= (z->cur_size / 10))) {
1227 unlock_zone(z);
1228 continue;
1229 }
1230
1231 z->doing_gc = TRUE;
1232
1233 /*
1234 * Snatch all of the free elements away from the zone.
1235 */
1236
1237 scan = (void *)z->free_elements;
1238 (void *)z->free_elements = NULL;
1239
1240 unlock_zone(z);
1241
1242 /*
1243 * Pass 1:
1244 *
1245 * Determine which elements we can attempt to collect
1246 * and count them up in the page table. Foreign elements
1247 * are returned to the zone.
1248 */
1249
1250 prev = (void *)&scan;
1251 elt = scan;
1252 n = 0; tail = keep = NULL;
1253 while (elt != NULL) {
1254 if (from_zone_map(elt, elt_size)) {
1255 zone_page_collect((vm_offset_t)elt, elt_size);
1256
1257 prev = elt;
1258 elt = elt->next;
1259
1260 ++zgc_stats.elems_collected;
1261 }
1262 else {
1263 if (keep == NULL)
1264 keep = tail = elt;
1265 else
1266 tail = tail->next = elt;
1267
1268 elt = prev->next = elt->next;
1269 tail->next = NULL;
1270 }
1271
1272 /*
1273 * Dribble back the elements we are keeping.
1274 */
1275
1276 if (++n >= 50) {
1277 if (z->waiting == TRUE) {
1278 lock_zone(z);
1279
1280 if (keep != NULL) {
1281 tail->next = (void *)z->free_elements;
1282 (void *)z->free_elements = keep;
1283 tail = keep = NULL;
1284 } else {
1285 m =0;
1286 base_elt = elt;
1287 base_prev = prev;
1288 while ((elt != NULL) && (++m < 50)) {
1289 prev = elt;
1290 elt = elt->next;
1291 }
1292 if (m !=0 ) {
1293 prev->next = (void *)z->free_elements;
1294 (void *)z->free_elements = (void *)base_elt;
1295 base_prev->next = elt;
1296 prev = base_prev;
1297 }
1298 }
1299
1300 if (z->waiting) {
1301 z->waiting = FALSE;
1302 zone_wakeup(z);
1303 }
1304
1305 unlock_zone(z);
1306 }
1307 n =0;
1308 }
1309 }
1310
1311 /*
1312 * Return any remaining elements.
1313 */
1314
1315 if (keep != NULL) {
1316 lock_zone(z);
1317
1318 tail->next = (void *)z->free_elements;
1319 (void *)z->free_elements = keep;
1320
1321 unlock_zone(z);
1322 }
1323
1324 /*
1325 * Pass 2:
1326 *
1327 * Determine which pages we can reclaim and
1328 * free those elements.
1329 */
1330
1331 size_freed = 0;
1332 prev = (void *)&scan;
1333 elt = scan;
1334 n = 0; tail = keep = NULL;
1335 while (elt != NULL) {
1336 if (zone_page_collectable((vm_offset_t)elt, elt_size)) {
1337 size_freed += elt_size;
1338 zone_page_free_element(&zone_free_pages,
1339 (vm_offset_t)elt, elt_size);
1340
1341 elt = prev->next = elt->next;
1342
1343 ++zgc_stats.elems_freed;
1344 }
1345 else {
1346 zone_page_keep((vm_offset_t)elt, elt_size);
1347
1348 if (keep == NULL)
1349 keep = tail = elt;
1350 else
1351 tail = tail->next = elt;
1352
1353 elt = prev->next = elt->next;
1354 tail->next = NULL;
1355
1356 ++zgc_stats.elems_kept;
1357 }
1358
1359 /*
1360 * Dribble back the elements we are keeping,
1361 * and update the zone size info.
1362 */
1363
1364 if (++n >= 50) {
1365 lock_zone(z);
1366
1367 z->cur_size -= size_freed;
1368 size_freed = 0;
1369
1370 if (keep != NULL) {
1371 tail->next = (void *)z->free_elements;
1372 (void *)z->free_elements = keep;
1373 }
1374
1375 if (z->waiting) {
1376 z->waiting = FALSE;
1377 zone_wakeup(z);
1378 }
1379
1380 unlock_zone(z);
1381
1382 n = 0; tail = keep = NULL;
1383 }
1384 }
1385
1386 /*
1387 * Return any remaining elements, and update
1388 * the zone size info.
1389 */
1390
1391 lock_zone(z);
1392
1393 if (size_freed > 0 || keep != NULL) {
1394
1395 z->cur_size -= size_freed;
1396
1397 if (keep != NULL) {
1398 tail->next = (void *)z->free_elements;
1399 (void *)z->free_elements = keep;
1400 }
1401
1402 }
1403
1404 z->doing_gc = FALSE;
1405 if (z->waiting) {
1406 z->waiting = FALSE;
1407 zone_wakeup(z);
1408 }
1409 unlock_zone(z);
1410 }
1411
1412 /*
1413 * Reclaim the pages we are freeing.
1414 */
1415
1416 while ((zp = zone_free_pages) != NULL) {
1417 zone_free_pages = zp->link;
1418 kmem_free(zone_map, zone_map_min_address + PAGE_SIZE *
1419 (zp - zone_page_table), PAGE_SIZE);
1420 ++zgc_stats.pgs_freed;
1421 }
1422
1423 mutex_unlock(&zone_gc_lock);
1424 }
1425
1426 /*
1427 * consider_zone_gc:
1428 *
1429 * Called by the pageout daemon when the system needs more free pages.
1430 */
1431
1432 void
1433 consider_zone_gc(void)
1434 {
1435 /*
1436 * By default, don't attempt zone GC more frequently
1437 * than once / 1 minutes.
1438 */
1439
1440 if (zone_gc_max_rate == 0)
1441 zone_gc_max_rate = (60 << SCHED_TICK_SHIFT) + 1;
1442
1443 if (zone_gc_allowed &&
1444 ((sched_tick > (zone_gc_last_tick + zone_gc_max_rate)) ||
1445 zone_gc_forced)) {
1446 zone_gc_forced = FALSE;
1447 zone_gc_last_tick = sched_tick;
1448 zone_gc();
1449 }
1450 }
1451
1452
1453 kern_return_t
1454 host_zone_info(
1455 host_t host,
1456 zone_name_array_t *namesp,
1457 mach_msg_type_number_t *namesCntp,
1458 zone_info_array_t *infop,
1459 mach_msg_type_number_t *infoCntp)
1460 {
1461 zone_name_t *names;
1462 vm_offset_t names_addr;
1463 vm_size_t names_size;
1464 zone_info_t *info;
1465 vm_offset_t info_addr;
1466 vm_size_t info_size;
1467 unsigned int max_zones, i;
1468 zone_t z;
1469 zone_name_t *zn;
1470 zone_info_t *zi;
1471 kern_return_t kr;
1472
1473 if (host == HOST_NULL)
1474 return KERN_INVALID_HOST;
1475
1476 /*
1477 * We assume that zones aren't freed once allocated.
1478 * We won't pick up any zones that are allocated later.
1479 */
1480
1481 simple_lock(&all_zones_lock);
1482 #ifdef ppc
1483 max_zones = num_zones + 4;
1484 #else
1485 max_zones = num_zones + 2;
1486 #endif
1487 z = first_zone;
1488 simple_unlock(&all_zones_lock);
1489
1490 if (max_zones <= *namesCntp) {
1491 /* use in-line memory */
1492 names_size = *namesCntp * sizeof *names;
1493 names = *namesp;
1494 } else {
1495 names_size = round_page(max_zones * sizeof *names);
1496 kr = kmem_alloc_pageable(ipc_kernel_map,
1497 &names_addr, names_size);
1498 if (kr != KERN_SUCCESS)
1499 return kr;
1500 names = (zone_name_t *) names_addr;
1501 }
1502
1503 if (max_zones <= *infoCntp) {
1504 /* use in-line memory */
1505 info_size = *infoCntp * sizeof *info;
1506 info = *infop;
1507 } else {
1508 info_size = round_page(max_zones * sizeof *info);
1509 kr = kmem_alloc_pageable(ipc_kernel_map,
1510 &info_addr, info_size);
1511 if (kr != KERN_SUCCESS) {
1512 if (names != *namesp)
1513 kmem_free(ipc_kernel_map,
1514 names_addr, names_size);
1515 return kr;
1516 }
1517
1518 info = (zone_info_t *) info_addr;
1519 }
1520 zn = &names[0];
1521 zi = &info[0];
1522
1523 for (i = 0; i < num_zones; i++) {
1524 struct zone zcopy;
1525
1526 assert(z != ZONE_NULL);
1527
1528 lock_zone(z);
1529 zcopy = *z;
1530 unlock_zone(z);
1531
1532 simple_lock(&all_zones_lock);
1533 z = z->next_zone;
1534 simple_unlock(&all_zones_lock);
1535
1536 /* assuming here the name data is static */
1537 (void) strncpy(zn->zn_name, zcopy.zone_name,
1538 sizeof zn->zn_name);
1539
1540 zi->zi_count = zcopy.count;
1541 zi->zi_cur_size = zcopy.cur_size;
1542 zi->zi_max_size = zcopy.max_size;
1543 zi->zi_elem_size = zcopy.elem_size;
1544 zi->zi_alloc_size = zcopy.alloc_size;
1545 zi->zi_exhaustible = zcopy.exhaustible;
1546 zi->zi_collectable = zcopy.collectable;
1547
1548 zn++;
1549 zi++;
1550 }
1551 strcpy(zn->zn_name, "kernel_stacks");
1552 stack_fake_zone_info(&zi->zi_count, &zi->zi_cur_size, &zi->zi_max_size, &zi->zi_elem_size,
1553 &zi->zi_alloc_size, &zi->zi_collectable, &zi->zi_exhaustible);
1554 zn++;
1555 zi++;
1556 #ifdef ppc
1557 strcpy(zn->zn_name, "save_areas");
1558 save_fake_zone_info(&zi->zi_count, &zi->zi_cur_size, &zi->zi_max_size, &zi->zi_elem_size,
1559 &zi->zi_alloc_size, &zi->zi_collectable, &zi->zi_exhaustible);
1560 zn++;
1561 zi++;
1562
1563 strcpy(zn->zn_name, "pmap_mappings");
1564 mapping_fake_zone_info(&zi->zi_count, &zi->zi_cur_size, &zi->zi_max_size, &zi->zi_elem_size,
1565 &zi->zi_alloc_size, &zi->zi_collectable, &zi->zi_exhaustible);
1566 zn++;
1567 zi++;
1568 #endif
1569 strcpy(zn->zn_name, "kalloc.large");
1570 kalloc_fake_zone_info(&zi->zi_count, &zi->zi_cur_size, &zi->zi_max_size, &zi->zi_elem_size,
1571 &zi->zi_alloc_size, &zi->zi_collectable, &zi->zi_exhaustible);
1572
1573 if (names != *namesp) {
1574 vm_size_t used;
1575 vm_map_copy_t copy;
1576
1577 used = max_zones * sizeof *names;
1578
1579 if (used != names_size)
1580 bzero((char *) (names_addr + used), names_size - used);
1581
1582 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)names_addr,
1583 (vm_map_size_t)names_size, TRUE, &copy);
1584 assert(kr == KERN_SUCCESS);
1585
1586 *namesp = (zone_name_t *) copy;
1587 }
1588 *namesCntp = max_zones;
1589
1590 if (info != *infop) {
1591 vm_size_t used;
1592 vm_map_copy_t copy;
1593
1594 used = max_zones * sizeof *info;
1595
1596 if (used != info_size)
1597 bzero((char *) (info_addr + used), info_size - used);
1598
1599 kr = vm_map_copyin(ipc_kernel_map, (vm_map_address_t)info_addr,
1600 (vm_map_size_t)info_size, TRUE, &copy);
1601 assert(kr == KERN_SUCCESS);
1602
1603 *infop = (zone_info_t *) copy;
1604 }
1605 *infoCntp = max_zones;
1606
1607 return KERN_SUCCESS;
1608 }
1609
1610 #if MACH_KDB
1611 #include <ddb/db_command.h>
1612 #include <ddb/db_output.h>
1613 #include <kern/kern_print.h>
1614
1615 const char *zone_labels =
1616 "ENTRY COUNT TOT_SZ MAX_SZ ELT_SZ ALLOC_SZ NAME";
1617
1618 /* Forwards */
1619 void db_print_zone(
1620 zone_t addr);
1621
1622 #if ZONE_DEBUG
1623 void db_zone_check_active(
1624 zone_t zone);
1625 void db_zone_print_active(
1626 zone_t zone);
1627 #endif /* ZONE_DEBUG */
1628 void db_zone_print_free(
1629 zone_t zone);
1630 void
1631 db_print_zone(
1632 zone_t addr)
1633 {
1634 struct zone zcopy;
1635
1636 zcopy = *addr;
1637
1638 db_printf("%8x %8x %8x %8x %6x %8x %s ",
1639 addr, zcopy.count, zcopy.cur_size,
1640 zcopy.max_size, zcopy.elem_size,
1641 zcopy.alloc_size, zcopy.zone_name);
1642 if (zcopy.exhaustible)
1643 db_printf("H");
1644 if (zcopy.collectable)
1645 db_printf("C");
1646 if (zcopy.expandable)
1647 db_printf("X");
1648 db_printf("\n");
1649 }
1650
1651 /*ARGSUSED*/
1652 void
1653 db_show_one_zone(
1654 db_expr_t addr,
1655 int have_addr,
1656 __unused db_expr_t count,
1657 __unused char * modif)
1658 {
1659 struct zone *z = (zone_t)((char *)0 + addr);
1660
1661 if (z == ZONE_NULL || !have_addr){
1662 db_error("No Zone\n");
1663 /*NOTREACHED*/
1664 }
1665
1666 db_printf("%s\n", zone_labels);
1667 db_print_zone(z);
1668 }
1669
1670 /*ARGSUSED*/
1671 void
1672 db_show_all_zones(
1673 __unused db_expr_t addr,
1674 int have_addr,
1675 db_expr_t count,
1676 __unused char * modif)
1677 {
1678 zone_t z;
1679 unsigned total = 0;
1680
1681 /*
1682 * Don't risk hanging by unconditionally locking,
1683 * risk of incoherent data is small (zones aren't freed).
1684 */
1685 have_addr = simple_lock_try(&all_zones_lock);
1686 count = num_zones;
1687 z = first_zone;
1688 if (have_addr) {
1689 simple_unlock(&all_zones_lock);
1690 }
1691
1692 db_printf("%s\n", zone_labels);
1693 for ( ; count > 0; count--) {
1694 if (!z) {
1695 db_error("Mangled Zone List\n");
1696 /*NOTREACHED*/
1697 }
1698 db_print_zone(z);
1699 total += z->cur_size,
1700
1701 have_addr = simple_lock_try(&all_zones_lock);
1702 z = z->next_zone;
1703 if (have_addr) {
1704 simple_unlock(&all_zones_lock);
1705 }
1706 }
1707 db_printf("\nTotal %8x", total);
1708 db_printf("\n\nzone_gc() has reclaimed %d pages\n", zgc_stats.pgs_freed);
1709 }
1710
1711 #if ZONE_DEBUG
1712 void
1713 db_zone_check_active(
1714 zone_t zone)
1715 {
1716 int count = 0;
1717 queue_t tmp_elem;
1718
1719 if (!zone_debug_enabled(zone) || !zone_check)
1720 return;
1721 tmp_elem = queue_first(&zone->active_zones);
1722 while (count < zone->count) {
1723 count++;
1724 if (tmp_elem == 0) {
1725 printf("unexpected zero element, zone=0x%x, count=%d\n",
1726 zone, count);
1727 assert(FALSE);
1728 break;
1729 }
1730 if (queue_end(tmp_elem, &zone->active_zones)) {
1731 printf("unexpected queue_end, zone=0x%x, count=%d\n",
1732 zone, count);
1733 assert(FALSE);
1734 break;
1735 }
1736 tmp_elem = queue_next(tmp_elem);
1737 }
1738 if (!queue_end(tmp_elem, &zone->active_zones)) {
1739 printf("not at queue_end, zone=0x%x, tmp_elem=0x%x\n",
1740 zone, tmp_elem);
1741 assert(FALSE);
1742 }
1743 }
1744
1745 void
1746 db_zone_print_active(
1747 zone_t zone)
1748 {
1749 int count = 0;
1750 queue_t tmp_elem;
1751
1752 if (!zone_debug_enabled(zone)) {
1753 printf("zone 0x%x debug not enabled\n", zone);
1754 return;
1755 }
1756 if (!zone_check) {
1757 printf("zone_check FALSE\n");
1758 return;
1759 }
1760
1761 printf("zone 0x%x, active elements %d\n", zone, zone->count);
1762 printf("active list:\n");
1763 tmp_elem = queue_first(&zone->active_zones);
1764 while (count < zone->count) {
1765 printf(" 0x%x", tmp_elem);
1766 count++;
1767 if ((count % 6) == 0)
1768 printf("\n");
1769 if (tmp_elem == 0) {
1770 printf("\nunexpected zero element, count=%d\n", count);
1771 break;
1772 }
1773 if (queue_end(tmp_elem, &zone->active_zones)) {
1774 printf("\nunexpected queue_end, count=%d\n", count);
1775 break;
1776 }
1777 tmp_elem = queue_next(tmp_elem);
1778 }
1779 if (!queue_end(tmp_elem, &zone->active_zones))
1780 printf("\nnot at queue_end, tmp_elem=0x%x\n", tmp_elem);
1781 else
1782 printf("\n");
1783 }
1784 #endif /* ZONE_DEBUG */
1785
1786 void
1787 db_zone_print_free(
1788 zone_t zone)
1789 {
1790 int count = 0;
1791 int freecount;
1792 vm_offset_t elem;
1793
1794 freecount = zone_free_count(zone);
1795 printf("zone 0x%x, free elements %d\n", zone, freecount);
1796 printf("free list:\n");
1797 elem = zone->free_elements;
1798 while (count < freecount) {
1799 printf(" 0x%x", elem);
1800 count++;
1801 if ((count % 6) == 0)
1802 printf("\n");
1803 if (elem == 0) {
1804 printf("\nunexpected zero element, count=%d\n", count);
1805 break;
1806 }
1807 elem = *((vm_offset_t *)elem);
1808 }
1809 if (elem != 0)
1810 printf("\nnot at end of free list, elem=0x%x\n", elem);
1811 else
1812 printf("\n");
1813 }
1814
1815 #endif /* MACH_KDB */
1816
1817
1818 #if ZONE_DEBUG
1819
1820 /* should we care about locks here ? */
1821
1822 #if MACH_KDB
1823 void *
1824 next_element(
1825 zone_t z,
1826 void *prev)
1827 {
1828 char *elt = (char *)prev;
1829
1830 if (!zone_debug_enabled(z))
1831 return(0);
1832 elt -= ZONE_DEBUG_OFFSET;
1833 elt = (char *) queue_next((queue_t) elt);
1834 if ((queue_t) elt == &z->active_zones)
1835 return(0);
1836 elt += ZONE_DEBUG_OFFSET;
1837 return(elt);
1838 }
1839
1840 void *
1841 first_element(
1842 zone_t z)
1843 {
1844 char *elt;
1845
1846 if (!zone_debug_enabled(z))
1847 return(0);
1848 if (queue_empty(&z->active_zones))
1849 return(0);
1850 elt = (char *)queue_first(&z->active_zones);
1851 elt += ZONE_DEBUG_OFFSET;
1852 return(elt);
1853 }
1854
1855 /*
1856 * Second arg controls how many zone elements are printed:
1857 * 0 => none
1858 * n, n < 0 => all
1859 * n, n > 0 => last n on active list
1860 */
1861 int
1862 zone_count(
1863 zone_t z,
1864 int tail)
1865 {
1866 void *elt;
1867 int count = 0;
1868 boolean_t print = (tail != 0);
1869
1870 if (tail < 0)
1871 tail = z->count;
1872 if (z->count < tail)
1873 tail = 0;
1874 tail = z->count - tail;
1875 for (elt = first_element(z); elt; elt = next_element(z, elt)) {
1876 if (print && tail <= count)
1877 db_printf("%8x\n", elt);
1878 count++;
1879 }
1880 assert(count == z->count);
1881 return(count);
1882 }
1883 #endif /* MACH_KDB */
1884
1885 #define zone_in_use(z) ( z->count || z->free_elements )
1886
1887 void
1888 zone_debug_enable(
1889 zone_t z)
1890 {
1891 if (zone_debug_enabled(z) || zone_in_use(z) ||
1892 z->alloc_size < (z->elem_size + ZONE_DEBUG_OFFSET))
1893 return;
1894 queue_init(&z->active_zones);
1895 z->elem_size += ZONE_DEBUG_OFFSET;
1896 }
1897
1898 void
1899 zone_debug_disable(
1900 zone_t z)
1901 {
1902 if (!zone_debug_enabled(z) || zone_in_use(z))
1903 return;
1904 z->elem_size -= ZONE_DEBUG_OFFSET;
1905 z->active_zones.next = z->active_zones.prev = 0;
1906 }
1907 #endif /* ZONE_DEBUG */