|
|
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: * ! 28: * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez ! 29: * Import of Mac OS X kernel (~semeria) ! 30: * ! 31: * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez ! 32: * Import of OSF Mach kernel (~mburg) ! 33: * ! 34: * Revision 1.2.19.5 1995/02/24 15:20:29 alanl ! 35: * Lock package cleanup. ! 36: * [95/02/15 alanl] ! 37: * ! 38: * Merge with DIPC2_SHARED. ! 39: * [1995/01/05 15:11:02 alanl] ! 40: * ! 41: * Revision 1.2.28.2 1994/11/10 06:12:50 dwm ! 42: * mk6 CR764 - s/spinlock/simple_lock/ (name change only) ! 43: * [1994/11/10 05:28:35 dwm] ! 44: * ! 45: * Revision 1.2.28.1 1994/11/04 10:07:40 dwm ! 46: * mk6 CR668 - 1.3b26 merge ! 47: * * Revision 1.2.2.4 1993/11/08 15:04:18 gm ! 48: * CR9710: Updated to new zinit() and zone_change() interfaces. ! 49: * * End1.3merge ! 50: * [1994/11/04 09:25:48 dwm] ! 51: * ! 52: * Revision 1.2.19.3 1994/09/23 02:20:52 ezf ! 53: * change marker to not FREE ! 54: * [1994/09/22 21:33:57 ezf] ! 55: * ! 56: * Revision 1.2.19.2 1994/06/14 18:36:36 bolinger ! 57: * NMK17.2 merge: Replace simple_lock ops. ! 58: * [1994/06/14 18:35:17 bolinger] ! 59: * ! 60: * Revision 1.2.19.1 1994/06/14 17:04:23 bolinger ! 61: * Merge up to NMK17.2. ! 62: * [1994/06/14 16:54:19 bolinger] ! 63: * ! 64: * Revision 1.2.23.3 1994/10/14 12:24:33 sjs ! 65: * Removed krealloc_spinl routine: the newer locking scheme makes it ! 66: * obsolete. ! 67: * [94/10/13 sjs] ! 68: * ! 69: * Revision 1.2.23.2 1994/08/11 14:42:46 rwd ! 70: * Post merge cleanup ! 71: * [94/08/09 rwd] ! 72: * ! 73: * Changed zcollectable to use zchange. ! 74: * [94/08/04 rwd] ! 75: * ! 76: * Revision 1.2.17.2 1994/07/08 01:58:45 alanl ! 77: * Change comment to match function name. ! 78: * [1994/07/08 01:47:59 alanl] ! 79: * ! 80: * Revision 1.2.17.1 1994/05/26 16:20:38 sjs ! 81: * Added krealloc_spinl: same as krealloc but uses spin locks. ! 82: * [94/05/25 sjs] ! 83: * ! 84: * Revision 1.2.23.1 1994/08/04 02:24:55 mmp ! 85: * Added krealloc_spinl: same as krealloc but uses spin locks. ! 86: * [94/05/25 sjs] ! 87: * ! 88: * Revision 1.2.13.1 1994/02/11 14:27:12 paire ! 89: * Changed krealloc() to make it work on a MP system. Added a new parameter ! 90: * which is the simple lock that should be held while modifying the memory ! 91: * area already initialized. ! 92: * Change from NMK16.1 [93/09/02 paire] ! 93: * ! 94: * Do not set debug for kalloc zones as default. It wastes ! 95: * to much space. ! 96: * Change from NMK16.1 [93/08/16 bernadat] ! 97: * [94/02/07 paire] ! 98: * ! 99: * Revision 1.2.2.3 1993/07/28 17:15:44 bernard ! 100: * CR9523 -- Prototypes. ! 101: * [1993/07/27 20:14:12 bernard] ! 102: * ! 103: * Revision 1.2.2.2 1993/06/02 23:37:46 jeffc ! 104: * Added to OSF/1 R1.3 from NMK15.0. ! 105: * [1993/06/02 21:12:59 jeffc] ! 106: * ! 107: * Revision 1.2 1992/12/07 21:28:42 robert ! 108: * integrate any changes below for 14.0 (branch from 13.16 base) ! 109: * ! 110: * Joseph Barrera (jsb) at Carnegie-Mellon University 11-Sep-92 ! 111: * Added krealloc. Added kalloc_max_prerounded for quicker choice between ! 112: * zalloc and kmem_alloc. Renamed MINSIZE to KALLOC_MINSIZE. ! 113: * [1992/12/06 19:47:16 robert] ! 114: * ! 115: * Revision 1.1 1992/09/30 02:09:23 robert ! 116: * Initial revision ! 117: * ! 118: * $EndLog$ ! 119: */ ! 120: /* CMU_HIST */ ! 121: /* ! 122: * Revision 2.9 91/05/14 16:43:17 mrt ! 123: * Correcting copyright ! 124: * ! 125: * Revision 2.8 91/03/16 14:50:37 rpd ! 126: * Updated for new kmem_alloc interface. ! 127: * [91/03/03 rpd] ! 128: * ! 129: * Revision 2.7 91/02/05 17:27:22 mrt ! 130: * Changed to new Mach copyright ! 131: * [91/02/01 16:14:12 mrt] ! 132: * ! 133: * Revision 2.6 90/06/19 22:59:06 rpd ! 134: * Made the big kalloc zones collectable. ! 135: * [90/06/05 rpd] ! 136: * ! 137: * Revision 2.5 90/06/02 14:54:47 rpd ! 138: * Added kalloc_max, kalloc_map_size. ! 139: * [90/03/26 22:06:39 rpd] ! 140: * ! 141: * Revision 2.4 90/01/11 11:43:13 dbg ! 142: * De-lint. ! 143: * [89/12/06 dbg] ! 144: * ! 145: * Revision 2.3 89/09/08 11:25:51 dbg ! 146: * MACH_KERNEL: remove non-MACH data types. ! 147: * [89/07/11 dbg] ! 148: * ! 149: * Revision 2.2 89/08/31 16:18:59 rwd ! 150: * First Checkin ! 151: * [89/08/23 15:41:37 rwd] ! 152: * ! 153: * Revision 2.6 89/08/02 08:03:28 jsb ! 154: * Make all kalloc zones 8 MB big. (No more kalloc panics!) ! 155: * [89/08/01 14:10:17 jsb] ! 156: * ! 157: * Revision 2.4 89/04/05 13:03:10 rvb ! 158: * Guarantee a zone max of at least 100 elements or 10 pages ! 159: * which ever is greater. Afs (AllocDouble()) puts a great demand ! 160: * on the 2048 zone and used to blow away. ! 161: * [89/03/09 rvb] ! 162: * ! 163: * Revision 2.3 89/02/25 18:04:39 gm0w ! 164: * Changes for cleanup. ! 165: * ! 166: * Revision 2.2 89/01/18 02:07:04 jsb ! 167: * Give each kalloc zone a meaningful name (for panics); ! 168: * create a zone for each power of 2 between MINSIZE ! 169: * and PAGE_SIZE, instead of using (obsoleted) NQUEUES. ! 170: * [89/01/17 10:16:33 jsb] ! 171: * ! 172: * ! 173: * 13-Feb-88 John Seamons (jks) at NeXT ! 174: * Updated to use kmem routines instead of vmem routines. ! 175: * ! 176: * 21-Jun-85 Avadis Tevanian (avie) at Carnegie-Mellon University ! 177: * Created. ! 178: */ ! 179: /* CMU_ENDHIST */ ! 180: /* ! 181: * Mach Operating System ! 182: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University ! 183: * All Rights Reserved. ! 184: * ! 185: * Permission to use, copy, modify and distribute this software and its ! 186: * documentation is hereby granted, provided that both the copyright ! 187: * notice and this permission notice appear in all copies of the ! 188: * software, derivative works or modified versions, and any portions ! 189: * thereof, and that both notices appear in supporting documentation. ! 190: * ! 191: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 192: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 193: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 194: * ! 195: * Carnegie Mellon requests users of this software to return to ! 196: * ! 197: * Software Distribution Coordinator or [email protected] ! 198: * School of Computer Science ! 199: * Carnegie Mellon University ! 200: * Pittsburgh PA 15213-3890 ! 201: * ! 202: * any improvements or extensions that they make and grant Carnegie Mellon ! 203: * the rights to redistribute these changes. ! 204: */ ! 205: /* ! 206: */ ! 207: /* ! 208: * File: kern/kalloc.c ! 209: * Author: Avadis Tevanian, Jr. ! 210: * Date: 1985 ! 211: * ! 212: * General kernel memory allocator. This allocator is designed ! 213: * to be used by the kernel to manage dynamic memory fast. ! 214: */ ! 215: ! 216: #include <zone_debug.h> ! 217: ! 218: #include <mach/boolean.h> ! 219: #include <mach/machine/vm_types.h> ! 220: #include <mach/vm_param.h> ! 221: #include <kern/misc_protos.h> ! 222: #include <kern/zalloc.h> ! 223: #include <kern/kalloc.h> ! 224: #include <kern/lock.h> ! 225: #include <vm/vm_kern.h> ! 226: #include <vm/vm_object.h> ! 227: #include <vm/vm_map.h> ! 228: ! 229: #ifdef MACH_BSD ! 230: zone_t kalloc_zone(vm_size_t); ! 231: #endif ! 232: ! 233: vm_map_t kalloc_map; ! 234: vm_size_t kalloc_map_size = 8 * 1024 * 1024; ! 235: vm_size_t kalloc_max; ! 236: vm_size_t kalloc_max_prerounded; ! 237: ! 238: /* ! 239: * All allocations of size less than kalloc_max are rounded to the ! 240: * next highest power of 2. This allocator is built on top of ! 241: * the zone allocator. A zone is created for each potential size ! 242: * that we are willing to get in small blocks. ! 243: * ! 244: * We assume that kalloc_max is not greater than 64K; ! 245: * thus 16 is a safe array size for k_zone and k_zone_name. ! 246: * ! 247: * Note that kalloc_max is somewhat confusingly named. ! 248: * It represents the first power of two for which no zone exists. ! 249: * kalloc_max_prerounded is the smallest allocation size, before ! 250: * rounding, for which no zone exists. ! 251: */ ! 252: ! 253: int first_k_zone = -1; ! 254: struct zone *k_zone[16]; ! 255: static char *k_zone_name[16] = { ! 256: "kalloc.1", "kalloc.2", ! 257: "kalloc.4", "kalloc.8", ! 258: "kalloc.16", "kalloc.32", ! 259: "kalloc.64", "kalloc.128", ! 260: "kalloc.256", "kalloc.512", ! 261: "kalloc.1024", "kalloc.2048", ! 262: "kalloc.4096", "kalloc.8192", ! 263: "kalloc.16384", "kalloc.32768" ! 264: }; ! 265: ! 266: /* ! 267: * Max number of elements per zone. zinit rounds things up correctly ! 268: * Doing things this way permits each zone to have a different maximum size ! 269: * based on need, rather than just guessing; it also ! 270: * means its patchable in case you're wrong! ! 271: */ ! 272: unsigned long k_zone_max[16] = { ! 273: 1024, /* 1 Byte */ ! 274: 1024, /* 2 Byte */ ! 275: 1024, /* 4 Byte */ ! 276: 1024, /* 8 Byte */ ! 277: 1024, /* 16 Byte */ ! 278: 4096, /* 32 Byte */ ! 279: 4096, /* 64 Byte */ ! 280: 4096, /* 128 Byte */ ! 281: 4096, /* 256 Byte */ ! 282: 1024, /* 512 Byte */ ! 283: 1024, /* 1024 Byte */ ! 284: 1024, /* 2048 Byte */ ! 285: 1024, /* 4096 Byte */ ! 286: 4096, /* 8192 Byte */ ! 287: 64, /* 16384 Byte */ ! 288: 64, /* 32768 Byte */ ! 289: }; ! 290: ! 291: /* ! 292: * Initialize the memory allocator. This should be called only ! 293: * once on a system wide basis (i.e. first processor to get here ! 294: * does the initialization). ! 295: * ! 296: * This initializes all of the zones. ! 297: */ ! 298: ! 299: void ! 300: kalloc_init( ! 301: void) ! 302: { ! 303: kern_return_t retval; ! 304: vm_offset_t min; ! 305: vm_size_t size; ! 306: register int i; ! 307: ! 308: retval = kmem_suballoc(kernel_map, &min, kalloc_map_size, ! 309: FALSE, TRUE, &kalloc_map); ! 310: if (retval != KERN_SUCCESS) ! 311: panic("kalloc_init: kmem_suballoc failed"); ! 312: ! 313: /* ! 314: * Ensure that zones up to size 8192 bytes exist. ! 315: * This is desirable because messages are allocated ! 316: * with kalloc, and messages up through size 8192 are common. ! 317: */ ! 318: ! 319: if (PAGE_SIZE < 16*1024) ! 320: kalloc_max = 16*1024; ! 321: else ! 322: kalloc_max = PAGE_SIZE; ! 323: kalloc_max_prerounded = kalloc_max / 2 + 1; ! 324: ! 325: /* ! 326: * Allocate a zone for each size we are going to handle. ! 327: * We specify non-paged memory. ! 328: */ ! 329: for (i = 0, size = 1; size < kalloc_max; i++, size <<= 1) { ! 330: if (size < KALLOC_MINSIZE) { ! 331: k_zone[i] = 0; ! 332: continue; ! 333: } ! 334: if (size == KALLOC_MINSIZE) { ! 335: first_k_zone = i; ! 336: } ! 337: k_zone[i] = zinit(size, k_zone_max[i] * size, size, ! 338: k_zone_name[i]); ! 339: } ! 340: } ! 341: ! 342: vm_offset_t ! 343: kalloc( ! 344: vm_size_t size) ! 345: { ! 346: register int zindex; ! 347: register vm_size_t allocsize; ! 348: ! 349: /* ! 350: * If size is too large for a zone, then use kmem_alloc. ! 351: * (We use kmem_alloc instead of kmem_alloc_wired so that ! 352: * krealloc can use kmem_realloc.) ! 353: */ ! 354: ! 355: if (size >= kalloc_max_prerounded) { ! 356: vm_offset_t addr; ! 357: ! 358: if (kmem_alloc(kalloc_map, &addr, size) != KERN_SUCCESS) ! 359: addr = 0; ! 360: return(addr); ! 361: } ! 362: ! 363: /* compute the size of the block that we will actually allocate */ ! 364: ! 365: allocsize = KALLOC_MINSIZE; ! 366: zindex = first_k_zone; ! 367: while (allocsize < size) { ! 368: allocsize <<= 1; ! 369: zindex++; ! 370: } ! 371: ! 372: /* allocate from the appropriate zone */ ! 373: ! 374: assert(allocsize < kalloc_max); ! 375: return(zalloc(k_zone[zindex])); ! 376: } ! 377: ! 378: void ! 379: krealloc( ! 380: vm_offset_t *addrp, ! 381: vm_size_t old_size, ! 382: vm_size_t new_size, ! 383: simple_lock_t lock) ! 384: { ! 385: register int zindex; ! 386: register vm_size_t allocsize; ! 387: vm_offset_t naddr; ! 388: ! 389: /* can only be used for increasing allocation size */ ! 390: ! 391: assert(new_size > old_size); ! 392: ! 393: /* if old_size is zero, then we are simply allocating */ ! 394: ! 395: if (old_size == 0) { ! 396: simple_unlock(lock); ! 397: naddr = kalloc(new_size); ! 398: simple_lock(lock); ! 399: *addrp = naddr; ! 400: return; ! 401: } ! 402: ! 403: /* if old block was kmem_alloc'd, then use kmem_realloc if necessary */ ! 404: ! 405: if (old_size >= kalloc_max_prerounded) { ! 406: old_size = round_page(old_size); ! 407: new_size = round_page(new_size); ! 408: if (new_size > old_size) { ! 409: ! 410: if (kmem_realloc(kalloc_map, *addrp, old_size, &naddr, ! 411: ! 412: ! 413: ! 414: ! 415: new_size) != KERN_SUCCESS) { ! 416: panic("krealloc: kmem_realloc"); ! 417: naddr = 0; ! 418: } ! 419: ! 420: simple_lock(lock); ! 421: *addrp = naddr; ! 422: ! 423: /* kmem_realloc() doesn't free old page range. */ ! 424: kmem_free(kalloc_map, *addrp, old_size); ! 425: } ! 426: return; ! 427: } ! 428: ! 429: /* compute the size of the block that we actually allocated */ ! 430: ! 431: allocsize = KALLOC_MINSIZE; ! 432: zindex = first_k_zone; ! 433: while (allocsize < old_size) { ! 434: allocsize <<= 1; ! 435: zindex++; ! 436: } ! 437: ! 438: /* if new size fits in old block, then return */ ! 439: ! 440: if (new_size <= allocsize) { ! 441: return; ! 442: } ! 443: ! 444: /* if new size does not fit in zone, kmem_alloc it, else zalloc it */ ! 445: ! 446: simple_unlock(lock); ! 447: if (new_size >= kalloc_max_prerounded) { ! 448: if (kmem_alloc(kalloc_map, &naddr, new_size) != KERN_SUCCESS) { ! 449: panic("krealloc: kmem_alloc"); ! 450: simple_lock(lock); ! 451: *addrp = 0; ! 452: return; ! 453: } ! 454: } else { ! 455: register int new_zindex; ! 456: ! 457: allocsize <<= 1; ! 458: new_zindex = zindex + 1; ! 459: while (allocsize < new_size) { ! 460: allocsize <<= 1; ! 461: new_zindex++; ! 462: } ! 463: naddr = zalloc(k_zone[new_zindex]); ! 464: } ! 465: simple_lock(lock); ! 466: ! 467: /* copy existing data */ ! 468: ! 469: bcopy((const char *)*addrp, (char *)naddr, old_size); ! 470: ! 471: /* free old block, and return */ ! 472: ! 473: zfree(k_zone[zindex], *addrp); ! 474: ! 475: /* set up new address */ ! 476: ! 477: *addrp = naddr; ! 478: } ! 479: ! 480: ! 481: vm_offset_t ! 482: kget( ! 483: vm_size_t size) ! 484: { ! 485: register int zindex; ! 486: register vm_size_t allocsize; ! 487: ! 488: /* size must not be too large for a zone */ ! 489: ! 490: if (size >= kalloc_max_prerounded) { ! 491: /* This will never work, so we might as well panic */ ! 492: panic("kget"); ! 493: } ! 494: ! 495: /* compute the size of the block that we will actually allocate */ ! 496: ! 497: allocsize = KALLOC_MINSIZE; ! 498: zindex = first_k_zone; ! 499: while (allocsize < size) { ! 500: allocsize <<= 1; ! 501: zindex++; ! 502: } ! 503: ! 504: /* allocate from the appropriate zone */ ! 505: ! 506: assert(allocsize < kalloc_max); ! 507: return(zget(k_zone[zindex])); ! 508: } ! 509: ! 510: void ! 511: kfree( ! 512: vm_offset_t data, ! 513: vm_size_t size) ! 514: { ! 515: register int zindex; ! 516: register vm_size_t freesize; ! 517: ! 518: /* if size was too large for a zone, then use kmem_free */ ! 519: ! 520: if (size >= kalloc_max_prerounded) { ! 521: kmem_free(kalloc_map, data, size); ! 522: return; ! 523: } ! 524: ! 525: /* compute the size of the block that we actually allocated from */ ! 526: ! 527: freesize = KALLOC_MINSIZE; ! 528: zindex = first_k_zone; ! 529: while (freesize < size) { ! 530: freesize <<= 1; ! 531: zindex++; ! 532: } ! 533: ! 534: /* free to the appropriate zone */ ! 535: ! 536: assert(freesize < kalloc_max); ! 537: zfree(k_zone[zindex], data); ! 538: } ! 539: ! 540: #ifdef MACH_BSD ! 541: zone_t ! 542: kalloc_zone( ! 543: vm_size_t size) ! 544: { ! 545: register int zindex = 0; ! 546: register vm_size_t allocsize; ! 547: ! 548: /* compute the size of the block that we will actually allocate */ ! 549: ! 550: allocsize = size; ! 551: if (size <= kalloc_max) { ! 552: allocsize = KALLOC_MINSIZE; ! 553: zindex = first_k_zone; ! 554: while (allocsize < size) { ! 555: allocsize <<= 1; ! 556: zindex++; ! 557: } ! 558: return (k_zone[zindex]); ! 559: } ! 560: return (ZONE_NULL); ! 561: } ! 562: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.