shithub: p9-stm32-example-os

ref: f801657f77f3923ec2388c25bdcb036c8019ba89
dir: /alloc.c/

View raw version
#include	<u.h>
#include	"dat.h"
#include	"fns.h"
#include	"mem.h"
#include	"debug.h"
#include	"libkern/kern.h"

#define CMEMSIZE	DATASIZE

#define	BHDR_MAGIC	0xcafebafe
#define BHDR_POISON	0xdeadbeef
#define	BPTR(h)		((void *)((ulong)h + sizeof(Bhdr)))
#define	BHDR(p)		((Bhdr *)((ulong)p - sizeof(Bhdr)))
#define	BNEXT(h)	((Bhdr *)((ulong)h + sizeof(Bhdr) + h->size))

enum {
	Bfree	= 0,
	Balloc,
};

typedef struct Bhdr {
	ulong	magic;
	ulong	size;
	int		tp;
	Lock	l;
} Bhdr;
#define first ((Bhdr*) DATASADDR)

void
allocinit()
{
	first->magic = BHDR_MAGIC;
	first->size = DATASIZE - sizeof(Bhdr);
	first->tp = Bfree;
	memset(&first->l, 0, sizeof(Lock));
	memset(BPTR(first), 0, first->size);
}

void
allocdump()
{
	int s = splhi();
	for(Bhdr *hdr = first; ((ulong)hdr - (ulong)first) < CMEMSIZE; hdr = BNEXT(hdr)) {
		if(hdr->magic != BHDR_MAGIC)
			print("corrupt: ");
		print("alloc: BPTR(hdr) 0x%08x BNEXT(hdr) 0x%08x hdr->size %ud\n", BPTR(hdr), BNEXT(hdr), hdr->size);
	}
	splx(s);
}

Bhdr*
cmfindsmallest(ulong size)
{
	Bhdr *t = nil;

	DBGALLOC print("alloc: finding %uld size block\n", size);

	for(Bhdr *hdr = first; ((ulong)hdr - (ulong)first) < CMEMSIZE;
		hdr = BNEXT(hdr)) {

		DBGALLOC print("alloc: checking block with size %uld\n", hdr->size);

		if(hdr->magic != BHDR_MAGIC) {
			allocdump();
			panic("block at 0x%08ux has bad magic number 0x%08ux\n", hdr, hdr->magic);
		}

		if(hdr->size < size || hdr->tp == Balloc)
			continue;
		if(hdr->size >= size && t == nil)
			t = hdr;
		if(hdr->size >= size && hdr->size < t->size)
			t = hdr;
	}

	DBGALLOC print("alloc: block selected\n");

	return t;
}

void*
mallocz(ulong size, int clr)
{
	if(size % 8 != 0)
		size = size + 8 - (size % 8);

	lock(&first->l);

	Bhdr* ohdr;
	Bhdr* hdr = cmfindsmallest(size);

	ulong osize;
	void *ptr;

	if(hdr == nil)
		return nil;

//	lock(&hdr->l);
	// allocate block
	DBGALLOC print("alloc: allocating block of %uld\n", size);
	osize = hdr->size;
	hdr->tp = Balloc;
	hdr->size = size;
	ohdr = hdr;
	ptr = BPTR(hdr);

	// create next block
	DBGALLOC print("alloc: creating next block 0x%08x\n", (uint)BNEXT(hdr));
	if((ulong)BNEXT(hdr) < ((ulong)first + CMEMSIZE - sizeof(Bhdr)) &&
		BNEXT(hdr)->magic != BHDR_MAGIC) {
		hdr = BNEXT(hdr);
		hdr->magic = BHDR_MAGIC;
		hdr->tp = Bfree;
		hdr->size = osize - size - sizeof(Bhdr);
		memset(&hdr->l, 0, sizeof(Lock));
		DBGALLOC print("alloc: created next block of size %uld\n", hdr->size);
	}

//	unlock(&ohdr->l);
	unlock(&first->l);
	// return pointer
	DBGALLOC print("alloc: finished; memset and return\n");
	if(clr)
		memset(ptr, 0, size);
	return ptr;
}

void*
malloc(ulong size)
{
	return mallocz(size, 1);
}

void*
smalloc(ulong size)
{
	void *ptr;
	while((ptr = malloc(size)) == nil)
		_wait(100);

	return ptr;
}

void
free(void *ptr)
{
	Bhdr *hdr = nil;
	Bhdr *c = nil;

	// first pass: find and free the block
	DBGALLOC print("alloc: free'ing block\n");
	hdr = BHDR(ptr);
	if(hdr == nil)
		return;

	lock(&first->l);
//	lock(&hdr->l);
	hdr->tp = Bfree;
	memset(ptr, 0, hdr->size);

	// second pass: coalesce with the next block
	DBGALLOC print("alloc: coalesce with next block\n");

	if((ulong)BNEXT(hdr) < (ulong)first + CMEMSIZE) {
		c = BNEXT(hdr);
//		lock(&c->l);
		if(c->tp == Bfree) {
			c->magic = BHDR_POISON;
			hdr->size = hdr->size + c->size + sizeof(Bhdr);
		}
//		unlock(&c->l);
	}

	// third pass: coalesce with the previous block
	DBGALLOC print("alloc: coalesce with previous block\n");
	c = nil;
	for(Bhdr *t = first; (ulong)t - (ulong)first < CMEMSIZE && c == nil;
		t = BNEXT(t))
		if(t != hdr) {
//			lock(&t->l);
			if(BNEXT(t) < first + CMEMSIZE && BNEXT(t) == hdr && t->tp == Bfree) {
				c = t;
//				unlock(&t->l);
				break;
			}
//			unlock(&t->l);
		}

	if(c != nil) {
//		lock(&c->l);
		c->size = c->size + hdr->size + sizeof(Bhdr);
		hdr->magic = BHDR_POISON;
//		unlock(&c->l);
	}

	// free is done; return
//	unlock(&hdr->l);
	unlock(&first->l);
	DBGALLOC print("alloc: updating size to %uld\n", c->size);
}

void*
realloc(void *ptr, ulong size)
{
	Bhdr *hdr = nil;
	void *nptr;

	hdr = BHDR(ptr);
	if(hdr == nil)
		return nil;
//	lock(&first->l);
//	lock(&hdr->l);

	// first pass: see if the block is extendable
	// TODO

	// second pass: find a new block
	nptr = malloc(size);
	if(nptr == nil)
		return nil;

	if(hdr->size < size)
		size = hdr->size;

	memcpy(nptr, BPTR(hdr), size);
//	unlock(&hdr->l);
//	unlock(&first->l);
	free(ptr);
	return nptr;
}

/*	maximizing memory usage	*/
/*	a noop; should be an overhead for the STM; implementing
	it is coalescing with the next block	*/
ulong
msize(void *ptr)
{
	Bhdr *hdr = nil;
	void *t_ptr;

	DBGALLOC print("alloc: msizing'ing block\n");
	hdr = BHDR(ptr);
	if(hdr == nil)
		return 0;
	return hdr->size;
}

/*	memory allocation tracing off	*/
enum {
	Npadlong	= 2,
	MallocOffset = 0,
	ReallocOffset = 1
};

void
setmalloctag(void *v, ulong pc)
{
	return;
}

ulong
getmalloctag(void *v)
{
	return ~0;
}

void
setrealloctag(void *v, ulong pc)
{
	return;
}

ulong
getrealloctag(void *v)
{
	return ~0;
}