xref: /plan9-contrib/sys/src/9k/port/qmalloc.c (revision f4d540d39d7147b15bff24e19c1798ed9234080c)
19ef1f84bSDavid du Colombier /*
29ef1f84bSDavid du Colombier  * malloc
39ef1f84bSDavid du Colombier  *
49ef1f84bSDavid du Colombier  *	Uses Quickfit (see SIGPLAN Notices October 1988)
59ef1f84bSDavid du Colombier  *	with allocator from Kernighan & Ritchie
69ef1f84bSDavid du Colombier  *
79ef1f84bSDavid du Colombier  * This is a placeholder.
89ef1f84bSDavid du Colombier  */
99ef1f84bSDavid du Colombier #include "u.h"
109ef1f84bSDavid du Colombier #include "../port/lib.h"
119ef1f84bSDavid du Colombier #include "mem.h"
129ef1f84bSDavid du Colombier #include "dat.h"
139ef1f84bSDavid du Colombier #include "fns.h"
149ef1f84bSDavid du Colombier 
159ef1f84bSDavid du Colombier typedef double Align;
169ef1f84bSDavid du Colombier typedef union Header Header;
179ef1f84bSDavid du Colombier typedef struct Qlist Qlist;
189ef1f84bSDavid du Colombier 
199ef1f84bSDavid du Colombier union Header {
209ef1f84bSDavid du Colombier 	struct {
219ef1f84bSDavid du Colombier 		Header*	next;
229ef1f84bSDavid du Colombier 		uint	size;
239ef1f84bSDavid du Colombier 	} s;
249ef1f84bSDavid du Colombier 	Align	al;
259ef1f84bSDavid du Colombier };
269ef1f84bSDavid du Colombier 
279ef1f84bSDavid du Colombier struct Qlist {
289ef1f84bSDavid du Colombier 	Lock	lk;
299ef1f84bSDavid du Colombier 	Header*	first;
309ef1f84bSDavid du Colombier 
319ef1f84bSDavid du Colombier 	uint	nalloc;
329ef1f84bSDavid du Colombier };
339ef1f84bSDavid du Colombier 
349ef1f84bSDavid du Colombier enum {
359ef1f84bSDavid du Colombier 	Unitsz		= sizeof(Header),
369ef1f84bSDavid du Colombier };
379ef1f84bSDavid du Colombier 
389ef1f84bSDavid du Colombier #define	NUNITS(n)	(HOWMANY(n, Unitsz) + 1)
399ef1f84bSDavid du Colombier #define	NQUICK		((4096/Unitsz)+1)
409ef1f84bSDavid du Colombier 
419ef1f84bSDavid du Colombier static	Qlist	quicklist[NQUICK+1];
429ef1f84bSDavid du Colombier static	Header	misclist;
439ef1f84bSDavid du Colombier static	Header	*rover;
449ef1f84bSDavid du Colombier static	unsigned tailsize;
459ef1f84bSDavid du Colombier static	unsigned availnunits;
469ef1f84bSDavid du Colombier static	Header	*tailbase;
479ef1f84bSDavid du Colombier static	Header	*tailptr;
489ef1f84bSDavid du Colombier static	Header	checkval;
499ef1f84bSDavid du Colombier static	int	morecore(unsigned);
509ef1f84bSDavid du Colombier 
519277c452SDavid du Colombier enum
529277c452SDavid du Colombier {
539277c452SDavid du Colombier 	QSmalign = 0,
549277c452SDavid du Colombier 	QSmalignquick,
559277c452SDavid du Colombier 	QSmalignrover,
569277c452SDavid du Colombier 	QSmalignfront,
579277c452SDavid du Colombier 	QSmalignback,
589277c452SDavid du Colombier 	QSmaligntail,
599277c452SDavid du Colombier 	QSmalignnottail,
609277c452SDavid du Colombier 	QSmalloc,
619277c452SDavid du Colombier 	QSmallocrover,
629277c452SDavid du Colombier 	QSmalloctail,
639277c452SDavid du Colombier 	QSfree,
649277c452SDavid du Colombier 	QSfreetail,
659277c452SDavid du Colombier 	QSfreequick,
669277c452SDavid du Colombier 	QSfreenext,
679277c452SDavid du Colombier 	QSfreeprev,
689277c452SDavid du Colombier 	QSmax
699277c452SDavid du Colombier };
709277c452SDavid du Colombier 
719277c452SDavid du Colombier static	char*	qstatstr[QSmax] = {
729277c452SDavid du Colombier [QSmalign]		"malign",
739277c452SDavid du Colombier [QSmalignquick]	"malignquick",
749277c452SDavid du Colombier [QSmalignrover]	"malignrover",
759277c452SDavid du Colombier [QSmalignfront]	"malignfront",
769277c452SDavid du Colombier [QSmalignback]	"malignback",
779277c452SDavid du Colombier [QSmaligntail]	"maligntail",
789277c452SDavid du Colombier [QSmalignnottail]	"malignnottail",
799277c452SDavid du Colombier [QSmalloc]		"malloc",
809277c452SDavid du Colombier [QSmallocrover]	"mallocrover",
819277c452SDavid du Colombier [QSmalloctail]	"malloctail",
829277c452SDavid du Colombier [QSfree]		"free",
839277c452SDavid du Colombier [QSfreetail]	"freetail",
849277c452SDavid du Colombier [QSfreequick]	"freequick",
859277c452SDavid du Colombier [QSfreenext]	"freenext",
869277c452SDavid du Colombier [QSfreeprev]	"freeprev",
879277c452SDavid du Colombier };
889277c452SDavid du Colombier 
899ef1f84bSDavid du Colombier static	void*	qmalloc(usize);
909ef1f84bSDavid du Colombier static	void	qfreeinternal(void*);
919277c452SDavid du Colombier static	int	qstats[QSmax];
929ef1f84bSDavid du Colombier 
939ef1f84bSDavid du Colombier static	Lock		mainlock;
949ef1f84bSDavid du Colombier 
959ef1f84bSDavid du Colombier #define	MLOCK		ilock(&mainlock)
969ef1f84bSDavid du Colombier #define	MUNLOCK		iunlock(&mainlock)
979ef1f84bSDavid du Colombier #define QLOCK(l)	ilock(l)
989ef1f84bSDavid du Colombier #define QUNLOCK(l)	iunlock(l)
999ef1f84bSDavid du Colombier 
1009ef1f84bSDavid du Colombier #define	tailalloc(p, n)	((p)=tailptr, tailsize -= (n), tailptr+=(n),\
1019ef1f84bSDavid du Colombier 			 (p)->s.size=(n), (p)->s.next = &checkval)
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier #define ISPOWEROF2(x)	(/*((x) != 0) && */!((x) & ((x)-1)))
1049ef1f84bSDavid du Colombier #define ALIGNHDR(h, a)	(Header*)((((uintptr)(h))+((a)-1)) & ~((a)-1))
1059ef1f84bSDavid du Colombier #define ALIGNED(h, a)	((((uintptr)(h)) & (a-1)) == 0)
1069ef1f84bSDavid du Colombier 
1079ef1f84bSDavid du Colombier static void*
qmallocalign(usize nbytes,uintptr align,long offset,usize span)1089ef1f84bSDavid du Colombier qmallocalign(usize nbytes, uintptr align, long offset, usize span)
1099ef1f84bSDavid du Colombier {
1109ef1f84bSDavid du Colombier 	Qlist *qlist;
1119ef1f84bSDavid du Colombier 	uintptr aligned;
1129ef1f84bSDavid du Colombier 	Header **pp, *p, *q, *r;
1139ef1f84bSDavid du Colombier 	uint naligned, nunits, n;
1149ef1f84bSDavid du Colombier 
1159ef1f84bSDavid du Colombier 	if(nbytes == 0 || offset != 0 || span != 0)
1169ef1f84bSDavid du Colombier 		return nil;
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 	if(!ISPOWEROF2(align))
1199ef1f84bSDavid du Colombier 		panic("qmallocalign");
1209ef1f84bSDavid du Colombier 
1219ef1f84bSDavid du Colombier 	if(align <= sizeof(Align))
1229ef1f84bSDavid du Colombier 		return qmalloc(nbytes);
1239ef1f84bSDavid du Colombier 
1249277c452SDavid du Colombier 	qstats[QSmalign]++;
1259ef1f84bSDavid du Colombier 	nunits = NUNITS(nbytes);
1269ef1f84bSDavid du Colombier 	if(nunits <= NQUICK){
1279ef1f84bSDavid du Colombier 		/*
1289ef1f84bSDavid du Colombier 		 * Look for a conveniently aligned block
1299ef1f84bSDavid du Colombier 		 * on one of the quicklists.
1309ef1f84bSDavid du Colombier 		 */
1319ef1f84bSDavid du Colombier 		qlist = &quicklist[nunits];
1329ef1f84bSDavid du Colombier 		QLOCK(&qlist->lk);
1339ef1f84bSDavid du Colombier 		pp = &qlist->first;
1349ef1f84bSDavid du Colombier 		for(p = *pp; p != nil; p = p->s.next){
1359ef1f84bSDavid du Colombier 			if(ALIGNED(p+1, align)){
1369ef1f84bSDavid du Colombier 				*pp = p->s.next;
1379ef1f84bSDavid du Colombier 				p->s.next = &checkval;
1389ef1f84bSDavid du Colombier 				QUNLOCK(&qlist->lk);
1399277c452SDavid du Colombier 				qstats[QSmalignquick]++;
1409ef1f84bSDavid du Colombier 				return p+1;
1419ef1f84bSDavid du Colombier 			}
1429ef1f84bSDavid du Colombier 			pp = &p->s.next;
1439ef1f84bSDavid du Colombier 		}
1449ef1f84bSDavid du Colombier 		QUNLOCK(&qlist->lk);
1459ef1f84bSDavid du Colombier 	}
1469ef1f84bSDavid du Colombier 
1479ef1f84bSDavid du Colombier 	MLOCK;
1489ef1f84bSDavid du Colombier 	if(nunits > tailsize) {
1499ef1f84bSDavid du Colombier 		/* hard way */
1509ef1f84bSDavid du Colombier 		if((q = rover) != nil){
1519ef1f84bSDavid du Colombier 			do {
1529ef1f84bSDavid du Colombier 				p = q->s.next;
1539ef1f84bSDavid du Colombier 				if(p->s.size < nunits)
1549ef1f84bSDavid du Colombier 					continue;
1559ef1f84bSDavid du Colombier 				aligned = ALIGNED(p+1, align);
1569ef1f84bSDavid du Colombier 				naligned = NUNITS(align)-1;
1579ef1f84bSDavid du Colombier 				if(!aligned && p->s.size < nunits+naligned)
1589ef1f84bSDavid du Colombier 					continue;
1599ef1f84bSDavid du Colombier 
1609ef1f84bSDavid du Colombier 				/*
1619ef1f84bSDavid du Colombier 				 * This block is big enough, remove it
1629ef1f84bSDavid du Colombier 				 * from the list.
1639ef1f84bSDavid du Colombier 				 */
1649ef1f84bSDavid du Colombier 				q->s.next = p->s.next;
1659ef1f84bSDavid du Colombier 				rover = q;
1669277c452SDavid du Colombier 				qstats[QSmalignrover]++;
1679ef1f84bSDavid du Colombier 
1689ef1f84bSDavid du Colombier 				/*
1699ef1f84bSDavid du Colombier 				 * Free any runt in front of the alignment.
1709ef1f84bSDavid du Colombier 				 */
1719ef1f84bSDavid du Colombier 				if(!aligned){
1729ef1f84bSDavid du Colombier 					r = p;
1739ef1f84bSDavid du Colombier 					p = ALIGNHDR(p+1, align) - 1;
1749ef1f84bSDavid du Colombier 					n = p - r;
1759ef1f84bSDavid du Colombier 					p->s.size = r->s.size - n;
1769ef1f84bSDavid du Colombier 
1779ef1f84bSDavid du Colombier 					r->s.size = n;
1789ef1f84bSDavid du Colombier 					r->s.next = &checkval;
1799ef1f84bSDavid du Colombier 					qfreeinternal(r+1);
1809277c452SDavid du Colombier 					qstats[QSmalignfront]++;
1819ef1f84bSDavid du Colombier 				}
1829ef1f84bSDavid du Colombier 
1839ef1f84bSDavid du Colombier 				/*
1849ef1f84bSDavid du Colombier 				 * Free any residue after the aligned block.
1859ef1f84bSDavid du Colombier 				 */
1869ef1f84bSDavid du Colombier 				if(p->s.size > nunits){
1879ef1f84bSDavid du Colombier 					r = p+nunits;
1889ef1f84bSDavid du Colombier 					r->s.size = p->s.size - nunits;
1899ef1f84bSDavid du Colombier 					r->s.next = &checkval;
1909277c452SDavid du Colombier 					qstats[QSmalignback]++;
1919ef1f84bSDavid du Colombier 					qfreeinternal(r+1);
1929ef1f84bSDavid du Colombier 
1939ef1f84bSDavid du Colombier 					p->s.size = nunits;
1949ef1f84bSDavid du Colombier 				}
1959ef1f84bSDavid du Colombier 
1969ef1f84bSDavid du Colombier 				p->s.next = &checkval;
1979ef1f84bSDavid du Colombier 				MUNLOCK;
1989ef1f84bSDavid du Colombier 				return p+1;
1999ef1f84bSDavid du Colombier 			} while((q = p) != rover);
2009ef1f84bSDavid du Colombier 		}
2019ef1f84bSDavid du Colombier 		if((n = morecore(nunits)) == 0){
2029ef1f84bSDavid du Colombier 			MUNLOCK;
2039ef1f84bSDavid du Colombier 			return nil;
2049ef1f84bSDavid du Colombier 		}
2059ef1f84bSDavid du Colombier 		tailsize += n;
2069ef1f84bSDavid du Colombier 	}
2079ef1f84bSDavid du Colombier 
2089ef1f84bSDavid du Colombier 	q = ALIGNHDR(tailptr+1, align);
2099ef1f84bSDavid du Colombier 	if(q == tailptr+1){
2109ef1f84bSDavid du Colombier 		tailalloc(p, nunits);
2119277c452SDavid du Colombier 		qstats[QSmaligntail]++;
2129ef1f84bSDavid du Colombier 	}
2139ef1f84bSDavid du Colombier 	else{
2149ef1f84bSDavid du Colombier 		naligned = NUNITS(align)-1;
2159ef1f84bSDavid du Colombier 		if(tailsize < nunits+naligned){
2169ef1f84bSDavid du Colombier 			/*
2179ef1f84bSDavid du Colombier 			 * There are at least nunits,
2189ef1f84bSDavid du Colombier 			 * get enough for alignment.
2199ef1f84bSDavid du Colombier 			 */
2209ef1f84bSDavid du Colombier 			if((n = morecore(naligned)) == 0){
2219ef1f84bSDavid du Colombier 				MUNLOCK;
2229ef1f84bSDavid du Colombier 				return nil;
2239ef1f84bSDavid du Colombier 			}
2249ef1f84bSDavid du Colombier 			tailsize += n;
2259ef1f84bSDavid du Colombier 		}
2269ef1f84bSDavid du Colombier 		/*
2279ef1f84bSDavid du Colombier 		 * Save the residue before the aligned allocation
2289ef1f84bSDavid du Colombier 		 * and free it after the tail pointer has been bumped
2299ef1f84bSDavid du Colombier 		 * for the main allocation.
2309ef1f84bSDavid du Colombier 		 */
2319ef1f84bSDavid du Colombier 		n = q-tailptr - 1;
2329ef1f84bSDavid du Colombier 		tailalloc(r, n);
2339ef1f84bSDavid du Colombier 		tailalloc(p, nunits);
2349277c452SDavid du Colombier 		qstats[QSmalignnottail]++;
2359ef1f84bSDavid du Colombier 		qfreeinternal(r+1);
2369ef1f84bSDavid du Colombier 	}
2379ef1f84bSDavid du Colombier 	MUNLOCK;
2389ef1f84bSDavid du Colombier 
2399ef1f84bSDavid du Colombier 	return p+1;
2409ef1f84bSDavid du Colombier }
2419ef1f84bSDavid du Colombier 
2429ef1f84bSDavid du Colombier static void*
qmalloc(usize nbytes)2439ef1f84bSDavid du Colombier qmalloc(usize nbytes)
2449ef1f84bSDavid du Colombier {
2459ef1f84bSDavid du Colombier 	Qlist *qlist;
2469ef1f84bSDavid du Colombier 	Header *p, *q;
2479ef1f84bSDavid du Colombier 	uint nunits, n;
2489ef1f84bSDavid du Colombier 
2499ef1f84bSDavid du Colombier ///* FIXME: (ignore for now)
2509ef1f84bSDavid du Colombier 	if(nbytes == 0)
2519ef1f84bSDavid du Colombier 		return nil;
2529ef1f84bSDavid du Colombier //*/
2539ef1f84bSDavid du Colombier 
2549277c452SDavid du Colombier 	qstats[QSmalloc]++;
2559ef1f84bSDavid du Colombier 	nunits = NUNITS(nbytes);
2569ef1f84bSDavid du Colombier 	if(nunits <= NQUICK){
2579ef1f84bSDavid du Colombier 		qlist = &quicklist[nunits];
2589ef1f84bSDavid du Colombier 		QLOCK(&qlist->lk);
2599ef1f84bSDavid du Colombier 		if((p = qlist->first) != nil){
2609ef1f84bSDavid du Colombier 			qlist->first = p->s.next;
2619ef1f84bSDavid du Colombier 			qlist->nalloc++;
2629ef1f84bSDavid du Colombier 			QUNLOCK(&qlist->lk);
2639ef1f84bSDavid du Colombier 			p->s.next = &checkval;
2649ef1f84bSDavid du Colombier 			return p+1;
2659ef1f84bSDavid du Colombier 		}
2669ef1f84bSDavid du Colombier 		QUNLOCK(&qlist->lk);
2679ef1f84bSDavid du Colombier 	}
2689ef1f84bSDavid du Colombier 
2699ef1f84bSDavid du Colombier 	MLOCK;
2709ef1f84bSDavid du Colombier 	if(nunits > tailsize) {
2719ef1f84bSDavid du Colombier 		/* hard way */
2729ef1f84bSDavid du Colombier 		if((q = rover) != nil){
2739ef1f84bSDavid du Colombier 			do {
2749ef1f84bSDavid du Colombier 				p = q->s.next;
2759ef1f84bSDavid du Colombier 				if(p->s.size >= nunits) {
2769ef1f84bSDavid du Colombier 					if(p->s.size > nunits) {
2779ef1f84bSDavid du Colombier 						p->s.size -= nunits;
2789ef1f84bSDavid du Colombier 						p += p->s.size;
2799ef1f84bSDavid du Colombier 						p->s.size = nunits;
2809ef1f84bSDavid du Colombier 					} else
2819ef1f84bSDavid du Colombier 						q->s.next = p->s.next;
2829ef1f84bSDavid du Colombier 					p->s.next = &checkval;
2839ef1f84bSDavid du Colombier 					rover = q;
2849277c452SDavid du Colombier 					qstats[QSmallocrover]++;
2859ef1f84bSDavid du Colombier 					MUNLOCK;
2869ef1f84bSDavid du Colombier 					return p+1;
2879ef1f84bSDavid du Colombier 				}
2889ef1f84bSDavid du Colombier 			} while((q = p) != rover);
2899ef1f84bSDavid du Colombier 		}
2909ef1f84bSDavid du Colombier 		if((n = morecore(nunits)) == 0){
2919ef1f84bSDavid du Colombier 			MUNLOCK;
2929ef1f84bSDavid du Colombier 			return nil;
2939ef1f84bSDavid du Colombier 		}
2949ef1f84bSDavid du Colombier 		tailsize += n;
2959ef1f84bSDavid du Colombier 	}
2969277c452SDavid du Colombier 	qstats[QSmalloctail]++;
2979ef1f84bSDavid du Colombier 	tailalloc(p, nunits);
2989ef1f84bSDavid du Colombier 	MUNLOCK;
2999ef1f84bSDavid du Colombier 
3009ef1f84bSDavid du Colombier 	return p+1;
3019ef1f84bSDavid du Colombier }
3029ef1f84bSDavid du Colombier 
3039ef1f84bSDavid du Colombier static void
qfreeinternal(void * ap)3049ef1f84bSDavid du Colombier qfreeinternal(void* ap)
3059ef1f84bSDavid du Colombier {
3069ef1f84bSDavid du Colombier 	Qlist *qlist;
3079ef1f84bSDavid du Colombier 	Header *p, *q;
3089ef1f84bSDavid du Colombier 	uint nunits;
3099ef1f84bSDavid du Colombier 
3109ef1f84bSDavid du Colombier 	if(ap == nil)
3119ef1f84bSDavid du Colombier 		return;
3129277c452SDavid du Colombier 	qstats[QSfree]++;
3139ef1f84bSDavid du Colombier 
3149ef1f84bSDavid du Colombier 	p = (Header*)ap - 1;
3159ef1f84bSDavid du Colombier 	if((nunits = p->s.size) == 0 || p->s.next != &checkval)
3169ef1f84bSDavid du Colombier 		panic("malloc: corrupt allocation arena");
3179ef1f84bSDavid du Colombier 	if(tailptr != nil && p+nunits == tailptr) {
3189ef1f84bSDavid du Colombier 		/* block before tail */
3199ef1f84bSDavid du Colombier 		tailptr = p;
3209ef1f84bSDavid du Colombier 		tailsize += nunits;
3219277c452SDavid du Colombier 		qstats[QSfreetail]++;
3229ef1f84bSDavid du Colombier 		return;
3239ef1f84bSDavid du Colombier 	}
3249ef1f84bSDavid du Colombier 	if(nunits <= NQUICK) {
3259ef1f84bSDavid du Colombier 		qlist = &quicklist[nunits];
3269ef1f84bSDavid du Colombier 		QLOCK(&qlist->lk);
3279ef1f84bSDavid du Colombier 		p->s.next = qlist->first;
3289ef1f84bSDavid du Colombier 		qlist->first = p;
3299ef1f84bSDavid du Colombier 		QUNLOCK(&qlist->lk);
3309277c452SDavid du Colombier 		qstats[QSfreequick]++;
3319ef1f84bSDavid du Colombier 		return;
3329ef1f84bSDavid du Colombier 	}
3339ef1f84bSDavid du Colombier 	if((q = rover) == nil) {
3349ef1f84bSDavid du Colombier 		q = &misclist;
3359ef1f84bSDavid du Colombier 		q->s.size = 0;
3369ef1f84bSDavid du Colombier 		q->s.next = q;
3379ef1f84bSDavid du Colombier 	}
3389ef1f84bSDavid du Colombier 	for(; !(p > q && p < q->s.next); q = q->s.next)
3399ef1f84bSDavid du Colombier 		if(q >= q->s.next && (p > q || p < q->s.next))
3409ef1f84bSDavid du Colombier 			break;
3419ef1f84bSDavid du Colombier 	if(p+p->s.size == q->s.next) {
3429ef1f84bSDavid du Colombier 		p->s.size += q->s.next->s.size;
3439ef1f84bSDavid du Colombier 		p->s.next = q->s.next->s.next;
3449277c452SDavid du Colombier 		qstats[QSfreenext]++;
3459ef1f84bSDavid du Colombier 	} else
3469ef1f84bSDavid du Colombier 		p->s.next = q->s.next;
3479ef1f84bSDavid du Colombier 	if(q+q->s.size == p) {
3489ef1f84bSDavid du Colombier 		q->s.size += p->s.size;
3499ef1f84bSDavid du Colombier 		q->s.next = p->s.next;
3509277c452SDavid du Colombier 		qstats[QSfreeprev]++;
3519ef1f84bSDavid du Colombier 	} else
3529ef1f84bSDavid du Colombier 		q->s.next = p;
3539ef1f84bSDavid du Colombier 	rover = q;
3549ef1f84bSDavid du Colombier }
3559ef1f84bSDavid du Colombier 
3569ef1f84bSDavid du Colombier static void
mallocreadfmt(char * s,char * e)3579ef1f84bSDavid du Colombier mallocreadfmt(char* s, char* e)
3589ef1f84bSDavid du Colombier {
3599ef1f84bSDavid du Colombier 	char *p;
3609ef1f84bSDavid du Colombier 	Header *q;
3619ef1f84bSDavid du Colombier 	int i, n, t;
3629ef1f84bSDavid du Colombier 	Qlist *qlist;
3639ef1f84bSDavid du Colombier 
3649ef1f84bSDavid du Colombier 	p = s;
3659ef1f84bSDavid du Colombier 	p = seprint(p, e, "%lud/%lud kernel malloc\n",
3669ef1f84bSDavid du Colombier 		(tailptr-tailbase)*sizeof(Header),
3679ef1f84bSDavid du Colombier 		(tailsize+availnunits + tailptr-tailbase)*sizeof(Header));
3689ef1f84bSDavid du Colombier 	p = seprint(p, e, "0/0 kernel draw\n"); // keep scripts happy
3699ef1f84bSDavid du Colombier 
3709ef1f84bSDavid du Colombier 	t = 0;
3719ef1f84bSDavid du Colombier 	for(i = 0; i <= NQUICK; i++) {
3729ef1f84bSDavid du Colombier 		n = 0;
3739ef1f84bSDavid du Colombier 		qlist = &quicklist[i];
3749ef1f84bSDavid du Colombier 		QLOCK(&qlist->lk);
3759ef1f84bSDavid du Colombier 		for(q = qlist->first; q != nil; q = q->s.next){
3769ef1f84bSDavid du Colombier //			if(q->s.size != i)
3779ef1f84bSDavid du Colombier //				p = seprint(p, e, "q%d\t%#p\t%ud\n",
3789ef1f84bSDavid du Colombier //					i, q, q->s.size);
3799ef1f84bSDavid du Colombier 			n++;
3809ef1f84bSDavid du Colombier 		}
3819ef1f84bSDavid du Colombier 		QUNLOCK(&qlist->lk);
3829ef1f84bSDavid du Colombier 
3839ef1f84bSDavid du Colombier //		if(n != 0)
3849ef1f84bSDavid du Colombier //			p = seprint(p, e, "q%d %d\n", i, n);
3859ef1f84bSDavid du Colombier 		t += n * i*sizeof(Header);
3869ef1f84bSDavid du Colombier 	}
3879ef1f84bSDavid du Colombier 	p = seprint(p, e, "quick: %ud bytes total\n", t);
3889ef1f84bSDavid du Colombier 
3899ef1f84bSDavid du Colombier 	MLOCK;
3909ef1f84bSDavid du Colombier 	if((q = rover) != nil){
3919ef1f84bSDavid du Colombier 		i = t = 0;
3929ef1f84bSDavid du Colombier 		do {
3939ef1f84bSDavid du Colombier 			t += q->s.size;
3949ef1f84bSDavid du Colombier 			i++;
3959ef1f84bSDavid du Colombier //			p = seprint(p, e, "m%d\t%#p\n", q->s.size, q);
3969ef1f84bSDavid du Colombier 		} while((q = q->s.next) != rover);
3979ef1f84bSDavid du Colombier 
3989ef1f84bSDavid du Colombier 		p = seprint(p, e, "rover: %d blocks %ud bytes total\n",
3999ef1f84bSDavid du Colombier 			i, t*sizeof(Header));
4009ef1f84bSDavid du Colombier 	}
4019ef1f84bSDavid du Colombier 
4029ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(qstats); i++){
4039ef1f84bSDavid du Colombier 		if(qstats[i] == 0)
4049ef1f84bSDavid du Colombier 			continue;
4059277c452SDavid du Colombier //		p = seprint(p, e, "%s %ud\n", qstatstr[i], qstats[i]);
4069ef1f84bSDavid du Colombier 	}
4079ef1f84bSDavid du Colombier 	USED(p);
4089ef1f84bSDavid du Colombier 	MUNLOCK;
4099ef1f84bSDavid du Colombier }
4109ef1f84bSDavid du Colombier 
4119ef1f84bSDavid du Colombier long
mallocreadsummary(Chan *,void * a,long n,long offset)4129ef1f84bSDavid du Colombier mallocreadsummary(Chan*, void *a, long n, long offset)
4139ef1f84bSDavid du Colombier {
4149ef1f84bSDavid du Colombier 	char *alloc;
4159ef1f84bSDavid du Colombier 
4169ef1f84bSDavid du Colombier 	alloc = malloc(16*READSTR);
4179ef1f84bSDavid du Colombier 	if(waserror()){
4189ef1f84bSDavid du Colombier 		free(alloc);
4199ef1f84bSDavid du Colombier 		nexterror();
4209ef1f84bSDavid du Colombier 	}
4219ef1f84bSDavid du Colombier 	mallocreadfmt(alloc, alloc+16*READSTR);
4229ef1f84bSDavid du Colombier 	n = readstr(offset, a, n, alloc);
4239ef1f84bSDavid du Colombier 	poperror();
4249ef1f84bSDavid du Colombier 	free(alloc);
4259ef1f84bSDavid du Colombier 
4269ef1f84bSDavid du Colombier 	return n;
4279ef1f84bSDavid du Colombier }
4289ef1f84bSDavid du Colombier 
4299ef1f84bSDavid du Colombier void
mallocsummary(void)4309ef1f84bSDavid du Colombier mallocsummary(void)
4319ef1f84bSDavid du Colombier {
4329ef1f84bSDavid du Colombier 	Header *q;
4339ef1f84bSDavid du Colombier 	int i, n, t;
4349ef1f84bSDavid du Colombier 	Qlist *qlist;
4359ef1f84bSDavid du Colombier 
4369ef1f84bSDavid du Colombier 	t = 0;
4379ef1f84bSDavid du Colombier 	for(i = 0; i <= NQUICK; i++) {
4389ef1f84bSDavid du Colombier 		n = 0;
4399ef1f84bSDavid du Colombier 		qlist = &quicklist[i];
4409ef1f84bSDavid du Colombier 		QLOCK(&qlist->lk);
4419ef1f84bSDavid du Colombier 		for(q = qlist->first; q != nil; q = q->s.next){
4429ef1f84bSDavid du Colombier 			if(q->s.size != i)
4439ef1f84bSDavid du Colombier 				DBG("q%d\t%#p\t%ud\n", i, q, q->s.size);
4449ef1f84bSDavid du Colombier 			n++;
4459ef1f84bSDavid du Colombier 		}
4469ef1f84bSDavid du Colombier 		QUNLOCK(&qlist->lk);
4479ef1f84bSDavid du Colombier 
4489ef1f84bSDavid du Colombier 		t += n * i*sizeof(Header);
4499ef1f84bSDavid du Colombier 	}
4509ef1f84bSDavid du Colombier 	print("quick: %ud bytes total\n", t);
4519ef1f84bSDavid du Colombier 
4529ef1f84bSDavid du Colombier 	MLOCK;
4539ef1f84bSDavid du Colombier 	if((q = rover) != nil){
4549ef1f84bSDavid du Colombier 		i = t = 0;
4559ef1f84bSDavid du Colombier 		do {
4569ef1f84bSDavid du Colombier 			t += q->s.size;
4579ef1f84bSDavid du Colombier 			i++;
4589ef1f84bSDavid du Colombier 		} while((q = q->s.next) != rover);
4599ef1f84bSDavid du Colombier 	}
4609ef1f84bSDavid du Colombier 	MUNLOCK;
4619ef1f84bSDavid du Colombier 
4629ef1f84bSDavid du Colombier 	if(i != 0){
4639ef1f84bSDavid du Colombier 		print("rover: %d blocks %ud bytes total\n",
4649ef1f84bSDavid du Colombier 			i, t*sizeof(Header));
4659ef1f84bSDavid du Colombier 	}
4669ef1f84bSDavid du Colombier 	print("total allocated %lud, %ud remaining\n",
4679ef1f84bSDavid du Colombier 		(tailptr-tailbase)*sizeof(Header),
4689ef1f84bSDavid du Colombier 		(tailsize+availnunits)*sizeof(Header));
4699ef1f84bSDavid du Colombier 
4709ef1f84bSDavid du Colombier 	for(i = 0; i < nelem(qstats); i++){
4719ef1f84bSDavid du Colombier 		if(qstats[i] == 0)
4729ef1f84bSDavid du Colombier 			continue;
4739277c452SDavid du Colombier 		print("%s %ud\n", qstatstr[i], qstats[i]);
4749ef1f84bSDavid du Colombier 	}
4759ef1f84bSDavid du Colombier }
4769ef1f84bSDavid du Colombier 
4779ef1f84bSDavid du Colombier void
free(void * ap)4789ef1f84bSDavid du Colombier free(void* ap)
4799ef1f84bSDavid du Colombier {
4809ef1f84bSDavid du Colombier 	MLOCK;
4819ef1f84bSDavid du Colombier 	qfreeinternal(ap);
4829ef1f84bSDavid du Colombier 	MUNLOCK;
4839ef1f84bSDavid du Colombier }
4849ef1f84bSDavid du Colombier 
4859ef1f84bSDavid du Colombier void*
malloc(ulong size)4869ef1f84bSDavid du Colombier malloc(ulong size)
4879ef1f84bSDavid du Colombier {
4889ef1f84bSDavid du Colombier 	void* v;
4899ef1f84bSDavid du Colombier 
4909ef1f84bSDavid du Colombier 	if((v = qmalloc(size)) != nil)
4919ef1f84bSDavid du Colombier 		memset(v, 0, size);
4929ef1f84bSDavid du Colombier 
4939ef1f84bSDavid du Colombier 	return v;
4949ef1f84bSDavid du Colombier }
4959ef1f84bSDavid du Colombier 
4969ef1f84bSDavid du Colombier void*
mallocz(ulong size,int clr)4979ef1f84bSDavid du Colombier mallocz(ulong size, int clr)
4989ef1f84bSDavid du Colombier {
4999ef1f84bSDavid du Colombier 	void *v;
5009ef1f84bSDavid du Colombier 
5019ef1f84bSDavid du Colombier 	if((v = qmalloc(size)) != nil && clr)
5029ef1f84bSDavid du Colombier 		memset(v, 0, size);
5039ef1f84bSDavid du Colombier 
5049ef1f84bSDavid du Colombier 	return v;
5059ef1f84bSDavid du Colombier }
5069ef1f84bSDavid du Colombier 
5079ef1f84bSDavid du Colombier void*
mallocalign(ulong nbytes,ulong align,long offset,ulong span)5089ef1f84bSDavid du Colombier mallocalign(ulong nbytes, ulong align, long offset, ulong span)
5099ef1f84bSDavid du Colombier {
5109ef1f84bSDavid du Colombier 	void *v;
5119ef1f84bSDavid du Colombier 
5129ef1f84bSDavid du Colombier 	if(span != 0 && align <= span){
5139ef1f84bSDavid du Colombier 		if(nbytes > span)
5149ef1f84bSDavid du Colombier 			return nil;
5159ef1f84bSDavid du Colombier 		align = span;
5169ef1f84bSDavid du Colombier 		span = 0;
5179ef1f84bSDavid du Colombier 	}
5189ef1f84bSDavid du Colombier 
5199ef1f84bSDavid du Colombier 	/*
5209ef1f84bSDavid du Colombier 	 * Should this memset or should it be left to the caller?
5219ef1f84bSDavid du Colombier 	 */
5229ef1f84bSDavid du Colombier 	if((v = qmallocalign(nbytes, align, offset, span)) != nil)
5239ef1f84bSDavid du Colombier 		memset(v, 0, nbytes);
5249ef1f84bSDavid du Colombier 
5259ef1f84bSDavid du Colombier 	return v;
5269ef1f84bSDavid du Colombier }
5279ef1f84bSDavid du Colombier 
5289ef1f84bSDavid du Colombier void*
smalloc(ulong size)5299ef1f84bSDavid du Colombier smalloc(ulong size)
5309ef1f84bSDavid du Colombier {
5319ef1f84bSDavid du Colombier 	void *v;
5329ef1f84bSDavid du Colombier 
5339ef1f84bSDavid du Colombier 	while((v = malloc(size)) == nil)
5349ef1f84bSDavid du Colombier 		tsleep(&up->sleep, return0, 0, 100);
5359ef1f84bSDavid du Colombier 	memset(v, 0, size);
5369ef1f84bSDavid du Colombier 
5379ef1f84bSDavid du Colombier 	return v;
5389ef1f84bSDavid du Colombier }
5399ef1f84bSDavid du Colombier 
5409ef1f84bSDavid du Colombier void*
realloc(void * ap,ulong size)5419ef1f84bSDavid du Colombier realloc(void* ap, ulong size)
5429ef1f84bSDavid du Colombier {
5439ef1f84bSDavid du Colombier 	void *v;
5449ef1f84bSDavid du Colombier 	Header *p;
5459ef1f84bSDavid du Colombier 	ulong osize;
5469ef1f84bSDavid du Colombier 	uint nunits, ounits;
5479ef1f84bSDavid du Colombier 	int delta;
5489ef1f84bSDavid du Colombier 
5499ef1f84bSDavid du Colombier 	/*
5509ef1f84bSDavid du Colombier 	 * Easy stuff:
5519ef1f84bSDavid du Colombier 	 * free and return nil if size is 0
5529ef1f84bSDavid du Colombier 	 * (implementation-defined behaviour);
5539ef1f84bSDavid du Colombier 	 * behave like malloc if ap is nil;
5549ef1f84bSDavid du Colombier 	 * check for arena corruption;
5559ef1f84bSDavid du Colombier 	 * do nothing if units are the same.
5569ef1f84bSDavid du Colombier 	 */
5579ef1f84bSDavid du Colombier 	if(size == 0){
5589ef1f84bSDavid du Colombier 		MLOCK;
5599ef1f84bSDavid du Colombier 		qfreeinternal(ap);
5609ef1f84bSDavid du Colombier 		MUNLOCK;
5619ef1f84bSDavid du Colombier 
5629ef1f84bSDavid du Colombier 		return nil;
5639ef1f84bSDavid du Colombier 	}
5649ef1f84bSDavid du Colombier 	if(ap == nil)
5659ef1f84bSDavid du Colombier 		return qmalloc(size);
5669ef1f84bSDavid du Colombier 
5679ef1f84bSDavid du Colombier 	p = (Header*)ap - 1;
5689ef1f84bSDavid du Colombier 	if((ounits = p->s.size) == 0 || p->s.next != &checkval)
5699ef1f84bSDavid du Colombier 		panic("realloc: corrupt allocation arena");
5709ef1f84bSDavid du Colombier 
5719ef1f84bSDavid du Colombier 	if((nunits = NUNITS(size)) == ounits)
5729ef1f84bSDavid du Colombier 		return ap;
5739ef1f84bSDavid du Colombier 
5749ef1f84bSDavid du Colombier 	/*
5759ef1f84bSDavid du Colombier 	 * Slightly harder:
5769ef1f84bSDavid du Colombier 	 * if this allocation abuts the tail, try to just
5779ef1f84bSDavid du Colombier 	 * adjust the tailptr.
5789ef1f84bSDavid du Colombier 	 */
5799ef1f84bSDavid du Colombier 	MLOCK;
5809ef1f84bSDavid du Colombier 	if(tailptr != nil && p+ounits == tailptr){
5819ef1f84bSDavid du Colombier 		delta = nunits-ounits;
5829ef1f84bSDavid du Colombier 		if(delta < 0 || tailsize >= delta){
5839ef1f84bSDavid du Colombier 			p->s.size = nunits;
5849ef1f84bSDavid du Colombier 			tailsize -= delta;
5859ef1f84bSDavid du Colombier 			tailptr += delta;
5869ef1f84bSDavid du Colombier 			MUNLOCK;
5879ef1f84bSDavid du Colombier 			return ap;
5889ef1f84bSDavid du Colombier 		}
5899ef1f84bSDavid du Colombier 	}
5909ef1f84bSDavid du Colombier 	MUNLOCK;
5919ef1f84bSDavid du Colombier 
5929ef1f84bSDavid du Colombier 	/*
5939ef1f84bSDavid du Colombier 	 * Worth doing if it's a small reduction?
5949ef1f84bSDavid du Colombier 	 * Do it anyway if <= NQUICK?
5959ef1f84bSDavid du Colombier 	if((ounits-nunits) < 2)
5969ef1f84bSDavid du Colombier 		return ap;
5979ef1f84bSDavid du Colombier 	 */
5989ef1f84bSDavid du Colombier 
5999ef1f84bSDavid du Colombier 	/*
6009ef1f84bSDavid du Colombier 	 * Too hard (or can't be bothered):
6019ef1f84bSDavid du Colombier 	 * allocate, copy and free.
6029ef1f84bSDavid du Colombier 	 * What does the standard say for failure here?
6039ef1f84bSDavid du Colombier 	 */
6049ef1f84bSDavid du Colombier 	if((v = qmalloc(size)) != nil){
6059ef1f84bSDavid du Colombier 		osize = (ounits-1)*sizeof(Header);
6069ef1f84bSDavid du Colombier 		if(size < osize)
6079ef1f84bSDavid du Colombier 			osize = size;
6089ef1f84bSDavid du Colombier 		memmove(v, ap, osize);
6099ef1f84bSDavid du Colombier 		MLOCK;
6109ef1f84bSDavid du Colombier 		qfreeinternal(ap);
6119ef1f84bSDavid du Colombier 		MUNLOCK;
6129ef1f84bSDavid du Colombier 	}
6139ef1f84bSDavid du Colombier 
6149ef1f84bSDavid du Colombier 	return v;
6159ef1f84bSDavid du Colombier }
6169ef1f84bSDavid du Colombier 
6179ef1f84bSDavid du Colombier void
setmalloctag(void *,ulong)6189ef1f84bSDavid du Colombier setmalloctag(void*, ulong)
6199ef1f84bSDavid du Colombier {
6209ef1f84bSDavid du Colombier }
6219ef1f84bSDavid du Colombier 
6229ef1f84bSDavid du Colombier void
mallocinit(void)6239ef1f84bSDavid du Colombier mallocinit(void)
6249ef1f84bSDavid du Colombier {
6259ef1f84bSDavid du Colombier 	if(tailptr != nil)
6269ef1f84bSDavid du Colombier 		return;
6279ef1f84bSDavid du Colombier 
6289ef1f84bSDavid du Colombier 	tailbase = UINT2PTR(sys->vmunused);
6299ef1f84bSDavid du Colombier 	tailptr = tailbase;
6309ef1f84bSDavid du Colombier 	availnunits = HOWMANY(sys->vmend - sys->vmunused, Unitsz);
6319ef1f84bSDavid du Colombier 	print("base %#p ptr %#p nunits %ud\n", tailbase, tailptr, availnunits);
6329ef1f84bSDavid du Colombier }
6339ef1f84bSDavid du Colombier 
6349ef1f84bSDavid du Colombier static int
morecore(uint nunits)6359ef1f84bSDavid du Colombier morecore(uint nunits)
6369ef1f84bSDavid du Colombier {
6379ef1f84bSDavid du Colombier 	/*
6389ef1f84bSDavid du Colombier 	 * First (simple) cut.
6399ef1f84bSDavid du Colombier 	 * Pump it up when you don't really need it.
6409ef1f84bSDavid du Colombier 	 * Pump it up until you can feel it.
6419ef1f84bSDavid du Colombier 	 */
642*f4d540d3SDavid du Colombier 	if(nunits < NUNITS(128*KiB))
6439ef1f84bSDavid du Colombier 		nunits = NUNITS(128*KiB);
644*f4d540d3SDavid du Colombier  	if(nunits > availnunits)
645*f4d540d3SDavid du Colombier 		nunits = availnunits;
6469ef1f84bSDavid du Colombier 	availnunits -= nunits;
6479ef1f84bSDavid du Colombier 
6489ef1f84bSDavid du Colombier 	return nunits;
6499ef1f84bSDavid du Colombier }
650