xref: /csrg-svn/sys/kern/kern_malloc.c (revision 45000)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_malloc.c	7.19 (Berkeley) 07/27/90
8  */
9 
10 #include "param.h"
11 #include "vm.h"
12 #include "cmap.h"
13 #include "time.h"
14 #include "proc.h"
15 #include "map.h"
16 #include "kernel.h"
17 #include "malloc.h"
18 
19 #include "machine/pte.h"
20 
21 struct kmembuckets bucket[MINBUCKET + 16];
22 struct kmemstats kmemstats[M_LAST];
23 struct kmemusage *kmemusage;
24 long wantkmemmap;
25 
26 /*
27  * Allocate a block of memory
28  */
29 qaddr_t
30 malloc(size, type, flags)
31 	unsigned long size;
32 	int type, flags;
33 {
34 	register struct kmembuckets *kbp;
35 	register struct kmemusage *kup;
36 	long indx, npg, alloc, allocsize;
37 	int s;
38 	caddr_t va, cp;
39 #ifdef KMEMSTATS
40 	register struct kmemstats *ksp = &kmemstats[type];
41 
42 	if (((unsigned long)type) > M_LAST)
43 		panic("malloc - bogus type");
44 #endif
45 
46 	indx = BUCKETINDX(size);
47 	kbp = &bucket[indx];
48 	s = splimp();
49 again:
50 #ifdef KMEMSTATS
51 	while (ksp->ks_memuse >= ksp->ks_limit) {
52 		if (flags & M_NOWAIT) {
53 			splx(s);
54 			return (0);
55 		}
56 		if (ksp->ks_limblocks < 65535)
57 			ksp->ks_limblocks++;
58 		sleep((caddr_t)ksp, PSWP+2);
59 	}
60 #endif
61 	if (kbp->kb_next == NULL) {
62 		if (size > MAXALLOCSAVE)
63 			allocsize = roundup(size, CLBYTES);
64 		else
65 			allocsize = 1 << indx;
66 		npg = clrnd(btoc(allocsize));
67 		if ((flags & M_NOWAIT) && freemem < npg) {
68 			splx(s);
69 			return (0);
70 		}
71 		alloc = rmalloc(kmemmap, npg);
72 		if (alloc == 0) {
73 			if (flags & M_NOWAIT) {
74 				splx(s);
75 				return (0);
76 			}
77 #ifdef KMEMSTATS
78 			if (ksp->ks_mapblocks < 65535)
79 				ksp->ks_mapblocks++;
80 #endif
81 			wantkmemmap++;
82 			sleep((caddr_t)&wantkmemmap, PSWP+2);
83 			goto again;
84 		}
85 		alloc -= CLSIZE;		/* convert to base 0 */
86 		(void) vmemall(&kmempt[alloc], (int)npg, &proc[0], CSYS);
87 		va = (caddr_t) kmemxtob(alloc);
88 		vmaccess(&kmempt[alloc], va, (int)npg);
89 #ifdef KMEMSTATS
90 		kbp->kb_total += kbp->kb_elmpercl;
91 #endif
92 		kup = btokup(va);
93 		kup->ku_indx = indx;
94 		if (allocsize > MAXALLOCSAVE) {
95 			if (npg > 65535)
96 				panic("malloc: allocation too large");
97 			kup->ku_pagecnt = npg;
98 #ifdef KMEMSTATS
99 			ksp->ks_memuse += allocsize;
100 #endif
101 			goto out;
102 		}
103 #ifdef KMEMSTATS
104 		kup->ku_freecnt = kbp->kb_elmpercl;
105 		kbp->kb_totalfree += kbp->kb_elmpercl;
106 #endif
107 		kbp->kb_next = va + (npg * NBPG) - allocsize;
108 		for (cp = kbp->kb_next; cp > va; cp -= allocsize)
109 			*(caddr_t *)cp = cp - allocsize;
110 		*(caddr_t *)cp = NULL;
111 	}
112 	va = kbp->kb_next;
113 	kbp->kb_next = *(caddr_t *)va;
114 #ifdef KMEMSTATS
115 	kup = btokup(va);
116 	if (kup->ku_indx != indx)
117 		panic("malloc: wrong bucket");
118 	if (kup->ku_freecnt == 0)
119 		panic("malloc: lost data");
120 	kup->ku_freecnt--;
121 	kbp->kb_totalfree--;
122 	ksp->ks_memuse += 1 << indx;
123 out:
124 	kbp->kb_calls++;
125 	ksp->ks_inuse++;
126 	ksp->ks_calls++;
127 	if (ksp->ks_memuse > ksp->ks_maxused)
128 		ksp->ks_maxused = ksp->ks_memuse;
129 #else
130 out:
131 #endif
132 	splx(s);
133 	return ((qaddr_t)va);
134 }
135 
136 #ifdef DIAGNOSTIC
137 long addrmask[] = { 0x00000000,
138 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
139 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
140 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
141 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
142 };
143 #endif /* DIAGNOSTIC */
144 
145 /*
146  * Free a block of memory allocated by malloc.
147  */
148 void
149 free(addr, type)
150 	caddr_t addr;
151 	int type;
152 {
153 	register struct kmembuckets *kbp;
154 	register struct kmemusage *kup;
155 	long alloc, size;
156 	int s;
157 #ifdef KMEMSTATS
158 	register struct kmemstats *ksp = &kmemstats[type];
159 #endif
160 
161 	kup = btokup(addr);
162 	size = 1 << kup->ku_indx;
163 #ifdef DIAGNOSTIC
164 	if (size > NBPG * CLSIZE)
165 		alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)];
166 	else
167 		alloc = addrmask[kup->ku_indx];
168 	if (((u_long)addr & alloc) != 0) {
169 		printf("free: unaligned addr 0x%x, size %d, type %d, mask %d\n",
170 			addr, size, type, alloc);
171 		panic("free: unaligned addr");
172 	}
173 #endif /* DIAGNOSTIC */
174 	kbp = &bucket[kup->ku_indx];
175 	s = splimp();
176 	if (size > MAXALLOCSAVE) {
177 		alloc = btokmemx(addr);
178 		(void) memfree(&kmempt[alloc], (int)kup->ku_pagecnt, 1);
179 		rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE);
180 		if (wantkmemmap) {
181 			wakeup((caddr_t)&wantkmemmap);
182 			wantkmemmap = 0;
183 		}
184 #ifdef KMEMSTATS
185 		size = kup->ku_pagecnt << PGSHIFT;
186 		ksp->ks_memuse -= size;
187 		kup->ku_indx = 0;
188 		kup->ku_pagecnt = 0;
189 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
190 		    ksp->ks_memuse < ksp->ks_limit)
191 			wakeup((caddr_t)ksp);
192 		ksp->ks_inuse--;
193 		kbp->kb_total -= 1;
194 #endif
195 		splx(s);
196 		return;
197 	}
198 #ifdef KMEMSTATS
199 	kup->ku_freecnt++;
200 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
201 		if (kup->ku_freecnt > kbp->kb_elmpercl)
202 			panic("free: multiple frees");
203 		else if (kbp->kb_totalfree > kbp->kb_highwat)
204 			kbp->kb_couldfree++;
205 	kbp->kb_totalfree++;
206 	ksp->ks_memuse -= size;
207 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
208 	    ksp->ks_memuse < ksp->ks_limit)
209 		wakeup((caddr_t)ksp);
210 	ksp->ks_inuse--;
211 #endif
212 	*(caddr_t *)addr = kbp->kb_next;
213 	kbp->kb_next = addr;
214 	splx(s);
215 }
216 
217 /*
218  * Initialize the kernel memory allocator
219  */
220 kmeminit()
221 {
222 	register long indx;
223 	int npg;
224 
225 #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
226 		ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
227 #endif
228 #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
229 		ERROR!_kmeminit:_MAXALLOCSAVE_too_big
230 #endif
231 #if	(MAXALLOCSAVE < CLBYTES)
232 		ERROR!_kmeminit:_MAXALLOCSAVE_too_small
233 #endif
234 	npg = ekmempt - kmempt;
235 	rminit(kmemmap, (long)npg, (long)CLSIZE, "malloc map", npg);
236 #ifdef KMEMSTATS
237 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
238 		if (1 << indx >= CLBYTES)
239 			bucket[indx].kb_elmpercl = 1;
240 		else
241 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
242 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
243 	}
244 	for (indx = 0; indx < M_LAST; indx++)
245 		kmemstats[indx].ks_limit = npg * NBPG * 6 / 10;
246 #endif
247 }
248