|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * The contents of this file constitute Original Code as defined in and
7: * are subject to the Apple Public Source License Version 1.1 (the
8: * "License"). You may not use this file except in compliance with the
9: * License. Please obtain a copy of the License at
10: * http://www.apple.com/publicsource and read it before using this file.
11: *
12: * This Original Code and all software distributed under the License are
13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17: * License for the specific language governing rights and limitations
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * HISTORY
27: * $Log: rtmalloc.c,v $
28: * Revision 1.1.1.1 2000/03/25 21:02:59 wsanchez
29: * Import of xnu-68.4
30: *
31: * Revision 1.3 2000/01/26 05:57:35 wsanchez
32: * Add APSL
33: *
34: * Revision 1.2 1998/10/20 03:35:27 wsanchez
35: * Merged in Bill's mother-of-all-diffs.
36: *
37: * Revision 1.1.2.1 1998/10/20 02:52:22 angell
38: * Changed PTE handling. Added SMP and RT. Improved context saving.
39: *
40: * Revision 1.1.1.1 1998/09/22 21:05:33 wsanchez
41: * Import of Mac OS X kernel (~semeria)
42: *
43: * Revision 1.1.1.1 1998/03/07 02:25:56 wsanchez
44: * Import of OSF Mach kernel (~mburg)
45: *
46: * Revision 1.1.4.4 1995/10/09 17:16:24 devrcs
47: * Merge RT IPC
48: * [1995/09/21 23:10:26 widyono]
49: *
50: * Revision 1.1.4.3 1995/01/10 05:13:37 devrcs
51: * mk6 CR801 - copyright marker not FREE_
52: * [1994/12/01 19:24:57 dwm]
53: *
54: * mk6 CR668 - 1.3b26 merge
55: * zchange to zone_change
56: * [1994/11/04 09:29:18 dwm]
57: *
58: * Revision 1.1.4.1 1994/08/18 23:12:56 widyono
59: * RT IPC from RT2_SHARED
60: * [1994/08/18 15:50:06 widyono]
61: *
62: * Revision 1.1.2.1 1994/07/29 07:34:38 widyono
63: * Explicitly make RT zones non-collectable, non-expandable
64: * [1994/07/29 06:26:39 widyono]
65: *
66: * Update to rt2_shared: zchange -> zone_change
67: * [1994/07/29 05:07:59 widyono]
68: *
69: * RT zone allocation routines, new module
70: * [1994/07/28 22:31:19 widyono]
71: *
72: * $EndLog$
73: */
74: /* CMU_HIST */
75: /*
76: * Revision 2.9 91/05/14 16:43:17 mrt
77: * Correcting copyright
78: *
79: * Revision 2.8 91/03/16 14:50:37 rpd
80: * Updated for new kmem_alloc interface.
81: * [91/03/03 rpd]
82: *
83: * Revision 2.7 91/02/05 17:27:22 mrt
84: * Changed to new Mach copyright
85: * [91/02/01 16:14:12 mrt]
86: *
87: * Revision 2.6 90/06/19 22:59:06 rpd
88: * Made the big kalloc zones collectable.
89: * [90/06/05 rpd]
90: *
91: * Revision 2.5 90/06/02 14:54:47 rpd
92: * Added kalloc_max, kalloc_map_size.
93: * [90/03/26 22:06:39 rpd]
94: *
95: * Revision 2.4 90/01/11 11:43:13 dbg
96: * De-lint.
97: * [89/12/06 dbg]
98: *
99: * Revision 2.3 89/09/08 11:25:51 dbg
100: * MACH_KERNEL: remove non-MACH data types.
101: * [89/07/11 dbg]
102: *
103: * Revision 2.2 89/08/31 16:18:59 rwd
104: * First Checkin
105: * [89/08/23 15:41:37 rwd]
106: *
107: * Revision 2.6 89/08/02 08:03:28 jsb
108: * Make all kalloc zones 8 MB big. (No more kalloc panics!)
109: * [89/08/01 14:10:17 jsb]
110: *
111: * Revision 2.4 89/04/05 13:03:10 rvb
112: * Guarantee a zone max of at least 100 elements or 10 pages
113: * which ever is greater. Afs (AllocDouble()) puts a great demand
114: * on the 2048 zone and used to blow away.
115: * [89/03/09 rvb]
116: *
117: * Revision 2.3 89/02/25 18:04:39 gm0w
118: * Changes for cleanup.
119: *
120: * Revision 2.2 89/01/18 02:07:04 jsb
121: * Give each kalloc zone a meaningful name (for panics);
122: * create a zone for each power of 2 between MINSIZE
123: * and PAGE_SIZE, instead of using (obsoleted) NQUEUES.
124: * [89/01/17 10:16:33 jsb]
125: *
126: *
127: * 13-Feb-88 John Seamons (jks) at NeXT
128: * Updated to use kmem routines instead of vmem routines.
129: *
130: * 21-Jun-85 Avadis Tevanian (avie) at Carnegie-Mellon University
131: * Created.
132: */
133: /* CMU_ENDHIST */
134: /*
135: * Mach Operating System
136: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
137: * All Rights Reserved.
138: *
139: * Permission to use, copy, modify and distribute this software and its
140: * documentation is hereby granted, provided that both the copyright
141: * notice and this permission notice appear in all copies of the
142: * software, derivative works or modified versions, and any portions
143: * thereof, and that both notices appear in supporting documentation.
144: *
145: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
146: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
147: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
148: *
149: * Carnegie Mellon requests users of this software to return to
150: *
151: * Software Distribution Coordinator or [email protected]
152: * School of Computer Science
153: * Carnegie Mellon University
154: * Pittsburgh PA 15213-3890
155: *
156: * any improvements or extensions that they make and grant Carnegie Mellon
157: * the rights to redistribute these changes.
158: */
159: /*
160: */
161: /*
162: * File: kern/rtmalloc.c
163: * Author: Ron Widyono
164: * Date: 1994
165: *
166: * General real-time kernel memory allocator. This allocator is designed
167: * to be used by the kernel to manage dynamic memory fast, but exclusively
168: * for real-time purposes. In fact, only real-time IPC users compete for
169: * these resources.
170: *
171: * This is a dirty implementation--a clone of kalloc. A cleaner imple-
172: * mentation is to have both k_zones and rt_zones use common code.
173: */
174:
175: #include <mach/boolean.h>
176: #include <mach/machine/vm_types.h>
177: #include <mach/vm_param.h>
178: #include <kern/misc_protos.h>
179: #include <kern/zalloc.h>
180: #include <kern/rtmalloc.h>
181: #include <vm/vm_kern.h>
182: #include <vm/vm_object.h>
183: #include <vm/vm_map.h>
184:
185: extern void Debugger(const char *);
186:
187: vm_map_t rtmalloc_map;
188: vm_size_t rtmalloc_map_size = 8 * 1024 * 1024;
189: vm_size_t rtmalloc_max;
190: vm_size_t rtmalloc_max_prerounded;
191:
192: /*
193: * All allocations of size less than rtmalloc_max are rounded to the
194: * next highest power of 2. This allocator is built on top of
195: * the zone allocator. A zone is created for each potential size
196: * that we are willing to get in small blocks.
197: *
198: * We assume that rtmalloc_max is not greater than 64K;
199: * thus 16 is a safe array size for rt_zone and rt_zone_name.
200: *
201: * Note that rtmalloc_max is somewhat confusingly named.
202: * It represents the first power of two for which no zone exists.
203: * rtmalloc_max_prerounded is the smallest allocation size, before
204: * rounding, for which no zone exists.
205: */
206:
207: int first_rt_zone = -1;
208: struct zone *rt_zone[16];
209: static char *rt_zone_name[16] = {
210: "rtmalloc.1", "rtmalloc.2",
211: "rtmalloc.4", "rtmalloc.8",
212: "rtmalloc.16", "rtmalloc.32",
213: "rtmalloc.64", "rtmalloc.128",
214: "rtmalloc.256", "rtmalloc.512",
215: "rtmalloc.1024", "rtmalloc.2048",
216: "rtmalloc.4096", "rtmalloc.8192",
217: "rtmalloc.16384", "rtmalloc.32768"
218: };
219:
220: /*
221: * Max number of elements per zone. zinit rounds things up correctly
222: * Doing things this way permits each zone to have a different maximum size
223: * based on need, rather than just guessing; it also
224: * means its patchable in case you're wrong!
225: */
226: unsigned long rt_zone_max[16] = {
227: RT_ZONE_MAX_1,
228: RT_ZONE_MAX_2,
229: RT_ZONE_MAX_4,
230: RT_ZONE_MAX_8,
231: RT_ZONE_MAX_16,
232: RT_ZONE_MAX_32,
233: RT_ZONE_MAX_64,
234: RT_ZONE_MAX_128,
235: RT_ZONE_MAX_256,
236: RT_ZONE_MAX_512,
237: RT_ZONE_MAX_1024,
238: RT_ZONE_MAX_2048,
239: RT_ZONE_MAX_4096,
240: RT_ZONE_MAX_8192,
241: RT_ZONE_MAX_16384,
242: RT_ZONE_MAX_32768
243: };
244:
245: /*
246: * Initialize the memory allocator. This should be called only
247: * once on a system wide basis (i.e. first processor to get here
248: * does the initialization).
249: *
250: * This initializes all of the zones.
251: */
252:
253: void
254: rtmalloc_init(
255: void)
256: {
257: kern_return_t retval;
258: vm_offset_t min, addr;
259: vm_size_t size;
260: register int i;
261:
262: retval = kmem_suballoc(kernel_map, &min, rtmalloc_map_size,
263: FALSE, TRUE, &rtmalloc_map);
264: if (retval != KERN_SUCCESS)
265: panic("rtmalloc_init: kmem_suballoc failed");
266:
267: /*
268: * Ensure that zones up to size 8192 bytes exist.
269: * This is desirable because messages are allocated
270: * with rtmalloc, and messages up through size 8192 are common.
271: */
272:
273: rtmalloc_max = 16 * 1024;
274: rtmalloc_max_prerounded = rtmalloc_max / 2 + 1;
275:
276: /*
277: * Allocate a zone for each size we are going to handle.
278: * We specify non-paged memory. Make zone exhaustible.
279: */
280: for (i = 0, size = 1; size < rtmalloc_max; i++, size <<= 1) {
281: if (size < rtmalloc_MINSIZE) {
282: rt_zone[i] = 0;
283: continue;
284: }
285: if (size == rtmalloc_MINSIZE) {
286: first_rt_zone = i;
287: }
288: rt_zone[i] = zinit(size, rt_zone_max[i] * size, size,
289: rt_zone_name[i]);
290: zone_change(rt_zone[i], Z_EXHAUST, TRUE);
291: zone_change(rt_zone[i], Z_COLLECT, FALSE);
292: zone_change(rt_zone[i], Z_EXPAND, FALSE);
293:
294: /*
295: * Get space from the zone_map. Since these zones are
296: * not collectable, no pages containing elements from these
297: * zones will ever be reclaimed by the garbage collection
298: * scheme below.
299: */
300:
301: zprealloc(rt_zone[i], rt_zone_max[i] * size);
302: }
303: }
304:
305: vm_offset_t
306: rtmalloc(
307: vm_size_t size)
308: {
309: register int zindex;
310: register vm_size_t allocsize;
311:
312: /*
313: * If size is too large for a zone, return error (0)
314: */
315:
316: if (size >= rtmalloc_max_prerounded) {
317: return(0);
318: }
319:
320: /* compute the size of the block that we will actually allocate */
321:
322: allocsize = rtmalloc_MINSIZE;
323: zindex = first_rt_zone;
324: while (allocsize < size) {
325: allocsize <<= 1;
326: zindex++;
327: }
328:
329: /* allocate from the appropriate zone */
330:
331: assert(allocsize < rtmalloc_max);
332: return(zalloc(rt_zone[zindex]));
333: }
334:
335: vm_offset_t
336: rtget(
337: vm_size_t size)
338: {
339: register int zindex;
340: register vm_size_t allocsize;
341:
342: /* size must not be too large for a zone */
343:
344: if (size >= rtmalloc_max_prerounded) {
345: /* This will never work, so we might as well panic */
346: panic("rtget");
347: }
348:
349: /* compute the size of the block that we will actually allocate */
350:
351: allocsize = rtmalloc_MINSIZE;
352: zindex = first_rt_zone;
353: while (allocsize < size) {
354: allocsize <<= 1;
355: zindex++;
356: }
357:
358: /* allocate from the appropriate zone */
359:
360: assert(allocsize < rtmalloc_max);
361: return(zget(rt_zone[zindex]));
362: }
363:
364: void
365: rtmfree(
366: vm_offset_t data,
367: vm_size_t size)
368: {
369: register int zindex;
370: register vm_size_t freesize;
371:
372: /*
373: * if size was too large for a RT zone, this is impossible;
374: * just return
375: */
376:
377: assert(size < rtmalloc_max_prerounded);
378: if (size >= rtmalloc_max_prerounded) {
379: return;
380: }
381:
382: /* compute the size of the block that we actually allocated from */
383:
384: freesize = rtmalloc_MINSIZE;
385: zindex = first_rt_zone;
386: while (freesize < size) {
387: freesize <<= 1;
388: zindex++;
389: }
390:
391: /* free to the appropriate zone */
392:
393: assert(freesize < rtmalloc_max);
394: zfree(rt_zone[zindex], data);
395: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.