xref: /csrg-svn/sys/kern/kern_malloc.c (revision 39711)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that the above copyright notice and this paragraph are
7  * duplicated in all such forms and that any documentation,
8  * advertising materials, and other materials related to such
9  * distribution and use acknowledge that the software was developed
10  * by the University of California, Berkeley.  The name of the
11  * University may not be used to endorse or promote products derived
12  * from this software without specific prior written permission.
13  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
16  *
17  *	@(#)kern_malloc.c	7.12.1.1 (Berkeley) 12/14/89
18  */
19 
20 #include "param.h"
21 #include "vm.h"
22 #include "cmap.h"
23 #include "time.h"
24 #include "proc.h"
25 #include "map.h"
26 #include "kernel.h"
27 #include "malloc.h"
28 
29 #include "machine/pte.h"
30 
31 struct kmembuckets bucket[MINBUCKET + 16];
32 struct kmemstats kmemstats[M_LAST];
33 struct kmemusage *kmemusage;
34 long wantkmemmap;
35 long malloc_reentered;
36 #define IN { if (malloc_reentered) panic("malloc reentered");\
37 			else malloc_reentered = 1;}
38 #define OUT (malloc_reentered = 0)
39 
40 /*
41  * Allocate a block of memory
42  */
43 qaddr_t
44 malloc(size, type, flags)
45 	unsigned long size;
46 	int type, flags;
47 {
48 	register struct kmembuckets *kbp;
49 	register struct kmemusage *kup;
50 	long indx, npg, alloc, allocsize;
51 	int s;
52 	caddr_t va, cp;
53 #ifdef KMEMSTATS
54 	register struct kmemstats *ksp = &kmemstats[type];
55 #if defined(ISO) || defined(TPIP)
56 	if (((unsigned int)type) > M_LAST)
57 		panic("malloc - bogus type");
58 #endif
59 #endif
60 
61 	indx = BUCKETINDX(size);
62 	kbp = &bucket[indx];
63 	s = splimp();
64 	IN;
65 again:
66 #ifdef KMEMSTATS
67 	while (ksp->ks_memuse >= ksp->ks_limit) {
68 		if (flags & M_NOWAIT) {
69 			OUT;
70 			splx(s);
71 			return (0);
72 		}
73 		if (ksp->ks_limblocks < 65535)
74 			ksp->ks_limblocks++;
75 		OUT;
76 		sleep((caddr_t)ksp, PSWP+2);
77 		IN;
78 	}
79 #endif
80 	if (kbp->kb_next == NULL) {
81 		if (size > MAXALLOCSAVE)
82 			allocsize = roundup(size, CLBYTES);
83 		else
84 			allocsize = 1 << indx;
85 		npg = clrnd(btoc(allocsize));
86 		if ((flags & M_NOWAIT) && freemem < npg) {
87 			OUT;
88 			splx(s);
89 			return (0);
90 		}
91 		alloc = rmalloc(kmemmap, npg);
92 		if (alloc == 0) {
93 			if (flags & M_NOWAIT) {
94 				OUT;
95 				splx(s);
96 				return (0);
97 			}
98 #ifdef KMEMSTATS
99 			if (ksp->ks_mapblocks < 65535)
100 				ksp->ks_mapblocks++;
101 #endif
102 			wantkmemmap++;
103 			OUT;
104 			sleep((caddr_t)&wantkmemmap, PSWP+2);
105 			IN;
106 			goto again;
107 		}
108 		alloc -= CLSIZE;		/* convert to base 0 */
109 		(void) vmemall(&kmempt[alloc], (int)npg, &proc[0], CSYS);
110 		va = (caddr_t) kmemxtob(alloc);
111 		vmaccess(&kmempt[alloc], va, (int)npg);
112 #ifdef KMEMSTATS
113 		kbp->kb_total += kbp->kb_elmpercl;
114 #endif
115 		kup = btokup(va);
116 		kup->ku_indx = indx;
117 		if (allocsize > MAXALLOCSAVE) {
118 			if (npg > 65535)
119 				panic("malloc: allocation too large");
120 			kup->ku_pagecnt = npg;
121 #ifdef KMEMSTATS
122 			ksp->ks_memuse += allocsize;
123 #endif
124 			goto out;
125 		}
126 #ifdef KMEMSTATS
127 		kup->ku_freecnt = kbp->kb_elmpercl;
128 		kbp->kb_totalfree += kbp->kb_elmpercl;
129 #endif
130 		kbp->kb_next = va + (npg * NBPG) - allocsize;
131 		for (cp = kbp->kb_next; cp >= va; cp -= allocsize) {
132 			((caddr_t *)cp)[2] = (cp > va ? cp - allocsize : NULL);
133 			if (indx == 7) {
134 				long *lp = (long *)cp;
135 				lp[0] = lp[1] = lp[3] = lp[4] = -1;
136 			}
137 		}
138 	}
139 	va = kbp->kb_next;
140 	kbp->kb_next = ((caddr_t *)va)[2];
141 	if (indx == 7) {
142 		long *lp = (long *)va;
143 		if (lp[0] != -1 || lp[1] != -1 || lp[3] != -1 || lp[4] != -1)
144 			panic("malloc meddled");
145 	}
146 #ifdef KMEMSTATS
147 	kup = btokup(va);
148 	if (kup->ku_indx != indx)
149 		panic("malloc: wrong bucket");
150 	if (kup->ku_freecnt == 0)
151 		panic("malloc: lost data");
152 	kup->ku_freecnt--;
153 	kbp->kb_totalfree--;
154 	ksp->ks_memuse += 1 << indx;
155 out:
156 	kbp->kb_calls++;
157 	ksp->ks_inuse++;
158 	ksp->ks_calls++;
159 	if (ksp->ks_memuse > ksp->ks_maxused)
160 		ksp->ks_maxused = ksp->ks_memuse;
161 #else
162 out:
163 #endif
164 	OUT;
165 	splx(s);
166 	return ((qaddr_t)va);
167 }
168 
169 /*
170  * Free a block of memory allocated by malloc.
171  */
172 void
173 free(addr, type)
174 	caddr_t addr;
175 	int type;
176 {
177 	register struct kmembuckets *kbp;
178 	register struct kmemusage *kup;
179 	long alloc, size;
180 	int s;
181 #ifdef KMEMSTATS
182 	register struct kmemstats *ksp = &kmemstats[type];
183 #endif
184 
185 	kup = btokup(addr);
186 	kbp = &bucket[kup->ku_indx];
187 	s = splimp();
188 	IN;
189 	size = 1 << kup->ku_indx;
190 	if (size > MAXALLOCSAVE) {
191 		alloc = btokmemx(addr);
192 		(void) memfree(&kmempt[alloc], (int)kup->ku_pagecnt, 0);
193 		rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE);
194 		OUT;
195 		if (wantkmemmap) {
196 			wakeup((caddr_t)&wantkmemmap);
197 			wantkmemmap = 0;
198 		}
199 #ifdef KMEMSTATS
200 		size = kup->ku_pagecnt << PGSHIFT;
201 		ksp->ks_memuse -= size;
202 		kup->ku_indx = 0;
203 		kup->ku_pagecnt = 0;
204 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
205 		    ksp->ks_memuse < ksp->ks_limit)
206 			wakeup((caddr_t)ksp);
207 		ksp->ks_inuse--;
208 		kbp->kb_total -= 1;
209 #endif
210 		splx(s);
211 		return;
212 	}
213 	if (size == 128) {
214 		long *lp = (long *)addr;
215 		lp[0] = lp[1] = lp[3] = lp[4] = -1;
216 	}
217 #ifdef KMEMSTATS
218 	kup->ku_freecnt++;
219 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
220 		if (kup->ku_freecnt > kbp->kb_elmpercl)
221 			panic("free: multiple frees");
222 		else if (kbp->kb_totalfree > kbp->kb_highwat)
223 			kbp->kb_couldfree++;
224 	kbp->kb_totalfree++;
225 	ksp->ks_memuse -= size;
226 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
227 	    ksp->ks_memuse < ksp->ks_limit)
228 		wakeup((caddr_t)ksp);
229 	ksp->ks_inuse--;
230 #endif
231 	((caddr_t *)addr)[2] = kbp->kb_next;
232 	kbp->kb_next = addr;
233 	OUT;
234 	splx(s);
235 }
236 
237 /*
238  * Initialize the kernel memory allocator
239  */
240 kmeminit()
241 {
242 	register long indx;
243 	int npg;
244 
245 #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
246 		ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
247 #endif
248 #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
249 		ERROR!_kmeminit:_MAXALLOCSAVE_too_big
250 #endif
251 #if	(MAXALLOCSAVE < CLBYTES)
252 		ERROR!_kmeminit:_MAXALLOCSAVE_too_small
253 #endif
254 	npg = ekmempt - kmempt;
255 	rminit(kmemmap, (long)npg, (long)CLSIZE, "malloc map", npg);
256 #ifdef KMEMSTATS
257 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
258 		if (1 << indx >= CLBYTES)
259 			bucket[indx].kb_elmpercl = 1;
260 		else
261 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
262 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
263 	}
264 	for (indx = 0; indx < M_LAST; indx++)
265 		kmemstats[indx].ks_limit = npg * CLBYTES * 8 / 10;
266 #endif
267 }
268