not doing *anything* while waiting for input; add substate
[unix-history] / usr / src / sys / kern / kern_malloc.c
CommitLineData
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
26struct kmembuckets bucket[MINBUCKET + 16];
27struct kmemstats kmemstats[M_LAST];
28struct kmemusage *kmemusage;
fd78e9f6 29long wantkmemmap;
d4202556
KM
30
31/*
32 * Allocate a block of memory
33 */
738ba0d6
KM
34qaddr_t
35malloc(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
51again:
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
125out:
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
132out:
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
141void
142free(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 */
202kmeminit()
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}