Source to kern/kalloc.c


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_LICENSE_HEADER_START@
 * 
 * "Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
 * Reserved.  This file contains Original Code and/or Modifications of
 * Original Code as defined in and that are subject to the Apple Public
 * Source License Version 1.0 (the 'License').  You may not use this file
 * except in compliance with the License.  Please obtain a copy of the
 * License at http://www.apple.com/publicsource and read it before using
 * this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License."
 * 
 * @APPLE_LICENSE_HEADER_END@
 */

/* 
 * Mach Operating System
 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  [email protected]
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 *	File:	kern/kalloc.c
 *	Author:	Avadis Tevanian, Jr.
 *	Date:	1985
 *
 *	General kernel memory allocator.  This allocator is designed
 *	to be used by the kernel to manage dynamic memory fast.
 */

#include <mach/machine/vm_types.h>
#include <mach/vm_param.h>

#include <kern/zalloc.h>
#include <kern/kalloc.h>
#include <vm/vm_kern.h>
#include <vm/vm_object.h>
#include <vm/vm_map.h>

vm_map_t kalloc_map;

/*
 *	All allocations of size less than kalloc_max are rounded to the
 *	next highest power of 2.  This allocator is built on top of
 *	the zone allocator.  A zone is created for each potential size
 *	that we are willing to get in small blocks.
 *
 *	We assume that kalloc_max is not greater than 64K;
 *	thus 16 is a safe array size for k_zone and k_zone_name.
 */

#define	NKSIZE	16
vm_size_t k_zone_maxsize;
struct zone *k_zone[NKSIZE];
static char k_zone_name[NKSIZE][16];
vm_size_t k_zone_elemsize[NKSIZE] = {
	16, 32, 48, 64, 80, 128, 256, 384, 512,
	1024, 2048, 3072, 4096, 8192, 12288, 16384
};

#if DIAGNOSTIC
/*
 * Be careful with ZALLOC0!  It seems that kdp now has a subtle dependency
 * on allocated memory not being initialized.  If you do use it you'll need
 * to enter gdb with cmd-Power and even then you may see a "SIGTRAP".
 */
#if ZALLOC0
void    *memset __P((void *, int, size_t));
#endif
#endif


/*
 *	Initialize the memory allocator.  This should be called only
 *	once on a system wide basis (i.e. first processor to get here
 *	does the initialization).
 *
 *	This initializes all of the zones.
 */

void kalloc_init(void)
{
	vm_size_t size;
	register int i;
	
	kalloc_map = kernel_map;

	/*
	 *	Allocate a zone for each size we are going to handle.
	 *	We specify non-paged memory.
	 */
	for (i = 0; i < NKSIZE; i++) {
		if ((size = k_zone_elemsize[i]) >= PAGE_SIZE)
			break;
		sprintf (k_zone_name[i], "kalloc.%d", size);
		k_zone[i] = zinit(size, 1024*1024, PAGE_SIZE,
			FALSE, k_zone_name[i]);
		k_zone_maxsize = size;
	}
}

vm_offset_t kalloc_noblock(size)
	vm_size_t size;
{
	register int zindex = 0;
	register vm_size_t allocsize;
	vm_offset_t addr;

	/* compute the size of the block that we will actually allocate */

	allocsize = size;
	if (size <= k_zone_maxsize) {
		allocsize = k_zone_elemsize[0];
		zindex = 0;
		while (allocsize < size) {
			allocsize = k_zone_elemsize[++zindex];
		}
	}

	/*
	 * If our size is still small enough, check the queue for that size
	 * and allocate.
	 */

	if (allocsize <= k_zone_maxsize) {
		addr = zalloc_noblock(k_zone[zindex]);
#if DIAGNOSTIC
#if ZALLOC0
		(void) memset((void *)addr, 0, (size_t) size);
#endif
#endif
	} else {
		if (kmem_alloc_zone(kalloc_map, &addr, allocsize, FALSE)
							    != KERN_SUCCESS)
			addr = 0;
	}

	return(addr);
}

vm_offset_t kalloc(size)
	vm_size_t size;
{
	register int zindex = 0;
	register vm_size_t allocsize;
	vm_offset_t addr;

	/* compute the size of the block that we will actually allocate */
	allocsize = size;
	if (size <= k_zone_maxsize) {
		allocsize = k_zone_elemsize[0];
		zindex = 0;
		while (allocsize < size) {
			allocsize = k_zone_elemsize[++zindex];
		}
	}

	/*
	 * If our size is still small enough, check the queue for that size
	 * and allocate.
	 */

	if (allocsize <= k_zone_maxsize) {
		addr = zalloc(k_zone[zindex]);
#if DIAGNOSTIC
#if ZALLOC0
		(void) memset((void *)addr, 0, (size_t) size);
#endif
#endif
	} else {
		if (kmem_alloc_wired(kalloc_map, &addr, allocsize)
							!= KERN_SUCCESS)
			addr = 0;
	}
	return(addr);
}

vm_offset_t kget(size)
	vm_size_t size;
{
	register int zindex = 0;
	register vm_size_t allocsize;
	vm_offset_t addr = 0;

	/* compute the size of the block that we will actually allocate */
	allocsize = size;
	if (size <= k_zone_maxsize) {
		allocsize = k_zone_elemsize[0];
		zindex = 0;
		while (allocsize < size) {
			allocsize = k_zone_elemsize[++zindex];
		}
	}

	/*
	 * If our size is still small enough, check the queue for that size
	 * and allocate.
	 */

	if (allocsize <= k_zone_maxsize) {
		addr = zget(k_zone[zindex]);
	} else {
		/* This will never work, so we might as well panic */
		panic("kget");
	}
	return(addr);
}

void 
kfree(data, size)
	vm_offset_t data;
	vm_size_t size;
{
	register int zindex = 0;
	register vm_size_t freesize;

	freesize = size;
	if (size <= k_zone_maxsize) {
		freesize = k_zone_elemsize[0];
		zindex = 0;
		while (freesize < size) {
			freesize = k_zone_elemsize[++zindex];
		}
	}

	if (freesize <= k_zone_maxsize) {
		zfree(k_zone[zindex], data);
	} else {
		kmem_free(kalloc_map, data, freesize);
	}
}

struct zone *kalloc_zone(
	vm_size_t	size)
{
	register int zindex = 0;
	register vm_size_t allocsize;

	/* compute the size of the block that we will actually allocate */

	allocsize = size;
	if (size <= k_zone_maxsize) {
		allocsize = k_zone_elemsize[0];
		zindex = 0;
		while (allocsize < size) {
			allocsize = k_zone_elemsize[++zindex];
		}

		return (k_zone[zindex]);
	}

	return (0);
}