summaryrefslogblamecommitdiffstats
path: root/private/ntos/boot/veneer/vrmalloc.c
blob: c0872f2546dd2c60f669a17af50a22b9cd19a229 (plain) (tree)


































































































































































































































































































































































                                                                                                   
/*
 *
 * Copyright 1994 FirmWorks, Mountain View CA USA. All rights reserved.
 * Copyright (c) 1995 FirePower Systems, Inc.
 *
 * $RCSfile: vrmalloc.c $
 * $Revision: 1.6 $
 * $Date: 1996/02/17 00:41:29 $
 * $Locker:  $
 *
 *
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 * A  "smarter" malloc				William L. Sebok
 *						Sept. 24, 1984
 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 *	 If n = the size of an area rounded DOWN to the nearest power of two,
 *	all free areas of memory whose length is the same index n is organized
 *	into a chain with other free areas of index n. A request for memory
 *	takes the first item in the chain whose index is the size of the
 *	request rounded UP to the nearest power of two.  If this chain is
 *	empty the next higher chain is examined.  If no larger chain has memory
 *	then new memory is allocated.  Only the amount of new memory needed is
 *	allocated.  Any old free memory left after an allocation is returned
 *	to the free list.  Extra new memory returned because of rounding
 *	to page boundaries is returned to free list.
 *
 *	  All memory areas (free or busy) handled by malloc are also chained
 *	sequentially by increasing address.  When memory is freed it is
 *	merged with adjacent free areas, if any.  If a free area of memory
 *	ends at the end of memory (i.e. at the break),  the break is
 *	contracted, freeing the memory back to the system.
 *
 *	Notes:
 *		ov_length field includes sizeof(struct overhead)
 *		adjacency chain includes all memory, allocated plus free.
 */

#include "veneer.h"

#define	MAGIC_FREE	0x548a934c
#define	MAGIC_BUSY	0xc139569a

#define NBUCKETS	24
#define NALIGN		4

struct qelem {
	struct qelem *q_forw;
	struct qelem *q_back;
};

struct overhead {
	struct qelem	ov_adj;		/* adjacency chain pointers */
	struct qelem	ov_buk;		/* bucket chain pointers */
	long		ov_magic;
	unsigned long	ov_length;
};

char endfree = 0;
struct qelem adjhead = { &adjhead, &adjhead };
struct qelem buckets[NBUCKETS] = {
	&buckets[0],  &buckets[0],
	&buckets[1],  &buckets[1],
	&buckets[2],  &buckets[2],
	&buckets[3],  &buckets[3],
	&buckets[4],  &buckets[4],
	&buckets[5],  &buckets[5],
	&buckets[6],  &buckets[6],
	&buckets[7],  &buckets[7],
	&buckets[8],  &buckets[8],
	&buckets[9],  &buckets[9],
	&buckets[10], &buckets[10],
	&buckets[11], &buckets[11],
	&buckets[12], &buckets[12],
	&buckets[13], &buckets[13],
	&buckets[14], &buckets[14],
	&buckets[15], &buckets[15],
	&buckets[16], &buckets[16],
	&buckets[17], &buckets[17],
	&buckets[18], &buckets[18],
	&buckets[19], &buckets[19],
	&buckets[20], &buckets[20],
	&buckets[21], &buckets[21],
	&buckets[22], &buckets[22],
	&buckets[23], &buckets[23],
};

/*
 * The following macros depend on the order of the elements in struct overhead
 */
#define TOADJ(p)	((struct qelem *)(p))
#define FROMADJ(p)	((struct overhead *)(p))
#define FROMBUK(p)	((struct overhead *)( (char *)p - sizeof(struct qelem)))
#define TOBUK(p)	((struct qelem *)( (char *)p + sizeof(struct qelem)))

#ifndef CURBRK
#define CURBRK	sbrk(0)
#endif CURBRK

STATIC void insque(), remque();

#ifdef	NULL
#undef  NULL
#endif
#define NULL	0
#ifdef debug
# define ASSERT(p,q)	if (!(p)) fatal(q)
#else
# define ASSERT(p,q)
#endif

#define ALIGN(n, granule)  ((n + ((granule)-1)) & ~((granule)-1))

char *
malloc(nbytes)
	unsigned nbytes;
{
	register struct overhead *p, *q;
	register int surplus = 0;
	register struct qelem *bucket;
	nbytes = ALIGN(nbytes, NALIGN) + sizeof(struct overhead);
	bucket = &buckets[log2(nbytes-1) + 1];	/* log2 rounded up */
	for (p = NULL; bucket < &buckets[NBUCKETS]; bucket++) {
		if (bucket->q_forw != bucket) {
			/*  remove from bucket chain */
			p = FROMBUK(bucket->q_forw);
			ASSERT(p->ov_magic == MAGIC_FREE, "\nmalloc: Entry \
not marked FREE found on Free List!\n");
			remque(TOBUK(p));
			surplus = p->ov_length - nbytes;
			break;
		}
	}
	if (p == NULL) {
#ifdef USE_SBRK
		register int i;
		p = (struct overhead *)CURBRK;
		if ((int)p == -1) {
			return(NULL);
		}
		if (i = (int)p&(NALIGN-1)) {
			sbrk(NALIGN-i);
		}
		p = (struct overhead *)sbrk(nbytes);
		if ((int)p == -1) {
			return(NULL);
		}
		q = (struct overhead *)CURBRK;
		if ((int)q == -1) {
			return(NULL);
		}
		p->ov_length = (char *)q - (char *)p;
		surplus = p->ov_length - nbytes;
		/* add to end of adjacency chain */
		ASSERT((FROMADJ(adjhead.q_back)) < p, "\nmalloc: Entry in \
adjacency chain found with address lower than Chain head!\n" );
		insque(TOADJ(p),adjhead.q_back);
#else
		struct qelem *pp;
		int alloc_size = ALIGN(nbytes, PAGE_SIZE);

		p = (struct overhead *)alloc(alloc_size, NALIGN);
		if ((int)p == -1) {
			return(NULL);
		}
		p->ov_length = alloc_size;
		surplus = p->ov_length - nbytes;

		/* add to adjacency chain in the correct place */
		for (pp = adjhead.q_forw; pp != &adjhead; pp = pp->q_forw) {
			if (p < FROMADJ(pp)) {
				break;
			}
		}
		ASSERT(pp == &adjhead || (p < FROMADJ(pp)),
		       "\nmalloc: Bogus insertion in adjacency list\n");
		insque(TOADJ(p),pp->q_back);
#endif
	}
	if (surplus > sizeof(struct overhead)) {
		/* if big enough, split it up */
		q = (struct overhead *)( (char *)p + nbytes);
		q->ov_length = surplus;
		p->ov_length = nbytes;
		q->ov_magic = MAGIC_FREE;
		/* add surplus into adjacency chain */
		insque(TOADJ(q),TOADJ(p));
		/* add surplus into bucket chain */
		insque(TOBUK(q),&buckets[log2(surplus)]);
	}
	p->ov_magic = MAGIC_BUSY;
	return((char*)p + sizeof(struct overhead));
}

void
free(mem)
register char *mem;
{
	register struct overhead *p, *q;
	if (mem == NULL) {
		return;
	}
	p = (struct overhead *)(mem - sizeof(struct overhead));
	if (p->ov_magic == MAGIC_FREE) {
		return;
	}
	if (p->ov_magic != MAGIC_BUSY) {
		fatal("attempt to free memory not allocated with malloc!\n");
	}
	q = FROMADJ((TOADJ(p))->q_back);
	if (q != FROMADJ(&adjhead)) {	/* q is not the first list item */
		ASSERT(q < p, "\nfree: While trying to merge a free area with \
a lower adjacent free area,\n addresses were found out of order!\n");
		/* If lower segment can be merged */
		if ((q->ov_magic == MAGIC_FREE) &&
							((char *)q + q->ov_length == (char *)p) ) {

			/* remove lower address area from bucket chain */
			remque(TOBUK(q));
			/* remove upper address area from adjacency chain */
			remque(TOADJ(p));
			q->ov_length += p->ov_length;
			p->ov_magic = NULL;
			p = q;
		}
	}
	q = FROMADJ((TOADJ(p))->q_forw);
	if (q != FROMADJ(&adjhead)) {	/* q is not the last list item */
		/* upper segment can be merged */
		ASSERT(q > p, "\nfree: While trying to merge a free area with \
a higher adjacent free area,\n addresses were found out of order!\n");
		if ( 	(q->ov_magic == MAGIC_FREE) &&
							((char *)p + p->ov_length == (char *)q) ) {

			/* remove upper from bucket chain */
			remque(TOBUK(q));
			/* remove upper from adjacency chain */
			remque(TOADJ(q));
			p->ov_length += q->ov_length;
			q->ov_magic = NULL;
		}
	}
#ifdef USE_SBRK
	/* freed area is at end of memory */
	if ((endfree && adjhead.q_back == TOADJ(p)) &&
						((char*)p + p->ov_length == (char *)CURBRK) ) {

		/* remove from end of adjacency chain */
		remque(adjhead.q_back);
		/* release memory to system */
		sbrk( -((int)(p->ov_length)));
		return;
	}
#endif
	p->ov_magic = MAGIC_FREE;
	/* place in bucket chain */
	insque(TOBUK(p),&buckets[log2(p->ov_length)]);
	return;
}

char *
realloc(mem,nbytes)
register char *mem; unsigned nbytes;
{
	register char *newmem;
	register struct overhead *p, *q;
	register int surplus;
	if (mem == NULL) {
		return(malloc(nbytes));
	}
	if(mem > (char*)FROMADJ(adjhead.q_back) + sizeof(struct overhead)) {
		return(NULL);
	}
	
	p = (struct overhead *)(mem - sizeof(struct overhead));
	nbytes = (nbytes + (NALIGN-1)) & (~(NALIGN-1));
	if (  (p->ov_magic == MAGIC_BUSY) && (q = FROMADJ(adjhead.q_back)) != p
	   && (q->ov_magic != MAGIC_FREE || (FROMADJ(q->ov_adj.q_back) != p)) ) {

		free(mem);
	}
	if( (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE)
	 && (surplus = p->ov_length - nbytes - sizeof(struct overhead)) >= 0 ) {
		if (surplus > sizeof(struct overhead)) {
			/*  return surplus to free list */
			nbytes += sizeof(struct overhead);
#ifdef USE_SBRK
			/* freed area is at end of memory */
			if ( endfree && adjhead.q_back == TOADJ(p)
			  &&	(char*)p + p->ov_length == (char *)CURBRK ) {
				/* release memory to system */
				sbrk(-surplus);
			} else
#endif
			{
				q = (struct overhead *)( (char *)p + nbytes);
				q->ov_length = surplus;
				q->ov_magic = MAGIC_FREE;
				insque(TOADJ(q),TOADJ(p));
				insque(TOBUK(q),&buckets[log2(surplus)]);
			}
			p->ov_length = nbytes;
		}
		if (p->ov_magic == MAGIC_FREE) {
			remque(TOBUK(p));
			p->ov_magic = MAGIC_BUSY;
		}
		return(mem);
	}
	newmem = malloc(nbytes);
	if (newmem != mem && newmem != NULL) {
		register unsigned n;
		if (p->ov_magic == MAGIC_BUSY || p->ov_magic == MAGIC_FREE) {
			n = p->ov_length - sizeof(struct overhead);
			nbytes = (nbytes < n) ? nbytes : n ;
		}
		bcopy(mem,newmem,nbytes);
	}
	if (p->ov_magic == MAGIC_BUSY) {
		free(mem);
	}
	return(newmem);
}

log2(n)
register int n;
{
	register int i = 0;
	while ((n >>= 1) > 0) {
		i++;
	}
	return(i);
}

void
insque(item,queu)
register struct qelem *item, *queu;
{
	register struct qelem *pueu;
	pueu = queu->q_forw;
	item->q_forw = pueu;
	item->q_back = queu;
	queu->q_forw = item;
	pueu->q_back = item;
}

void
remque(item)
register struct qelem *item;
{
	register struct qelem *queu, *pueu;
	pueu = item->q_forw;
	queu = item->q_back;
	queu->q_forw = pueu;
	pueu->q_back = queu;
}