1/*
2 * Copyright (c) 2005-2007 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29/*
30 * DTrace kalloc emulation.
31 *
32 * This is a subset of kalloc functionality, to allow dtrace
33 * specific allocation to be accounted for separately from the
34 * general kalloc pool.
35 *
36 * Note that allocations greater than dalloc_max still go into
37 * the kalloc.large bucket, as it seems impossible to emulate
38 * that functionality in the bsd kern.
39 */
40
41#include <stdarg.h>
42#include <string.h>
43#include <sys/malloc.h>
44#include <sys/dtrace.h>
45#include <kern/zalloc.h>
46
47#if defined(DTRACE_MEMORY_ZONES)
48
49#define DTRACE_ALLOC_MINSIZE 16
50
51vm_size_t dtrace_alloc_max;
52vm_size_t dtrace_alloc_max_prerounded;
53int first_d_zone = -1;
54struct zone *d_zone[16];
55static const char *d_zone_name[16] = {
56	"dtrace.1",		"dtrace.2",
57	"dtrace.4",		"dtrace.8",
58	"dtrace.16",		"dtrace.32",
59	"dtrace.64",		"dtrace.128",
60	"dtrace.256",		"dtrace.512",
61	"dtrace.1024",		"dtrace.2048",
62	"dtrace.4096",		"dtrace.8192",
63	"dtrace.16384",		"dtrace.32768"
64};
65
66unsigned long d_zone_max[16] = {
67      1024,		/*      1 Byte  */
68      1024,		/*      2 Byte  */
69      1024,		/*      4 Byte  */
70      1024,		/*      8 Byte  */
71      1024,		/*     16 Byte  */
72      4096,		/*     32 Byte  */
73      4096,		/*     64 Byte  */
74      4096,		/*    128 Byte  */
75      4096,		/*    256 Byte  */
76      1024,		/*    512 Byte  */
77      1024,		/*   1024 Byte  */
78      1024,		/*   2048 Byte  */
79      1024,		/*   4096 Byte  */
80      4096,		/*   8192 Byte  */
81      64,		/*  16384 Byte  */
82      64,		/*  32768 Byte  */
83};
84
85void dtrace_alloc_init(void)
86{
87	vm_size_t size;
88	int i;
89
90	if (PAGE_SIZE < 16*1024)
91		dtrace_alloc_max = 16*1024;
92	else
93		dtrace_alloc_max = PAGE_SIZE;
94	dtrace_alloc_max_prerounded = dtrace_alloc_max / 2 + 1;
95
96	/*
97	 *	Allocate a zone for each size we are going to handle.
98	 *	We specify non-paged memory.
99	 */
100	for (i = 0, size = 1; size < dtrace_alloc_max; i++, size <<= 1) {
101		if (size < DTRACE_ALLOC_MINSIZE) {
102			d_zone[i] = NULL;
103			continue;
104		}
105		if (size == DTRACE_ALLOC_MINSIZE) {
106			first_d_zone = i;
107		}
108		d_zone[i] = zinit(size, d_zone_max[i] * size, size, d_zone_name[i]);
109	}
110}
111
112void *dtrace_alloc(vm_size_t size)
113{
114	int zindex;
115	vm_size_t allocsize;
116
117	/*
118	 * If size is too large for a zone, then use kmem_alloc.
119	 * (We use kmem_alloc instead of kmem_alloc_kobject so that
120	 * krealloc can use kmem_realloc.)
121	 */
122
123	if (size >= dtrace_alloc_max_prerounded) {
124		return _MALLOC(size, M_TEMP, M_WAITOK);
125	}
126
127	/* compute the size of the block that we will actually allocate */
128	allocsize = DTRACE_ALLOC_MINSIZE;
129	zindex = first_d_zone;
130	while (allocsize < size) {
131		allocsize <<= 1;
132		zindex++;
133	}
134
135	return(zalloc_canblock(d_zone[zindex], TRUE));
136}
137
138void dtrace_free(void *data, vm_size_t size)
139{
140	int zindex;
141	vm_size_t freesize;
142
143	if (size >= dtrace_alloc_max_prerounded) {
144		_FREE(data, M_TEMP);
145		return;
146	}
147
148	/* compute the size of the block that we actually allocated from */
149	freesize = DTRACE_ALLOC_MINSIZE;
150	zindex = first_d_zone;
151	while (freesize < size) {
152		freesize <<= 1;
153		zindex++;
154	}
155
156	/* free to the appropriate zone */
157	zfree(d_zone[zindex], data);
158}
159
160#endif /* DTRACE_MEMORY_ZONES */
161