xref: /csrg-svn/sys/kern/kern_malloc.c (revision 32509)
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*32509Skre  *	@(#)kern_malloc.c	7.3 (Berkeley) 10/22/87
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;
2331422Smckusick 
2431422Smckusick /*
2531422Smckusick  * Allocate a block of memory
2631422Smckusick  */
2731422Smckusick qaddr_t malloc(size, type, flags)
2831422Smckusick 	unsigned long size;
2931422Smckusick 	long type, flags;
3031422Smckusick {
3131422Smckusick 	register struct kmembuckets *kbp;
3231422Smckusick 	register struct kmemusage *kup;
3331422Smckusick 	long indx, npg, alloc, allocsize, s;
3431422Smckusick 	caddr_t va, cp;
3531422Smckusick #ifdef KMEMSTATS
3631422Smckusick 	register struct kmemstats *ksp;
3731422Smckusick 
3831422Smckusick 	ksp = &kmemstats[type];
3931422Smckusick 	if (ksp->ks_inuse >= ksp->ks_limit)
4031422Smckusick 		return (0);
4131422Smckusick #endif
4231422Smckusick 	indx = BUCKETINDX(size);
4331422Smckusick 	kbp = &bucket[indx];
4431422Smckusick 	s = splimp();
4531422Smckusick 	if (kbp->kb_next == NULL) {
4631422Smckusick 		if (size > MAXALLOCSAVE)
4731422Smckusick 			allocsize = roundup(size, CLBYTES);
4831422Smckusick 		else
4931422Smckusick 			allocsize = 1 << indx;
5031422Smckusick 		npg = clrnd(btoc(allocsize));
5131422Smckusick 		if ((flags & M_NOWAIT) && freemem < npg) {
5231422Smckusick 			splx(s);
5331422Smckusick 			return (0);
5431422Smckusick 		}
5531422Smckusick 		alloc = rmalloc(kmemmap, npg);
5631422Smckusick 		if (alloc == 0) {
5731422Smckusick 			splx(s);
5831422Smckusick 			return (0);
5931422Smckusick 		}
6031422Smckusick 		if (vmemall(&kmempt[alloc], npg, &proc[0], CSYS) == 0) {
6131422Smckusick 			rmfree(kmemmap, npg, alloc);
6231422Smckusick 			splx(s);
6331422Smckusick 			return (0);
6431422Smckusick 		}
6531422Smckusick 		va = (caddr_t) kmemxtob(alloc);
6631422Smckusick 		vmaccess(&kmempt[alloc], va, npg);
6731422Smckusick #ifdef KMEMSTATS
6831422Smckusick 		kbp->kb_total += kbp->kb_elmpercl;
6931422Smckusick #endif
7031422Smckusick 		kup = btokup(va);
7131422Smckusick 		kup->ku_indx = indx;
7231422Smckusick 		if (allocsize > MAXALLOCSAVE) {
7331422Smckusick 			if (npg > 65535)
7431422Smckusick 				panic("malloc: allocation too large");
7531422Smckusick 			kup->ku_pagecnt = npg;
7631422Smckusick 			goto out;
7731422Smckusick 		}
7831422Smckusick #ifdef KMEMSTATS
7931422Smckusick 		kup->ku_freecnt = kbp->kb_elmpercl;
8031422Smckusick 		kbp->kb_totalfree += kbp->kb_elmpercl;
8131422Smckusick #endif
8231422Smckusick 		kbp->kb_next = va + (npg * NBPG) - allocsize;
8331422Smckusick 		for(cp = kbp->kb_next; cp > va; cp -= allocsize)
8431422Smckusick 			*(caddr_t *)cp = cp - allocsize;
8531422Smckusick 		*(caddr_t *)cp = NULL;
8631422Smckusick 	}
8731422Smckusick 	va = kbp->kb_next;
8831422Smckusick 	kbp->kb_next = *(caddr_t *)va;
8931422Smckusick #ifdef KMEMSTATS
9031422Smckusick 	kup = btokup(va);
9131422Smckusick 	if (kup->ku_indx != indx)
9231422Smckusick 		panic("malloc: wrong bucket");
9331422Smckusick 	if (kup->ku_freecnt == 0)
9431422Smckusick 		panic("malloc: lost data");
9531422Smckusick 	kup->ku_freecnt--;
9631422Smckusick 	kbp->kb_totalfree--;
9731422Smckusick out:
9831422Smckusick 	kbp->kb_calls++;
9931422Smckusick 	ksp->ks_inuse++;
10031422Smckusick 	ksp->ks_calls++;
10131422Smckusick 	if (ksp->ks_inuse > ksp->ks_maxused)
10231422Smckusick 		ksp->ks_maxused = ksp->ks_inuse;
10331422Smckusick #else
10431422Smckusick out:
10531422Smckusick #endif
10631422Smckusick 	splx(s);
10731422Smckusick 	return ((qaddr_t)va);
10831422Smckusick }
10931422Smckusick 
11031422Smckusick /*
11131422Smckusick  * Free a block of memory allocated by malloc.
11231422Smckusick  */
11331422Smckusick void free(addr, type)
11431422Smckusick 	caddr_t addr;
11531422Smckusick 	long type;
11631422Smckusick {
11731422Smckusick 	register struct kmembuckets *kbp;
11831422Smckusick 	register struct kmemusage *kup;
11931422Smckusick 	long alloc, s;
12031422Smckusick 
12131422Smckusick 	kup = btokup(addr);
12231422Smckusick 	s = splimp();
12331422Smckusick 	if (1 << kup->ku_indx > MAXALLOCSAVE) {
12431422Smckusick 		alloc = btokmemx(addr);
12531422Smckusick 		(void) memfree(&kmempt[alloc], kup->ku_pagecnt, 0);
12631422Smckusick 		rmfree(kmemmap, (long)kup->ku_pagecnt, alloc);
12731422Smckusick #ifdef KMEMSTATS
12831422Smckusick 		kup->ku_indx = 0;
12931422Smckusick 		kup->ku_pagecnt = 0;
13031422Smckusick 		kmemstats[type].ks_inuse--;
13131422Smckusick #endif
13231422Smckusick 		splx(s);
13331422Smckusick 		return;
13431422Smckusick 	}
13531422Smckusick 	kbp = &bucket[kup->ku_indx];
13631422Smckusick #ifdef KMEMSTATS
13731422Smckusick 	kup->ku_freecnt++;
13831422Smckusick 	if (kup->ku_freecnt >= kbp->kb_elmpercl)
13931422Smckusick 		if (kup->ku_freecnt > kbp->kb_elmpercl)
14031422Smckusick 			panic("free: multiple frees");
14131422Smckusick 		else if (kbp->kb_totalfree > kbp->kb_highwat)
14231422Smckusick 			kbp->kb_couldfree++;
14331422Smckusick 	kbp->kb_totalfree++;
14431422Smckusick 	kmemstats[type].ks_inuse--;
14531422Smckusick #endif
14631422Smckusick 	*(caddr_t *)addr = kbp->kb_next;
14731422Smckusick 	kbp->kb_next = addr;
14831422Smckusick 	splx(s);
14931422Smckusick }
15031422Smckusick 
15131422Smckusick /*
15231422Smckusick  * Initialize the kernel memory allocator
15331422Smckusick  */
15431422Smckusick kmeminit()
15531422Smckusick {
15631422Smckusick 	register long indx;
15731422Smckusick 
15831422Smckusick 	if (!powerof2(MAXALLOCSAVE))
15931422Smckusick 		panic("kmeminit: MAXALLOCSAVE not power of 2");
16031422Smckusick 	if (MAXALLOCSAVE > MINALLOCSIZE * 32768)
16131422Smckusick 		panic("kmeminit: MAXALLOCSAVE too big");
16231422Smckusick 	if (MAXALLOCSAVE < CLBYTES)
16331422Smckusick 		panic("kmeminit: MAXALLOCSAVE too small");
164*32509Skre 	rminit(kmemmap, ekmempt - kmempt, (long)CLSIZE,
16531422Smckusick 		"malloc map", ekmempt - kmempt);
16631422Smckusick #ifdef KMEMSTATS
16731422Smckusick 	for (indx = 0; indx < MINBUCKET + 16; indx++) {
16831422Smckusick 		if (1 << indx >= CLBYTES)
16931422Smckusick 			bucket[indx].kb_elmpercl = 1;
17031422Smckusick 		else
17131422Smckusick 			bucket[indx].kb_elmpercl = CLBYTES / (1 << indx);
17231422Smckusick 		bucket[indx].kb_highwat = 5 * bucket[indx].kb_elmpercl;
17331422Smckusick 	}
17431422Smckusick 	for (indx = 0; indx < M_LAST; indx++)
17531422Smckusick 		kmemstats[indx].ks_limit = 0x7fffffff;
17631422Smckusick #endif
17731422Smckusick }
178