|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1993-1987 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: kern/zalloc.c
31: * Author: Avadis Tevanian, Jr.
32: *
33: * Zone-based memory allocator. A zone is a collection of fixed size
34: * data blocks for which quick allocation/deallocation is possible.
35: */
36:
37: #include <kern/macro_help.h>
38: #include <kern/sched.h>
39: #include <kern/time_out.h>
40: #include <kern/zalloc.h>
41: #include <mach/vm_param.h>
42: #include <vm/vm_kern.h>
43: #include <machine/machspl.h>
44:
45: #include <mach_debug.h>
46: #if MACH_DEBUG
47: #include <mach/kern_return.h>
48: #include <mach/machine/vm_types.h>
49: #include <mach_debug/zone_info.h>
50: #include <kern/host.h>
51: #include <vm/vm_map.h>
52: #include <vm/vm_user.h>
53: #include <vm/vm_kern.h>
54: #endif
55:
56: #define ADD_TO_ZONE(zone, element) \
57: MACRO_BEGIN \
58: *((vm_offset_t *)(element)) = (zone)->free_elements; \
59: (zone)->free_elements = (vm_offset_t) (element); \
60: zone_count_down(zone); \
61: MACRO_END
62:
63: #define REMOVE_FROM_ZONE(zone, ret, type) \
64: MACRO_BEGIN \
65: (ret) = (type) (zone)->free_elements; \
66: if ((ret) != (type) 0) { \
67: zone_count_up(zone); \
68: (zone)->free_elements = *((vm_offset_t *)(ret)); \
69: } \
70: MACRO_END
71:
72: /*
73: * Support for garbage collection of unused zone pages:
74: */
75:
76: struct zone_page_table_entry {
77: struct zone_page_table_entry *next;
78: short in_free_list;
79: short alloc_count;
80: };
81:
82: extern struct zone_page_table_entry * zone_page_table;
83: extern vm_offset_t zone_map_min_address;
84:
85: #define lock_zone_page_table() simple_lock(&zone_page_table_lock)
86: #define unlock_zone_page_table() simple_unlock(&zone_page_table_lock)
87:
88: #define zone_page(addr) \
89: (&(zone_page_table[(atop(((vm_offset_t)addr) - zone_map_min_address))]))
90:
91:
92: extern void zone_page_alloc();
93: extern void zone_page_dealloc();
94: extern void zone_page_in_use();
95: extern void zone_page_free();
96:
97: zone_t zone_zone; /* this is the zone containing other zones */
98:
99: boolean_t zone_ignore_overflow = TRUE;
100:
101: vm_map_t zone_map = VM_MAP_NULL;
102: vm_size_t zone_map_size = 12 * 1024 * 1024;
103:
104: /*
105: * The VM system gives us an initial chunk of memory.
106: * It has to be big enough to allocate the zone_zone
107: * and some initial kernel data structures, like kernel maps.
108: * It is advantageous to make it bigger than really necessary,
109: * because this memory is more efficient than normal kernel
110: * virtual memory. (It doesn't have vm_page structures backing it
111: * and it may have other machine-dependent advantages.)
112: * So for best performance, zdata_size should approximate
113: * the amount of memory you expect the zone system to consume.
114: */
115:
116: vm_offset_t zdata;
117: vm_size_t zdata_size = 420 * 1024;
118:
119: #define zone_lock(zone) \
120: MACRO_BEGIN \
121: if (zone->type & ZONE_PAGEABLE) { \
122: lock_write(&zone->complex_lock); \
123: } else { \
124: simple_lock(&zone->lock); \
125: } \
126: MACRO_END
127:
128: #define zone_unlock(zone) \
129: MACRO_BEGIN \
130: if (zone->type & ZONE_PAGEABLE) { \
131: lock_done(&zone->complex_lock); \
132: } else { \
133: simple_unlock(&zone->lock); \
134: } \
135: MACRO_END
136:
137: #define zone_lock_init(zone) \
138: MACRO_BEGIN \
139: if (zone->type & ZONE_PAGEABLE) { \
140: lock_init(&zone->complex_lock, TRUE); \
141: } else { \
142: simple_lock_init(&zone->lock); \
143: } \
144: MACRO_END
145:
146: static vm_offset_t zget_space();
147:
148: decl_simple_lock_data(,zget_space_lock)
149: vm_offset_t zalloc_next_space;
150: vm_offset_t zalloc_end_of_space;
151: vm_size_t zalloc_wasted_space;
152:
153: /*
154: * Garbage collection map information
155: */
156: decl_simple_lock_data(,zone_page_table_lock)
157: struct zone_page_table_entry * zone_page_table;
158: vm_offset_t zone_map_min_address;
159: vm_offset_t zone_map_max_address;
160: int zone_pages;
161:
162: extern void zone_page_init();
163:
164: #define ZONE_PAGE_USED 0
165: #define ZONE_PAGE_UNUSED -1
166:
167:
168: /*
169: * Protects first_zone, last_zone, num_zones,
170: * and the next_zone field of zones.
171: */
172: decl_simple_lock_data(,all_zones_lock)
173: zone_t first_zone;
174: zone_t *last_zone;
175: int num_zones;
176:
177: /*
178: * zinit initializes a new zone. The zone data structures themselves
179: * are stored in a zone, which is initially a static structure that
180: * is initialized by zone_init.
181: */
182: zone_t zinit(size, max, alloc, memtype, name)
183: vm_size_t size; /* the size of an element */
184: vm_size_t max; /* maximum memory to use */
185: vm_size_t alloc; /* allocation size */
186: unsigned int memtype; /* flags specifying type of memory */
187: char *name; /* a name for the zone */
188: {
189: register zone_t z;
190:
191: if (zone_zone == ZONE_NULL)
192: z = (zone_t) zget_space(sizeof(struct zone));
193: else
194: z = (zone_t) zalloc(zone_zone);
195: if (z == ZONE_NULL)
196: panic("zinit");
197:
198: if (alloc == 0)
199: alloc = PAGE_SIZE;
200:
201: if (size == 0)
202: size = sizeof(z->free_elements);
203: /*
204: * Round off all the parameters appropriately.
205: */
206:
207: if ((max = round_page(max)) < (alloc = round_page(alloc)))
208: max = alloc;
209:
210: z->free_elements = 0;
211: z->cur_size = 0;
212: z->max_size = max;
213: z->elem_size = ((size-1) + sizeof(z->free_elements)) -
214: ((size-1) % sizeof(z->free_elements));
215:
216: z->alloc_size = alloc;
217: z->type = memtype;
218: z->zone_name = name;
219: #ifdef ZONE_COUNT
220: z->count = 0;
221: #endif
222: z->doing_alloc = FALSE;
223: zone_lock_init(z);
224:
225: /*
226: * Add the zone to the all-zones list.
227: */
228:
229: z->next_zone = ZONE_NULL;
230: simple_lock(&all_zones_lock);
231: *last_zone = z;
232: last_zone = &z->next_zone;
233: num_zones++;
234: simple_unlock(&all_zones_lock);
235:
236: return(z);
237: }
238:
239: /*
240: * Cram the given memory into the specified zone.
241: */
242: void zcram(zone_t zone, vm_offset_t newmem, vm_size_t size)
243: {
244: register vm_size_t elem_size;
245:
246: if (newmem == (vm_offset_t) 0) {
247: panic("zcram - memory at zero");
248: }
249: elem_size = zone->elem_size;
250:
251: zone_lock(zone);
252: while (size >= elem_size) {
253: ADD_TO_ZONE(zone, newmem);
254: zone_page_alloc(newmem, elem_size);
255: zone_count_up(zone); /* compensate for ADD_TO_ZONE */
256: size -= elem_size;
257: newmem += elem_size;
258: zone->cur_size += elem_size;
259: }
260: zone_unlock(zone);
261: }
262:
263: /*
264: * Contiguous space allocator for non-paged zones. Allocates "size" amount
265: * of memory from zone_map.
266: */
267:
268: static vm_offset_t zget_space(vm_offset_t size)
269: {
270: vm_offset_t new_space = 0;
271: vm_offset_t result;
272: vm_size_t space_to_add = 0; /*'=0' to quiet gcc warnings */
273:
274: simple_lock(&zget_space_lock);
275: while ((zalloc_next_space + size) > zalloc_end_of_space) {
276: /*
277: * Add at least one page to allocation area.
278: */
279:
280: space_to_add = round_page(size);
281:
282: if (new_space == 0) {
283: /*
284: * Memory cannot be wired down while holding
285: * any locks that the pageout daemon might
286: * need to free up pages. [Making the zget_space
287: * lock a complex lock does not help in this
288: * regard.]
289: *
290: * Unlock and allocate memory. Because several
291: * threads might try to do this at once, don't
292: * use the memory before checking for available
293: * space again.
294: */
295:
296: simple_unlock(&zget_space_lock);
297:
298: if (kmem_alloc_wired(zone_map,
299: &new_space, space_to_add)
300: != KERN_SUCCESS)
301: return(0);
302: zone_page_init(new_space, space_to_add,
303: ZONE_PAGE_USED);
304: simple_lock(&zget_space_lock);
305: continue;
306: }
307:
308:
309: /*
310: * Memory was allocated in a previous iteration.
311: *
312: * Check whether the new region is contiguous
313: * with the old one.
314: */
315:
316: if (new_space != zalloc_end_of_space) {
317: /*
318: * Throw away the remainder of the
319: * old space, and start a new one.
320: */
321: zalloc_wasted_space +=
322: zalloc_end_of_space - zalloc_next_space;
323: zalloc_next_space = new_space;
324: }
325:
326: zalloc_end_of_space = new_space + space_to_add;
327:
328: new_space = 0;
329: }
330: result = zalloc_next_space;
331: zalloc_next_space += size;
332: simple_unlock(&zget_space_lock);
333:
334: if (new_space != 0)
335: kmem_free(zone_map, new_space, space_to_add);
336:
337: return(result);
338: }
339:
340:
341: /*
342: * Initialize the "zone of zones" which uses fixed memory allocated
343: * earlier in memory initialization. zone_bootstrap is called
344: * before zone_init.
345: */
346: void zone_bootstrap()
347: {
348: simple_lock_init(&all_zones_lock);
349: first_zone = ZONE_NULL;
350: last_zone = &first_zone;
351: num_zones = 0;
352:
353: simple_lock_init(&zget_space_lock);
354: zalloc_next_space = zdata;
355: zalloc_end_of_space = zdata + zdata_size;
356: zalloc_wasted_space = 0;
357:
358: zone_zone = ZONE_NULL;
359: zone_zone = zinit(sizeof(struct zone), 128 * sizeof(struct zone),
360: sizeof(struct zone), 0, "zones");
361: }
362:
363: void zone_init()
364: {
365: vm_offset_t zone_min;
366: vm_offset_t zone_max;
367:
368: vm_size_t zone_table_size;
369:
370: zone_map = kmem_suballoc(kernel_map, &zone_min, &zone_max,
371: zone_map_size, FALSE);
372:
373: /*
374: * Setup garbage collection information:
375: */
376:
377: zone_table_size = atop(zone_max - zone_min) *
378: sizeof(struct zone_page_table_entry);
379: if (kmem_alloc_wired(zone_map, (vm_offset_t *) &zone_page_table,
380: zone_table_size) != KERN_SUCCESS)
381: panic("zone_init");
382: zone_min = (vm_offset_t)zone_page_table + round_page(zone_table_size);
383: zone_pages = atop(zone_max - zone_min);
384: zone_map_min_address = zone_min;
385: zone_map_max_address = zone_max;
386: simple_lock_init(&zone_page_table_lock);
387: zone_page_init(zone_min, zone_max - zone_min, ZONE_PAGE_UNUSED);
388: }
389:
390:
391: /*
392: * zalloc returns an element from the specified zone.
393: */
394: vm_offset_t zalloc(zone_t zone)
395: {
396: vm_offset_t addr;
397:
398: if (zone == ZONE_NULL)
399: panic ("zalloc: null zone");
400:
401: check_simple_locks();
402:
403: zone_lock(zone);
404: REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
405: while (addr == 0) {
406: /*
407: * If nothing was there, try to get more
408: */
409: if (zone->doing_alloc) {
410: /*
411: * Someone is allocating memory for this zone.
412: * Wait for it to show up, then try again.
413: */
414: assert_wait((event_t)&zone->doing_alloc, TRUE);
415: /* XXX say wakeup needed */
416: zone_unlock(zone);
417: thread_block((void (*)()) 0);
418: zone_lock(zone);
419: }
420: else {
421: if ((zone->cur_size + (zone->type & ZONE_PAGEABLE ?
422: zone->alloc_size : zone->elem_size)) >
423: zone->max_size) {
424: if (zone->type & ZONE_EXHAUSTIBLE)
425: break;
426: /*
427: * Printf calls logwakeup, which calls
428: * select_wakeup which will do a zfree
429: * (which tries to take the select_zone
430: * lock... Hang. Release the lock now
431: * so it can be taken again later.
432: * NOTE: this used to be specific to
433: * the select_zone, but for
434: * cleanliness, we just unlock all
435: * zones before this.
436: */
437: if (!(zone->type & ZONE_FIXED)) {
438: /*
439: * We're willing to overflow certain
440: * zones, but not without complaining.
441: *
442: * This is best used in conjunction
443: * with the collecatable flag. What we
444: * want is an assurance we can get the
445: * memory back, assuming there's no
446: * leak.
447: */
448: zone->max_size += (zone->max_size >> 1);
449: } else if (!zone_ignore_overflow) {
450: zone_unlock(zone);
451: printf("zone \"%s\" empty.\n",
452: zone->zone_name);
453: panic("zalloc: zone %s exhausted",
454: zone->zone_name);
455: }
456: }
457:
458: if (zone->type & ZONE_PAGEABLE)
459: zone->doing_alloc = TRUE;
460: zone_unlock(zone);
461:
462: if (zone->type & ZONE_PAGEABLE) {
463: if (kmem_alloc_pageable(zone_map, &addr,
464: zone->alloc_size)
465: != KERN_SUCCESS)
466: panic("zalloc: zone %s exhausted",
467: zone->zone_name);
468: zcram(zone, addr, zone->alloc_size);
469: zone_lock(zone);
470: zone->doing_alloc = FALSE;
471: /* XXX check before doing this */
472: thread_wakeup((event_t)&zone->doing_alloc);
473:
474: REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
475: } else if (zone->type & ZONE_COLLECTABLE) {
476: if (kmem_alloc_wired(zone_map,
477: &addr, zone->alloc_size)
478: != KERN_SUCCESS)
479: panic("zalloc: zone %s exhausted",
480: zone->zone_name);
481: zone_page_init(addr, zone->alloc_size,
482: ZONE_PAGE_USED);
483: zcram(zone, addr, zone->alloc_size);
484: zone_lock(zone);
485: REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
486: } else {
487: addr = zget_space(zone->elem_size);
488: if (addr == 0)
489: panic("zalloc: zone %s exhausted",
490: zone->zone_name);
491:
492: zone_lock(zone);
493: zone_count_up(zone);
494: zone->cur_size += zone->elem_size;
495: zone_unlock(zone);
496: zone_page_alloc(addr, zone->elem_size);
497: return(addr);
498: }
499: }
500: }
501:
502: zone_unlock(zone);
503: return(addr);
504: }
505:
506:
507: /*
508: * zget returns an element from the specified zone
509: * and immediately returns nothing if there is nothing there.
510: *
511: * This form should be used when you can not block (like when
512: * processing an interrupt).
513: */
514: vm_offset_t zget(zone_t zone)
515: {
516: register vm_offset_t addr;
517:
518: if (zone == ZONE_NULL)
519: panic ("zalloc: null zone");
520:
521: zone_lock(zone);
522: REMOVE_FROM_ZONE(zone, addr, vm_offset_t);
523: zone_unlock(zone);
524:
525: return(addr);
526: }
527:
528: boolean_t zone_check = FALSE;
529:
530: void zfree(zone_t zone, vm_offset_t elem)
531: {
532: zone_lock(zone);
533: if (zone_check) {
534: vm_offset_t this;
535:
536: /* check the zone's consistency */
537:
538: for (this = zone->free_elements;
539: this != 0;
540: this = * (vm_offset_t *) this)
541: if (this == elem)
542: panic("zfree");
543: }
544: ADD_TO_ZONE(zone, elem);
545: zone_unlock(zone);
546: }
547:
548: /*
549: * Zone garbage collection subroutines
550: *
551: * These routines have in common the modification of entries in the
552: * zone_page_table. The latter contains one entry for every page
553: * in the zone_map.
554: *
555: * For each page table entry in the given range:
556: *
557: * zone_page_in_use - decrements in_free_list
558: * zone_page_free - increments in_free_list
559: * zone_page_init - initializes in_free_list and alloc_count
560: * zone_page_alloc - increments alloc_count
561: * zone_page_dealloc - decrements alloc_count
562: * zone_add_free_page_list - adds the page to the free list
563: *
564: * Two counts are maintained for each page, the in_free_list count and
565: * alloc_count. The alloc_count is how many zone elements have been
566: * allocated from a page. (Note that the page could contain elements
567: * that span page boundaries. The count includes these elements so
568: * one element may be counted in two pages.) In_free_list is a count
569: * of how many zone elements are currently free. If in_free_list is
570: * equal to alloc_count then the page is eligible for garbage
571: * collection.
572: *
573: * Alloc_count and in_free_list are initialized to the correct values
574: * for a particular zone when a page is zcram'ed into a zone. Subsequent
575: * gets and frees of zone elements will call zone_page_in_use and
576: * zone_page_free which modify the in_free_list count. When the zones
577: * garbage collector runs it will walk through a zones free element list,
578: * remove the elements that reside on collectable pages, and use
579: * zone_add_free_page_list to create a list of pages to be collected.
580: */
581:
582: void zone_page_in_use(addr, size)
583: vm_offset_t addr;
584: vm_size_t size;
585: {
586: int i, j;
587: if ((addr < zone_map_min_address) ||
588: (addr+size > zone_map_max_address)) return;
589: i = atop(addr-zone_map_min_address);
590: j = atop((addr+size-1) - zone_map_min_address);
591: lock_zone_page_table();
592: for (; i <= j; i++) {
593: zone_page_table[i].in_free_list--;
594: }
595: unlock_zone_page_table();
596: }
597:
598: void zone_page_free(addr, size)
599: vm_offset_t addr;
600: vm_size_t size;
601: {
602: int i, j;
603: if ((addr < zone_map_min_address) ||
604: (addr+size > zone_map_max_address)) return;
605: i = atop(addr-zone_map_min_address);
606: j = atop((addr+size-1) - zone_map_min_address);
607: lock_zone_page_table();
608: for (; i <= j; i++) {
609: /* Set in_free_list to (ZONE_PAGE_USED + 1) if
610: * it was previously set to ZONE_PAGE_UNUSED.
611: */
612: if (zone_page_table[i].in_free_list == ZONE_PAGE_UNUSED) {
613: zone_page_table[i].in_free_list = 1;
614: } else {
615: zone_page_table[i].in_free_list++;
616: }
617: }
618: unlock_zone_page_table();
619: }
620:
621: void zone_page_init(addr, size, value)
622:
623: vm_offset_t addr;
624: vm_size_t size;
625: int value;
626: {
627: int i, j;
628: if ((addr < zone_map_min_address) ||
629: (addr+size > zone_map_max_address)) return;
630: i = atop(addr-zone_map_min_address);
631: j = atop((addr+size-1) - zone_map_min_address);
632: lock_zone_page_table();
633: for (; i <= j; i++) {
634: zone_page_table[i].alloc_count = value;
635: zone_page_table[i].in_free_list = 0;
636: }
637: unlock_zone_page_table();
638: }
639:
640: void zone_page_alloc(addr, size)
641: vm_offset_t addr;
642: vm_size_t size;
643: {
644: int i, j;
645: if ((addr < zone_map_min_address) ||
646: (addr+size > zone_map_max_address)) return;
647: i = atop(addr-zone_map_min_address);
648: j = atop((addr+size-1) - zone_map_min_address);
649: lock_zone_page_table();
650: for (; i <= j; i++) {
651: /* Set alloc_count to (ZONE_PAGE_USED + 1) if
652: * it was previously set to ZONE_PAGE_UNUSED.
653: */
654: if (zone_page_table[i].alloc_count == ZONE_PAGE_UNUSED) {
655: zone_page_table[i].alloc_count = 1;
656: } else {
657: zone_page_table[i].alloc_count++;
658: }
659: }
660: unlock_zone_page_table();
661: }
662:
663: void zone_page_dealloc(addr, size)
664: vm_offset_t addr;
665: vm_size_t size;
666: {
667: int i, j;
668: if ((addr < zone_map_min_address) ||
669: (addr+size > zone_map_max_address)) return;
670: i = atop(addr-zone_map_min_address);
671: j = atop((addr+size-1) - zone_map_min_address);
672: lock_zone_page_table();
673: for (; i <= j; i++) {
674: zone_page_table[i].alloc_count--;
675: }
676: unlock_zone_page_table();
677: }
678:
679: void
680: zone_add_free_page_list(free_list, addr, size)
681: struct zone_page_table_entry **free_list;
682: vm_offset_t addr;
683: vm_size_t size;
684: {
685: int i, j;
686: if ((addr < zone_map_min_address) ||
687: (addr+size > zone_map_max_address)) return;
688: i = atop(addr-zone_map_min_address);
689: j = atop((addr+size-1) - zone_map_min_address);
690: lock_zone_page_table();
691: for (; i <= j; i++) {
692: if (zone_page_table[i].alloc_count == 0) {
693: zone_page_table[i].next = *free_list;
694: *free_list = &zone_page_table[i];
695: zone_page_table[i].alloc_count = ZONE_PAGE_UNUSED;
696: zone_page_table[i].in_free_list = 0;
697: }
698: }
699: unlock_zone_page_table();
700: }
701:
702:
703: /* This is used for walking through a zone's free element list.
704: */
705: struct zone_free_entry {
706: struct zone_free_entry * next;
707: };
708:
709:
710: /* Zone garbage collection
711: *
712: * zone_gc will walk through all the free elements in all the
713: * zones that are marked collectable looking for reclaimable
714: * pages. zone_gc is called by consider_zone_gc when the system
715: * begins to run out of memory.
716: */
717: static void zone_gc()
718: {
719: int max_zones;
720: zone_t z;
721: int i;
722: register spl_t s;
723: struct zone_page_table_entry *freep;
724: struct zone_page_table_entry *zone_free_page_list;
725:
726: simple_lock(&all_zones_lock);
727: max_zones = num_zones;
728: z = first_zone;
729: simple_unlock(&all_zones_lock);
730:
731: zone_free_page_list = (struct zone_page_table_entry *) 0;
732:
733: for (i = 0; i < max_zones; i++) {
734: struct zone_free_entry * last;
735: struct zone_free_entry * elt;
736: assert(z != ZONE_NULL);
737: /* run this at splhigh so that interupt routines that use zones
738: can not interupt while their zone is locked */
739: s=splhigh();
740: zone_lock(z);
741:
742: if ((z->type & (ZONE_PAGEABLE|ZONE_COLLECTABLE)) == ZONE_COLLECTABLE) {
743:
744: /* Count the free elements in each page. This loop
745: * requires that all in_free_list entries are zero.
746: */
747: elt = (struct zone_free_entry *)(z->free_elements);
748: while ((elt != (struct zone_free_entry *)0)) {
749: zone_page_free((vm_offset_t)elt, z->elem_size);
750: elt = elt->next;
751: }
752:
753: /* Now determine which elements should be removed
754: * from the free list and, after all the elements
755: * on a page have been removed, add the element's
756: * page to a list of pages to be freed.
757: */
758: elt = (struct zone_free_entry *)(z->free_elements);
759: last = elt;
760: while ((elt != (struct zone_free_entry *)0)) {
761: if (((vm_offset_t)elt>=zone_map_min_address)&&
762: ((vm_offset_t)elt<=zone_map_max_address)&&
763: (zone_page(elt)->in_free_list ==
764: zone_page(elt)->alloc_count)) {
765:
766: z->cur_size -= z->elem_size;
767: zone_page_in_use((vm_offset_t)elt, z->elem_size);
768: zone_page_dealloc((vm_offset_t)elt, z->elem_size);
769: if (zone_page(elt)->alloc_count == 0 ||
770: zone_page(elt+(z->elem_size-1))->alloc_count==0) {
771: zone_add_free_page_list(
772: &zone_free_page_list,
773: (vm_offset_t)elt, z->elem_size);
774: }
775:
776:
777: if (elt == last) {
778: elt = elt->next;
779: z->free_elements =(vm_offset_t)elt;
780: last = elt;
781: } else {
782: last->next = elt->next;
783: elt = elt->next;
784: }
785: } else {
786: /* This element is not eligible for collection
787: * so clear in_free_list in preparation for a
788: * subsequent garbage collection pass.
789: */
790: if (((vm_offset_t)elt>=zone_map_min_address)&&
791: ((vm_offset_t)elt<=zone_map_max_address)) {
792: zone_page(elt)->in_free_list = 0;
793: }
794: last = elt;
795: elt = elt->next;
796: }
797: }
798: }
799: zone_unlock(z);
800: splx(s);
801: simple_lock(&all_zones_lock);
802: z = z->next_zone;
803: simple_unlock(&all_zones_lock);
804: }
805:
806: for (freep = zone_free_page_list; freep != 0; freep = freep->next) {
807: vm_offset_t free_addr;
808:
809: free_addr = zone_map_min_address +
810: PAGE_SIZE * (freep - zone_page_table);
811: kmem_free(zone_map, free_addr, PAGE_SIZE);
812: }
813: }
814:
815: boolean_t zone_gc_allowed = TRUE;
816: unsigned zone_gc_last_tick = 0;
817: unsigned zone_gc_max_rate = 0; /* in ticks */
818:
819: /*
820: * consider_zone_gc:
821: *
822: * Called by the pageout daemon when the system needs more free pages.
823: */
824:
825: void
826: consider_zone_gc()
827: {
828: /*
829: * By default, don't attempt zone GC more frequently
830: * than once a second.
831: */
832:
833: if (zone_gc_max_rate == 0)
834: zone_gc_max_rate = hz;
835:
836: if (zone_gc_allowed &&
837: (sched_tick > (zone_gc_last_tick + zone_gc_max_rate))) {
838: zone_gc_last_tick = sched_tick;
839: zone_gc();
840: }
841: }
842:
843: #if MACH_DEBUG
844: kern_return_t host_zone_info(host, namesp, namesCntp, infop, infoCntp)
845: host_t host;
846: zone_name_array_t *namesp;
847: unsigned int *namesCntp;
848: zone_info_array_t *infop;
849: unsigned int *infoCntp;
850: {
851: zone_name_t *names;
852: vm_offset_t names_addr;
853: vm_size_t names_size = 0; /*'=0' to quiet gcc warnings */
854: zone_info_t *info;
855: vm_offset_t info_addr;
856: vm_size_t info_size = 0; /*'=0' to quiet gcc warnings */
857: unsigned int max_zones, i;
858: zone_t z;
859: kern_return_t kr;
860:
861: if (host == HOST_NULL)
862: return KERN_INVALID_HOST;
863:
864: /*
865: * We assume that zones aren't freed once allocated.
866: * We won't pick up any zones that are allocated later.
867: */
868:
869: simple_lock(&all_zones_lock);
870: max_zones = num_zones;
871: z = first_zone;
872: simple_unlock(&all_zones_lock);
873:
874: if (max_zones <= *namesCntp) {
875: /* use in-line memory */
876:
877: names = *namesp;
878: } else {
879: names_size = round_page(max_zones * sizeof *names);
880: kr = kmem_alloc_pageable(ipc_kernel_map,
881: &names_addr, names_size);
882: if (kr != KERN_SUCCESS)
883: return kr;
884:
885: names = (zone_name_t *) names_addr;
886: }
887:
888: if (max_zones <= *infoCntp) {
889: /* use in-line memory */
890:
891: info = *infop;
892: } else {
893: info_size = round_page(max_zones * sizeof *info);
894: kr = kmem_alloc_pageable(ipc_kernel_map,
895: &info_addr, info_size);
896: if (kr != KERN_SUCCESS) {
897: if (names != *namesp)
898: kmem_free(ipc_kernel_map,
899: names_addr, names_size);
900: return kr;
901: }
902:
903: info = (zone_info_t *) info_addr;
904: }
905:
906: for (i = 0; i < max_zones; i++) {
907: zone_name_t *zn = &names[i];
908: zone_info_t *zi = &info[i];
909: struct zone zcopy;
910:
911: assert(z != ZONE_NULL);
912:
913: zone_lock(z);
914: zcopy = *z;
915: zone_unlock(z);
916:
917: simple_lock(&all_zones_lock);
918: z = z->next_zone;
919: simple_unlock(&all_zones_lock);
920:
921: /* assuming here the name data is static */
922: (void) strncpy(zn->zn_name, zcopy.zone_name,
923: sizeof zn->zn_name);
924:
925: #ifdef ZONE_COUNT
926: zi->zi_count = zcopy.count;
927: #else
928: zi->zi_count = 0;
929: #endif
930: zi->zi_cur_size = zcopy.cur_size;
931: zi->zi_max_size = zcopy.max_size;
932: zi->zi_elem_size = zcopy.elem_size;
933: zi->zi_alloc_size = zcopy.alloc_size;
934: zi->zi_pageable = (zcopy.type & ZONE_PAGEABLE) != 0;
935: zi->zi_exhaustible = (zcopy.type & ZONE_EXHAUSTIBLE) != 0;
936: zi->zi_collectable = (zcopy.type & ZONE_COLLECTABLE) != 0;
937: }
938:
939: if (names != *namesp) {
940: vm_size_t used;
941: vm_map_copy_t copy;
942:
943: used = max_zones * sizeof *names;
944:
945: if (used != names_size)
946: bzero((char *) (names_addr + used), names_size - used);
947:
948: kr = vm_map_copyin(ipc_kernel_map, names_addr, names_size,
949: TRUE, ©);
950: assert(kr == KERN_SUCCESS);
951:
952: *namesp = (zone_name_t *) copy;
953: }
954: *namesCntp = max_zones;
955:
956: if (info != *infop) {
957: vm_size_t used;
958: vm_map_copy_t copy;
959:
960: used = max_zones * sizeof *info;
961:
962: if (used != info_size)
963: bzero((char *) (info_addr + used), info_size - used);
964:
965: kr = vm_map_copyin(ipc_kernel_map, info_addr, info_size,
966: TRUE, ©);
967: assert(kr == KERN_SUCCESS);
968:
969: *infop = (zone_info_t *) copy;
970: }
971: *infoCntp = max_zones;
972:
973: return KERN_SUCCESS;
974: }
975: #endif /* MACH_DEBUG */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.