xref: /original-bsd/sys/kern/kern_malloc.c (revision 57124d5e)
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.2 (Berkeley) 06/22/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 		if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) {
61 			rmfree(kmemmap, npg, alloc);
62 			splx(s);
63 			return (0);
64 		}
65 		va = (caddr_t) kmemxtob(alloc);
66 		vmaccess(&kmempt[alloc], va, npg);
67 #ifdef KMEMSTATS
68 		kbp->kb_total += kbp->kb_elmpercl;
69 #endif
70 		kup = btokup(va);
71 		kup->ku_indx = indx;
72 		if (allocsize > MAXALLOCSAVE) {
73 			if (npg > 65535)
74 				panic("malloc: allocation too large");
75 			kup->ku_pagecnt = npg;
76 			goto out;
77 		}
78 #ifdef KMEMSTATS
79 		kup->ku_freecnt = kbp->kb_elmpercl;
80 		kbp->kb_totalfree += kbp->kb_elmpercl;
81 #endif
82 		kbp->kb_next = va + (npg * NBPG) - allocsize;
83 		for(cp = kbp->kb_next; cp > va; cp -= allocsize)
84 			*(caddr_t *)cp = cp - allocsize;
85 		*(caddr_t *)cp = NULL;
86 	}
87 	va = kbp->kb_next;
88 	kbp->kb_next = *(caddr_t *)va;
89 #ifdef KMEMSTATS
90 	kup = btokup(va);
91 	if (kup->ku_indx != indx)
92 		panic("malloc: wrong bucket");
93 	if (kup->ku_freecnt == 0)
94 		panic("malloc: lost data");
95 	kup->ku_freecnt--;
96 	kbp->kb_totalfree--;
97 out:
98 	kbp->kb_calls++;
99 	ksp->ks_inuse++;
100 	ksp->ks_calls++;
101 	if (ksp->ks_inuse > ksp->ks_maxused)
102 		ksp->ks_maxused = ksp->ks_inuse;
103 #else
104 out:
105 #endif
106 	splx(s);
107 	return ((qaddr_t)va);
108 }
109 
110 /*
111  * Free a block of memory allocated by malloc.
112  */
113 void free(addr, type)
114 	caddr_t addr;
115 	long type;
116 {
117 	register struct kmembuckets *kbp;
118 	register struct kmemusage *kup;
119 	long alloc, s;
120 
121 	kup = btokup(addr);
122 	s = splimp();
123 	if (1 << kup->ku_indx > MAXALLOCSAVE) {
124 		alloc = btokmemx(addr);
125 		(void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0);
126 		rmfree(kmemmap, (long)kup->ku_pagecnt, alloc);
127 #ifdef KMEMSTATS
128 		kup->ku_indx = 0;
129 		kup->ku_pagecnt = 0;
130 		kmemstats[type].ks_inuse--;
131 #endif
132 		splx(s);
133 		return;
134 	}
135 	kbp = &bucket[kup->ku_indx];
136 #ifdef KMEMSTATS
137 	kup->ku_freecnt++;
138 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
139 		if (kup->ku_freecnt > kbp->kb_elmpercl)
140 			panic("free: multiple frees");
141 		else if (kbp->kb_totalfree > kbp->kb_highwat)
142 			kbp->kb_couldfree++;
143 	kbp->kb_totalfree++;
144 	kmemstats[type].ks_inuse--;
145 #endif
146 	*(caddr_t *)addr = kbp->kb_next;
147 	kbp->kb_next = addr;
148 	splx(s);
149 }
150 
151 /*
152  * Initialize the kernel memory allocator
153  */
154 kmeminit()
155 {
156 	register long indx;
157 
158 	if (!powerof2(MAXALLOCSAVE))
159 		panic("kmeminit: MAXALLOCSAVE not power of 2");
160 	if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
161 		panic("kmeminit: MAXALLOCSAVE too big");
162 	if (MAXALLOCSAVE < CLBYTES)
163 		panic("kmeminit: MAXALLOCSAVE too small");
164 	rminit(kmemmap, ekmempt - kmempt, (long)1,
165 		"malloc map", ekmempt - kmempt);
166 #ifdef KMEMSTATS
167 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
168 		if (1 << indx >= CLBYTES)
169 			bucket[indx].kb_elmpercl = 1;
170 		else
171 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
172 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
173 	}
174 	for (indx = 0; indx < M_LAST; indx++)
175 		kmemstats[indx].ks_limit = 0x7fffffff;
176 #endif
177 }
178