xref: /original-bsd/sys/kern/kern_malloc.c (revision e877e4b2)
1 /*
2  * Copyright (c) 1987 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)kern_malloc.c	7.4 (Berkeley) 10/23/87
7  */
8 
9 #include "param.h"
10 #include "vm.h"
11 #include "cmap.h"
12 #include "time.h"
13 #include "proc.h"
14 #include "map.h"
15 #include "kernel.h"
16 #include "malloc.h"
17 
18 #include "../machine/pte.h"
19 
20 struct kmembuckets bucket[MINBUCKET + 16];
21 struct kmemstats kmemstats[M_LAST];
22 struct kmemusage *kmemusage;
23 
24 /*
25  * Allocate a block of memory
26  */
27 qaddr_t malloc(size, type, flags)
28 	unsigned long size;
29 	long type, flags;
30 {
31 	register struct kmembuckets *kbp;
32 	register struct kmemusage *kup;
33 	long indx, npg, alloc, allocsize, s;
34 	caddr_t va, cp;
35 #ifdef KMEMSTATS
36 	register struct kmemstats *ksp;
37 
38 	ksp = &kmemstats[type];
39 	if (ksp->ks_inuse >= ksp->ks_limit)
40 		return (0);
41 #endif
42 	indx = BUCKETINDX(size);
43 	kbp = &bucket[indx];
44 	s = splimp();
45 	if (kbp->kb_next == NULL) {
46 		if (size > MAXALLOCSAVE)
47 			allocsize = roundup(size, CLBYTES);
48 		else
49 			allocsize = 1 << indx;
50 		npg = clrnd(btoc(allocsize));
51 		if ((flags & M_NOWAIT) && freemem < npg) {
52 			splx(s);
53 			return (0);
54 		}
55 		alloc = rmalloc(kmemmap, npg);
56 		if (alloc == 0) {
57 			splx(s);
58 			return (0);
59 		}
60 		alloc -= CLSIZE;		/* convert to base 0 */
61 		if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) {
62 			rmfree(kmemmap, npg, alloc+CLSIZE);
63 			splx(s);
64 			return (0);
65 		}
66 		va = (caddr_t) kmemxtob(alloc);
67 		vmaccess(&kmempt[alloc], va, npg);
68 #ifdef KMEMSTATS
69 		kbp->kb_total += kbp->kb_elmpercl;
70 #endif
71 		kup = btokup(va);
72 		kup->ku_indx = indx;
73 		if (allocsize > MAXALLOCSAVE) {
74 			if (npg > 65535)
75 				panic("malloc: allocation too large");
76 			kup->ku_pagecnt = npg;
77 			goto out;
78 		}
79 #ifdef KMEMSTATS
80 		kup->ku_freecnt = kbp->kb_elmpercl;
81 		kbp->kb_totalfree += kbp->kb_elmpercl;
82 #endif
83 		kbp->kb_next = va + (npg * NBPG) - allocsize;
84 		for(cp = kbp->kb_next; cp > va; cp -= allocsize)
85 			*(caddr_t *)cp = cp - allocsize;
86 		*(caddr_t *)cp = NULL;
87 	}
88 	va = kbp->kb_next;
89 	kbp->kb_next = *(caddr_t *)va;
90 #ifdef KMEMSTATS
91 	kup = btokup(va);
92 	if (kup->ku_indx != indx)
93 		panic("malloc: wrong bucket");
94 	if (kup->ku_freecnt == 0)
95 		panic("malloc: lost data");
96 	kup->ku_freecnt--;
97 	kbp->kb_totalfree--;
98 out:
99 	kbp->kb_calls++;
100 	ksp->ks_inuse++;
101 	ksp->ks_calls++;
102 	if (ksp->ks_inuse > ksp->ks_maxused)
103 		ksp->ks_maxused = ksp->ks_inuse;
104 #else
105 out:
106 #endif
107 	splx(s);
108 	return ((qaddr_t)va);
109 }
110 
111 /*
112  * Free a block of memory allocated by malloc.
113  */
114 void free(addr, type)
115 	caddr_t addr;
116 	long type;
117 {
118 	register struct kmembuckets *kbp;
119 	register struct kmemusage *kup;
120 	long alloc, s;
121 
122 	kup = btokup(addr);
123 	s = splimp();
124 	if (1 << kup->ku_indx > MAXALLOCSAVE) {
125 		alloc = btokmemx(addr);
126 		(void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0);
127 		rmfree(kmemmap, (long)kup->ku_pagecnt, alloc+CLSIZE);
128 #ifdef KMEMSTATS
129 		kup->ku_indx = 0;
130 		kup->ku_pagecnt = 0;
131 		kmemstats[type].ks_inuse--;
132 #endif
133 		splx(s);
134 		return;
135 	}
136 	kbp = &bucket[kup->ku_indx];
137 #ifdef KMEMSTATS
138 	kup->ku_freecnt++;
139 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
140 		if (kup->ku_freecnt > kbp->kb_elmpercl)
141 			panic("free: multiple frees");
142 		else if (kbp->kb_totalfree > kbp->kb_highwat)
143 			kbp->kb_couldfree++;
144 	kbp->kb_totalfree++;
145 	kmemstats[type].ks_inuse--;
146 #endif
147 	*(caddr_t *)addr = kbp->kb_next;
148 	kbp->kb_next = addr;
149 	splx(s);
150 }
151 
152 /*
153  * Initialize the kernel memory allocator
154  */
155 kmeminit()
156 {
157 	register long indx;
158 
159 	if (!powerof2(MAXALLOCSAVE))
160 		panic("kmeminit: MAXALLOCSAVE not power of 2");
161 	if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
162 		panic("kmeminit: MAXALLOCSAVE too big");
163 	if (MAXALLOCSAVE < CLBYTES)
164 		panic("kmeminit: MAXALLOCSAVE too small");
165 	rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE,
166 		"malloc map", ekmempt - kmempt);
167 #ifdef KMEMSTATS
168 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
169 		if (1 << indx >= CLBYTES)
170 			bucket[indx].kb_elmpercl = 1;
171 		else
172 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
173 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
174 	}
175 	for (indx = 0; indx < M_LAST; indx++)
176 		kmemstats[indx].ks_limit = 0x7fffffff;
177 #endif
178 }
179