xref: /original-bsd/sys/kern/kern_malloc.c (revision d54be081)
1 /*
2  * Copyright (c) 1987, 1991 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)kern_malloc.c	7.25.1.1 (Berkeley) 05/19/91
8  */
9 
10 #include "param.h"
11 #include "proc.h"
12 #include "map.h"
13 #include "kernel.h"
14 #include "malloc.h"
15 #include "vm/vm.h"
16 #include "vm/vm_kern.h"
17 
18 struct kmembuckets bucket[MINBUCKET + 16];
19 struct kmemstats kmemstats[M_LAST];
20 struct kmemusage *kmemusage;
21 char *kmembase, *kmemlimit;
22 char *memname[] = INITKMEMNAMES;
23 
24 /*
25  * Allocate a block of memory
26  */
27 void *
28 malloc(size, type, flags)
29 	unsigned long size;
30 	int type, flags;
31 {
32 	register struct kmembuckets *kbp;
33 	register struct kmemusage *kup;
34 	long indx, npg, alloc, allocsize;
35 	int s;
36 	caddr_t va, cp, savedlist;
37 #ifdef KMEMSTATS
38 	register struct kmemstats *ksp = &kmemstats[type];
39 
40 #ifdef DIAGNOSTIC
41 	if (((unsigned long)type) > M_LAST)
42 		panic("malloc - bogus type");
43 	if (type == M_NAMEI)
44 		curproc->p_spare[0]++;
45 #endif
46 #endif
47 
48 	indx = BUCKETINDX(size);
49 	kbp = &bucket[indx];
50 	s = splimp();
51 #ifdef KMEMSTATS
52 	while (ksp->ks_memuse >= ksp->ks_limit) {
53 		if (flags & M_NOWAIT) {
54 			splx(s);
55 			return ((void *) NULL);
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 		va = (caddr_t) kmem_malloc(kmem_map, (vm_size_t)ctob(npg),
69 					   !(flags & M_NOWAIT));
70 		if (va == NULL) {
71 			splx(s);
72 			return ((void *) NULL);
73 		}
74 #ifdef KMEMSTATS
75 		kbp->kb_total += kbp->kb_elmpercl;
76 #endif
77 		kup = btokup(va);
78 		kup->ku_indx = indx;
79 		if (allocsize > MAXALLOCSAVE) {
80 			if (npg > 65535)
81 				panic("malloc: allocation too large");
82 			kup->ku_pagecnt = npg;
83 #ifdef KMEMSTATS
84 			ksp->ks_memuse += allocsize;
85 #endif
86 			goto out;
87 		}
88 #ifdef KMEMSTATS
89 		kup->ku_freecnt = kbp->kb_elmpercl;
90 		kbp->kb_totalfree += kbp->kb_elmpercl;
91 #endif
92 		/*
93 		 * Just in case we blocked while allocating memory,
94 		 * and someone else also allocated memory for this
95 		 * bucket, don't assume the list is still empty.
96 		 */
97 		savedlist = kbp->kb_next;
98 		kbp->kb_next = va + (npg * NBPG) - allocsize;
99 		for (cp = kbp->kb_next; cp > va; cp -= allocsize)
100 			*(caddr_t *)cp = cp - allocsize;
101 		*(caddr_t *)cp = savedlist;
102 	}
103 	va = kbp->kb_next;
104 	kbp->kb_next = *(caddr_t *)va;
105 #ifdef KMEMSTATS
106 	kup = btokup(va);
107 	if (kup->ku_indx != indx)
108 		panic("malloc: wrong bucket");
109 	if (kup->ku_freecnt == 0)
110 		panic("malloc: lost data");
111 	kup->ku_freecnt--;
112 	kbp->kb_totalfree--;
113 	ksp->ks_memuse += 1 << indx;
114 out:
115 	kbp->kb_calls++;
116 	ksp->ks_inuse++;
117 	ksp->ks_calls++;
118 	if (ksp->ks_memuse > ksp->ks_maxused)
119 		ksp->ks_maxused = ksp->ks_memuse;
120 #else
121 out:
122 #endif
123 	splx(s);
124 	return ((void *) va);
125 }
126 
127 #ifdef DIAGNOSTIC
128 long addrmask[] = { 0x00000000,
129 	0x00000001, 0x00000003, 0x00000007, 0x0000000f,
130 	0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
131 	0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
132 	0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
133 };
134 #endif /* DIAGNOSTIC */
135 
136 /*
137  * Free a block of memory allocated by malloc.
138  */
139 void
140 free(addr, type)
141 	void *addr;
142 	int type;
143 {
144 	register struct kmembuckets *kbp;
145 	register struct kmemusage *kup;
146 	long alloc, size;
147 	int s;
148 #ifdef KMEMSTATS
149 	register struct kmemstats *ksp = &kmemstats[type];
150 #endif
151 
152 	kup = btokup(addr);
153 	size = 1 << kup->ku_indx;
154 #ifdef DIAGNOSTIC
155 	if (type == M_NAMEI)
156 		curproc->p_spare[0]--;
157 	if (size > NBPG * CLSIZE)
158 		alloc = addrmask[BUCKETINDX(NBPG * CLSIZE)];
159 	else
160 		alloc = addrmask[kup->ku_indx];
161 	if (((u_long)addr & alloc) != 0) {
162 		printf("free: unaligned addr 0x%x, size %d, type %d, mask %d\n",
163 			addr, size, type, alloc);
164 		panic("free: unaligned addr");
165 	}
166 #endif /* DIAGNOSTIC */
167 	kbp = &bucket[kup->ku_indx];
168 	s = splimp();
169 	if (size > MAXALLOCSAVE) {
170 		kmem_free(kmem_map, (vm_offset_t)addr, ctob(kup->ku_pagecnt));
171 #ifdef KMEMSTATS
172 		size = kup->ku_pagecnt << PGSHIFT;
173 		ksp->ks_memuse -= size;
174 		kup->ku_indx = 0;
175 		kup->ku_pagecnt = 0;
176 		if (ksp->ks_memuse + size >= ksp->ks_limit &&
177 		    ksp->ks_memuse < ksp->ks_limit)
178 			wakeup((caddr_t)ksp);
179 		ksp->ks_inuse--;
180 		kbp->kb_total -= 1;
181 #endif
182 		splx(s);
183 		return;
184 	}
185 #ifdef KMEMSTATS
186 	kup->ku_freecnt++;
187 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
188 		if (kup->ku_freecnt > kbp->kb_elmpercl)
189 			panic("free: multiple frees");
190 		else if (kbp->kb_totalfree > kbp->kb_highwat)
191 			kbp->kb_couldfree++;
192 	kbp->kb_totalfree++;
193 	ksp->ks_memuse -= size;
194 	if (ksp->ks_memuse + size >= ksp->ks_limit &&
195 	    ksp->ks_memuse < ksp->ks_limit)
196 		wakeup((caddr_t)ksp);
197 	ksp->ks_inuse--;
198 #endif
199 	*(caddr_t *)addr = kbp->kb_next;
200 	kbp->kb_next = addr;
201 	splx(s);
202 }
203 
204 /*
205  * Initialize the kernel memory allocator
206  */
207 kmeminit()
208 {
209 	register long indx;
210 	int npg;
211 
212 #if	((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0)
213 		ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2
214 #endif
215 #if	(MAXALLOCSAVE > MINALLOCSIZE * 32768)
216 		ERROR!_kmeminit:_MAXALLOCSAVE_too_big
217 #endif
218 #if	(MAXALLOCSAVE < CLBYTES)
219 		ERROR!_kmeminit:_MAXALLOCSAVE_too_small
220 #endif
221 	npg = VM_KMEM_SIZE/ NBPG;
222 	kmemusage = (struct kmemusage *) kmem_alloc(kernel_map,
223 		(vm_size_t)(npg * sizeof(struct kmemusage)));
224 	kmem_map = kmem_suballoc(kernel_map, (vm_offset_t)&kmembase,
225 		(vm_offset_t)&kmemlimit, (vm_size_t)(npg * NBPG), FALSE);
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 * NBPG * 6 / 10;
236 #endif
237 }
238