Commit | Line | Data |
---|---|---|
d4202556 KM |
1 | /* |
2 | * Copyright (c) 1987 Regents of the University of California. | |
2420c94a | 3 | * All rights reserved. |
d4202556 | 4 | * |
2420c94a KM |
5 | * Redistribution and use in source and binary forms are permitted |
6 | * provided that this notice is preserved and that due credit is given | |
7 | * to the University of California at Berkeley. The name of the University | |
8 | * may not be used to endorse or promote products derived from this | |
9 | * software without specific prior written permission. This software | |
10 | * is provided ``as is'' without express or implied warranty. | |
11 | * | |
47516941 | 12 | * @(#)kern_malloc.c 7.9 (Berkeley) %G% |
d4202556 KM |
13 | */ |
14 | ||
15 | #include "param.h" | |
16 | #include "vm.h" | |
17 | #include "cmap.h" | |
18 | #include "time.h" | |
19 | #include "proc.h" | |
20 | #include "map.h" | |
21 | #include "kernel.h" | |
22 | #include "malloc.h" | |
23 | ||
24 | #include "../machine/pte.h" | |
25 | ||
26 | struct kmembuckets bucket[MINBUCKET + 16]; | |
27 | struct kmemstats kmemstats[M_LAST]; | |
28 | struct kmemusage *kmemusage; | |
fd78e9f6 | 29 | long wantkmemmap; |
d4202556 KM |
30 | |
31 | /* | |
32 | * Allocate a block of memory | |
33 | */ | |
738ba0d6 KM |
34 | qaddr_t |
35 | malloc(size, type, flags) | |
d4202556 | 36 | unsigned long size; |
47516941 | 37 | int type, flags; |
d4202556 KM |
38 | { |
39 | register struct kmembuckets *kbp; | |
40 | register struct kmemusage *kup; | |
47516941 MK |
41 | long indx, npg, alloc, allocsize; |
42 | int s; | |
d4202556 KM |
43 | caddr_t va, cp; |
44 | #ifdef KMEMSTATS | |
fd78e9f6 | 45 | register struct kmemstats *ksp = &kmemstats[type]; |
d4202556 | 46 | #endif |
fd78e9f6 | 47 | |
d4202556 KM |
48 | indx = BUCKETINDX(size); |
49 | kbp = &bucket[indx]; | |
50 | s = splimp(); | |
fd78e9f6 KM |
51 | again: |
52 | #ifdef KMEMSTATS | |
0a4aff4d | 53 | while (ksp->ks_memuse >= ksp->ks_limit) { |
fd78e9f6 KM |
54 | if (flags & M_NOWAIT) { |
55 | splx(s); | |
56 | return (0); | |
57 | } | |
58 | if (ksp->ks_limblocks < 65535) | |
59 | ksp->ks_limblocks++; | |
60 | sleep((caddr_t)ksp, PSWP+2); | |
61 | } | |
62 | #endif | |
d4202556 KM |
63 | if (kbp->kb_next == NULL) { |
64 | if (size > MAXALLOCSAVE) | |
65 | allocsize = roundup(size, CLBYTES); | |
66 | else | |
67 | allocsize = 1 << indx; | |
68 | npg = clrnd(btoc(allocsize)); | |
69 | if ((flags & M_NOWAIT) && freemem < npg) { | |
70 | splx(s); | |
71 | return (0); | |
72 | } | |
73 | alloc = rmalloc(kmemmap, npg); | |
74 | if (alloc == 0) { | |
fd78e9f6 KM |
75 | if (flags & M_NOWAIT) { |
76 | splx(s); | |
77 | return (0); | |
78 | } | |
79 | #ifdef KMEMSTATS | |
80 | if (ksp->ks_mapblocks < 65535) | |
81 | ksp->ks_mapblocks++; | |
82 | #endif | |
83 | wantkmemmap++; | |
84 | sleep((caddr_t)&wantkmemmap, PSWP+2); | |
85 | goto again; | |
d4202556 | 86 | } |
7656fce5 | 87 | alloc -= CLSIZE; /* convert to base 0 */ |
47516941 | 88 | (void) vmemall(&kmempt[alloc], (int)npg, &proc[0], CSYS); |
d4202556 | 89 | va = (caddr_t) kmemxtob(alloc); |
47516941 | 90 | vmaccess(&kmempt[alloc], va, (int)npg); |
d4202556 KM |
91 | #ifdef KMEMSTATS |
92 | kbp->kb_total += kbp->kb_elmpercl; | |
93 | #endif | |
94 | kup = btokup(va); | |
95 | kup->ku_indx = indx; | |
96 | if (allocsize > MAXALLOCSAVE) { | |
97 | if (npg > 65535) | |
98 | panic("malloc: allocation too large"); | |
99 | kup->ku_pagecnt = npg; | |
fd78e9f6 KM |
100 | #ifdef KMEMSTATS |
101 | ksp->ks_memuse += allocsize; | |
102 | #endif | |
d4202556 KM |
103 | goto out; |
104 | } | |
105 | #ifdef KMEMSTATS | |
106 | kup->ku_freecnt = kbp->kb_elmpercl; | |
107 | kbp->kb_totalfree += kbp->kb_elmpercl; | |
108 | #endif | |
109 | kbp->kb_next = va + (npg * NBPG) - allocsize; | |
fd78e9f6 | 110 | for (cp = kbp->kb_next; cp > va; cp -= allocsize) |
d4202556 KM |
111 | *(caddr_t *)cp = cp - allocsize; |
112 | *(caddr_t *)cp = NULL; | |
113 | } | |
114 | va = kbp->kb_next; | |
115 | kbp->kb_next = *(caddr_t *)va; | |
116 | #ifdef KMEMSTATS | |
117 | kup = btokup(va); | |
118 | if (kup->ku_indx != indx) | |
119 | panic("malloc: wrong bucket"); | |
120 | if (kup->ku_freecnt == 0) | |
121 | panic("malloc: lost data"); | |
122 | kup->ku_freecnt--; | |
123 | kbp->kb_totalfree--; | |
fd78e9f6 | 124 | ksp->ks_memuse += 1 << indx; |
d4202556 KM |
125 | out: |
126 | kbp->kb_calls++; | |
127 | ksp->ks_inuse++; | |
128 | ksp->ks_calls++; | |
0a4aff4d KM |
129 | if (ksp->ks_memuse > ksp->ks_maxused) |
130 | ksp->ks_maxused = ksp->ks_memuse; | |
d4202556 KM |
131 | #else |
132 | out: | |
133 | #endif | |
134 | splx(s); | |
135 | return ((qaddr_t)va); | |
136 | } | |
137 | ||
138 | /* | |
139 | * Free a block of memory allocated by malloc. | |
140 | */ | |
738ba0d6 KM |
141 | void |
142 | free(addr, type) | |
d4202556 | 143 | caddr_t addr; |
47516941 | 144 | int type; |
d4202556 KM |
145 | { |
146 | register struct kmembuckets *kbp; | |
147 | register struct kmemusage *kup; | |
47516941 MK |
148 | long alloc, size; |
149 | int s; | |
fd78e9f6 KM |
150 | #ifdef KMEMSTATS |
151 | register struct kmemstats *ksp = &kmemstats[type]; | |
152 | #endif | |
d4202556 KM |
153 | |
154 | kup = btokup(addr); | |
738ba0d6 | 155 | kbp = &bucket[kup->ku_indx]; |
d4202556 | 156 | s = splimp(); |
0a4aff4d KM |
157 | size = 1 << kup->ku_indx; |
158 | if (size > MAXALLOCSAVE) { | |
d4202556 | 159 | alloc = btokmemx(addr); |
47516941 | 160 | (void) memfree(&kmempt[alloc], (int)kup->ku_pagecnt, 0); |
fd78e9f6 KM |
161 | rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE); |
162 | if (wantkmemmap) { | |
163 | wakeup((caddr_t)&wantkmemmap); | |
164 | wantkmemmap = 0; | |
165 | } | |
d4202556 | 166 | #ifdef KMEMSTATS |
0a4aff4d KM |
167 | size = kup->ku_pagecnt << PGSHIFT; |
168 | ksp->ks_memuse -= size; | |
d4202556 KM |
169 | kup->ku_indx = 0; |
170 | kup->ku_pagecnt = 0; | |
0a4aff4d KM |
171 | if (ksp->ks_memuse + size >= ksp->ks_limit && |
172 | ksp->ks_memuse < ksp->ks_limit) | |
fd78e9f6 KM |
173 | wakeup((caddr_t)ksp); |
174 | ksp->ks_inuse--; | |
738ba0d6 | 175 | kbp->kb_total -= 1; |
d4202556 KM |
176 | #endif |
177 | splx(s); | |
178 | return; | |
179 | } | |
d4202556 KM |
180 | #ifdef KMEMSTATS |
181 | kup->ku_freecnt++; | |
182 | if (kup->ku_freecnt >= kbp->kb_elmpercl) | |
183 | if (kup->ku_freecnt > kbp->kb_elmpercl) | |
184 | panic("free: multiple frees"); | |
185 | else if (kbp->kb_totalfree > kbp->kb_highwat) | |
186 | kbp->kb_couldfree++; | |
187 | kbp->kb_totalfree++; | |
0a4aff4d KM |
188 | ksp->ks_memuse -= size; |
189 | if (ksp->ks_memuse + size >= ksp->ks_limit && | |
190 | ksp->ks_memuse < ksp->ks_limit) | |
fd78e9f6 KM |
191 | wakeup((caddr_t)ksp); |
192 | ksp->ks_inuse--; | |
d4202556 KM |
193 | #endif |
194 | *(caddr_t *)addr = kbp->kb_next; | |
195 | kbp->kb_next = addr; | |
196 | splx(s); | |
197 | } | |
198 | ||
199 | /* | |
200 | * Initialize the kernel memory allocator | |
201 | */ | |
202 | kmeminit() | |
203 | { | |
204 | register long indx; | |
738ba0d6 | 205 | int npg; |
d4202556 | 206 | |
47516941 MK |
207 | #if ((MAXALLOCSAVE & (MAXALLOCSAVE - 1)) != 0) |
208 | ERROR!_kmeminit:_MAXALLOCSAVE_not_power_of_2 | |
209 | #endif | |
210 | #if (MAXALLOCSAVE > MINALLOCSIZE * 32768) | |
211 | ERROR!_kmeminit:_MAXALLOCSAVE_too_big | |
212 | #endif | |
213 | #if (MAXALLOCSAVE < CLBYTES) | |
214 | ERROR!_kmeminit:_MAXALLOCSAVE_too_small | |
215 | #endif | |
738ba0d6 | 216 | npg = ekmempt - kmempt; |
47516941 | 217 | rminit(kmemmap, (long)npg, (long)CLSIZE, "malloc map", npg); |
d4202556 KM |
218 | #ifdef KMEMSTATS |
219 | for (indx = 0; indx < MINBUCKET + 16; indx++) { | |
220 | if (1 << indx >= CLBYTES) | |
221 | bucket[indx].kb_elmpercl = 1; | |
222 | else | |
223 | bucket[indx].kb_elmpercl = CLBYTES / (1 << indx); | |
224 | bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl; | |
225 | } | |
226 | for (indx = 0; indx < M_LAST; indx++) | |
738ba0d6 | 227 | kmemstats[indx].ks_limit = npg * CLBYTES * 8 / 10; |
d4202556 KM |
228 | #endif |
229 | } |