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