shithub: p9-stm32-example-bare

ref: 385ecf9c11ba7114801e877090951e1785698051
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)		((Bhdr *)((uint)h + sizeof(Bhdr)))
#define	BNEXT(h)	((Bhdr *)((uint)h + sizeof(Bhdr) + h->size))

enum {
	Bfree	= 0,
	Balloc,
};

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

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

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

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

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

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

		if(hdr->magic != BHDR_MAGIC)
			panic("block has bad magic number");

		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)
{
	Bhdr* hdr = cmfindsmallest(size);

	ulong osize;
	void *ptr;

	if(hdr == nil)
		return nil;

	// <-lock
	// allocate block
	osize = hdr->size;
	hdr->tp = Balloc;
	hdr->size = size;
	ptr = BPTR(hdr);

	// create next block
	if((uint)BNEXT(hdr) < ((uint)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);
		DBGALLOC print("alloc: created next block of size %uld\n", hdr->size);
	}

	// <-unlock
	// return pointer
	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");
	for(Bhdr *t = first; (uint)t - (uint)first < CMEMSIZE && hdr == nil; t = BNEXT(t)) {
		void *t_ptr = BPTR(t);
		if(t_ptr == ptr)
			hdr = t;
	}

	if(hdr == nil)
		return;

	hdr->tp = Bfree;
	memset(ptr, 0, hdr->size);

	// second pass: coalesce with the next block
	DBGALLOC print("alloc: coalesce with next block\n");
	if((uint)BNEXT(hdr) < (uint)first + CMEMSIZE && BNEXT(hdr)->tp == Bfree) {
		hdr->size = hdr->size + BNEXT(hdr)->size + sizeof(Bhdr);
	}

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

	if(c != nil)
		c->size = c->size + hdr->size + sizeof(Bhdr);

	DBGALLOC print("alloc: updating size to %uld\n", c->size);
}

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

	for(Bhdr *t = first; (uint)t - (uint)first < CMEMSIZE && hdr == nil; t = BNEXT(t)) {
		void *t_ptr = BPTR(t);
		if(t_ptr == ptr)
			hdr = t;
	}

	if(hdr == nil)
		return nil;

	// 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);
	free(ptr);
	return nptr;
}