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