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