xref: /csrg-svn/sys/kern/kern_malloc.c (revision 33438)
131422Smckusick /*
231422Smckusick  * Copyright (c) 1987 Regents of the University of California.
331422Smckusick  * All rights reserved.  The Berkeley software License Agreement
431422Smckusick  * specifies the terms and conditions for redistribution.
531422Smckusick  *
6*33438Smckusick  *	@(#)kern_malloc.c	7.5 (Berkeley) 02/06/88
731422Smckusick  */
831422Smckusick 
931422Smckusick #include "param.h"
1031422Smckusick #include "vm.h"
1131422Smckusick #include "cmap.h"
1231422Smckusick #include "time.h"
1331422Smckusick #include "proc.h"
1431422Smckusick #include "map.h"
1531422Smckusick #include "kernel.h"
1631422Smckusick #include "malloc.h"
1731422Smckusick 
1831422Smckusick #include "../machine/pte.h"
1931422Smckusick 
2031422Smckusick struct kmembuckets bucket[MINBUCKET + 16];
2131422Smckusick struct kmemstats kmemstats[M_LAST];
2231422Smckusick struct kmemusage *kmemusage;
23*33438Smckusick long wantkmemmap;
2431422Smckusick 
2531422Smckusick /*
2631422Smckusick  * Allocate a block of memory
2731422Smckusick  */
2831422Smckusick qaddr_t malloc(size, type, flags)
2931422Smckusick 	unsigned long size;
3031422Smckusick 	long type, flags;
3131422Smckusick {
3231422Smckusick 	register struct kmembuckets *kbp;
3331422Smckusick 	register struct kmemusage *kup;
3431422Smckusick 	long indx, npg, alloc, allocsize, s;
3531422Smckusick 	caddr_t va, cp;
3631422Smckusick #ifdef KMEMSTATS
37*33438Smckusick 	register struct kmemstats *ksp = &kmemstats[type];
38*33438Smckusick #endif
3931422Smckusick 
4031422Smckusick 	indx = BUCKETINDX(size);
4131422Smckusick 	kbp = &bucket[indx];
4231422Smckusick 	s = splimp();
43*33438Smckusick again:
44*33438Smckusick #ifdef KMEMSTATS
45*33438Smckusick 	while (ksp->ks_inuse >= ksp->ks_limit) {
46*33438Smckusick 		if (flags & M_NOWAIT) {
47*33438Smckusick 			splx(s);
48*33438Smckusick 			return (0);
49*33438Smckusick 		}
50*33438Smckusick 		if (ksp->ks_limblocks < 65535)
51*33438Smckusick 			ksp->ks_limblocks++;
52*33438Smckusick 		sleep((caddr_t)ksp, PSWP+2);
53*33438Smckusick 	}
54*33438Smckusick #endif
5531422Smckusick 	if (kbp->kb_next == NULL) {
5631422Smckusick 		if (size > MAXALLOCSAVE)
5731422Smckusick 			allocsize = roundup(size, CLBYTES);
5831422Smckusick 		else
5931422Smckusick 			allocsize = 1 << indx;
6031422Smckusick 		npg = clrnd(btoc(allocsize));
6131422Smckusick 		if ((flags & M_NOWAIT) && freemem < npg) {
6231422Smckusick 			splx(s);
6331422Smckusick 			return (0);
6431422Smckusick 		}
6531422Smckusick 		alloc = rmalloc(kmemmap, npg);
6631422Smckusick 		if (alloc == 0) {
67*33438Smckusick 			if (flags & M_NOWAIT) {
68*33438Smckusick 				splx(s);
69*33438Smckusick 				return (0);
70*33438Smckusick 			}
71*33438Smckusick #ifdef KMEMSTATS
72*33438Smckusick 			if (ksp->ks_mapblocks < 65535)
73*33438Smckusick 				ksp->ks_mapblocks++;
74*33438Smckusick #endif
75*33438Smckusick 			wantkmemmap++;
76*33438Smckusick 			sleep((caddr_t)&wantkmemmap, PSWP+2);
77*33438Smckusick 			goto again;
7831422Smckusick 		}
7932530Skre 		alloc -= CLSIZE;		/* convert to base 0 */
80*33438Smckusick 		(void) vmemall(&kmempt[alloc], npg, &proc[0], CSYS);
8131422Smckusick 		va = (caddr_t) kmemxtob(alloc);
8231422Smckusick 		vmaccess(&kmempt[alloc], va, npg);
8331422Smckusick #ifdef KMEMSTATS
8431422Smckusick 		kbp->kb_total += kbp->kb_elmpercl;
8531422Smckusick #endif
8631422Smckusick 		kup = btokup(va);
8731422Smckusick 		kup->ku_indx = indx;
8831422Smckusick 		if (allocsize > MAXALLOCSAVE) {
8931422Smckusick 			if (npg > 65535)
9031422Smckusick 				panic("malloc: allocation too large");
9131422Smckusick 			kup->ku_pagecnt = npg;
92*33438Smckusick #ifdef KMEMSTATS
93*33438Smckusick 			ksp->ks_memuse += allocsize;
94*33438Smckusick #endif
9531422Smckusick 			goto out;
9631422Smckusick 		}
9731422Smckusick #ifdef KMEMSTATS
9831422Smckusick 		kup->ku_freecnt = kbp->kb_elmpercl;
9931422Smckusick 		kbp->kb_totalfree += kbp->kb_elmpercl;
10031422Smckusick #endif
10131422Smckusick 		kbp->kb_next = va + (npg * NBPG) - allocsize;
102*33438Smckusick 		for (cp = kbp->kb_next; cp > va; cp -= allocsize)
10331422Smckusick 			*(caddr_t *)cp = cp - allocsize;
10431422Smckusick 		*(caddr_t *)cp = NULL;
10531422Smckusick 	}
10631422Smckusick 	va = kbp->kb_next;
10731422Smckusick 	kbp->kb_next = *(caddr_t *)va;
10831422Smckusick #ifdef KMEMSTATS
10931422Smckusick 	kup = btokup(va);
11031422Smckusick 	if (kup->ku_indx != indx)
11131422Smckusick 		panic("malloc: wrong bucket");
11231422Smckusick 	if (kup->ku_freecnt == 0)
11331422Smckusick 		panic("malloc: lost data");
11431422Smckusick 	kup->ku_freecnt--;
11531422Smckusick 	kbp->kb_totalfree--;
116*33438Smckusick 	ksp->ks_memuse += 1 << indx;
11731422Smckusick out:
11831422Smckusick 	kbp->kb_calls++;
11931422Smckusick 	ksp->ks_inuse++;
12031422Smckusick 	ksp->ks_calls++;
12131422Smckusick 	if (ksp->ks_inuse > ksp->ks_maxused)
12231422Smckusick 		ksp->ks_maxused = ksp->ks_inuse;
12331422Smckusick #else
12431422Smckusick out:
12531422Smckusick #endif
12631422Smckusick 	splx(s);
12731422Smckusick 	return ((qaddr_t)va);
12831422Smckusick }
12931422Smckusick 
13031422Smckusick /*
13131422Smckusick  * Free a block of memory allocated by malloc.
13231422Smckusick  */
13331422Smckusick void free(addr, type)
13431422Smckusick 	caddr_t addr;
13531422Smckusick 	long type;
13631422Smckusick {
13731422Smckusick 	register struct kmembuckets *kbp;
13831422Smckusick 	register struct kmemusage *kup;
13931422Smckusick 	long alloc, s;
140*33438Smckusick #ifdef KMEMSTATS
141*33438Smckusick 	register struct kmemstats *ksp = &kmemstats[type];
142*33438Smckusick #endif
14331422Smckusick 
14431422Smckusick 	kup = btokup(addr);
14531422Smckusick 	s = splimp();
14631422Smckusick 	if (1 << kup->ku_indx > MAXALLOCSAVE) {
14731422Smckusick 		alloc = btokmemx(addr);
14831422Smckusick 		(void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0);
149*33438Smckusick 		rmfree(kmemmap, (long)kup->ku_pagecnt, alloc + CLSIZE);
150*33438Smckusick 		if (wantkmemmap) {
151*33438Smckusick 			wakeup((caddr_t)&wantkmemmap);
152*33438Smckusick 			wantkmemmap = 0;
153*33438Smckusick 		}
15431422Smckusick #ifdef KMEMSTATS
155*33438Smckusick 		ksp->ks_memuse -= kup->ku_pagecnt << PGSHIFT;
15631422Smckusick 		kup->ku_indx = 0;
15731422Smckusick 		kup->ku_pagecnt = 0;
158*33438Smckusick 		if (ksp->ks_inuse == ksp->ks_limit)
159*33438Smckusick 			wakeup((caddr_t)ksp);
160*33438Smckusick 		ksp->ks_inuse--;
16131422Smckusick #endif
16231422Smckusick 		splx(s);
16331422Smckusick 		return;
16431422Smckusick 	}
16531422Smckusick 	kbp = &bucket[kup->ku_indx];
16631422Smckusick #ifdef KMEMSTATS
16731422Smckusick 	kup->ku_freecnt++;
16831422Smckusick 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
16931422Smckusick 		if (kup->ku_freecnt > kbp->kb_elmpercl)
17031422Smckusick 			panic("free: multiple frees");
17131422Smckusick 		else if (kbp->kb_totalfree > kbp->kb_highwat)
17231422Smckusick 			kbp->kb_couldfree++;
17331422Smckusick 	kbp->kb_totalfree++;
174*33438Smckusick 	if (ksp->ks_inuse == ksp->ks_limit)
175*33438Smckusick 		wakeup((caddr_t)ksp);
176*33438Smckusick 	ksp->ks_inuse--;
177*33438Smckusick 	ksp->ks_memuse -= 1 << kup->ku_indx;
17831422Smckusick #endif
17931422Smckusick 	*(caddr_t *)addr = kbp->kb_next;
18031422Smckusick 	kbp->kb_next = addr;
18131422Smckusick 	splx(s);
18231422Smckusick }
18331422Smckusick 
18431422Smckusick /*
18531422Smckusick  * Initialize the kernel memory allocator
18631422Smckusick  */
18731422Smckusick kmeminit()
18831422Smckusick {
18931422Smckusick 	register long indx;
19031422Smckusick 
19131422Smckusick 	if (!powerof2(MAXALLOCSAVE))
19231422Smckusick 		panic("kmeminit: MAXALLOCSAVE not power of 2");
19331422Smckusick 	if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
19431422Smckusick 		panic("kmeminit: MAXALLOCSAVE too big");
19531422Smckusick 	if (MAXALLOCSAVE < CLBYTES)
19631422Smckusick 		panic("kmeminit: MAXALLOCSAVE too small");
19732509Skre 	rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE,
19831422Smckusick 		"malloc map", ekmempt - kmempt);
19931422Smckusick #ifdef KMEMSTATS
20031422Smckusick 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
20131422Smckusick 		if (1 << indx >= CLBYTES)
20231422Smckusick 			bucket[indx].kb_elmpercl = 1;
20331422Smckusick 		else
20431422Smckusick 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
20531422Smckusick 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
20631422Smckusick 	}
20731422Smckusick 	for (indx = 0; indx < M_LAST; indx++)
208*33438Smckusick 		kmemstats[indx].ks_limit =
209*33438Smckusick 			(ekmempt - kmempt) * CLBYTES * 9 / 10;
21031422Smckusick #endif
21131422Smckusick }
212