#include <stdlib.h>
#include "list.h"
#include "error.h"
#include "bin.h"
#include "mem.h"

#define MEM_PRE		4096
static align_t local_store[MEM_PRE / MEM_ALIGN];
#define space ((char *)local_store)
static unsigned int avail = MEM_PRE;
static int bomb_gc = 0;
static list_t gc = 0;

void inline *mem_alloc(int bytes)
{
	int (*fn)(void *);
	register char *x;
	int tries = 0;
	list_t lp;

	/* could overflow if MEM_ALIGN is too large */
	bytes = MEM_ALIGN + bytes - (bytes & (MEM_ALIGN - 1));
	if (bytes <= avail) {
		avail -= bytes;
		return space + avail;
	}

	/* Clib */
retry_l:x = malloc(bytes);
	if (!x) {
		if (bomb_gc && tries > 9) {
			/* try at most 10 times... if bomb_gc is set, bad things
			 * are going to happen anyway...
			 */
			errno = ENOMEM;
			return x;
		}
		/* try gc handlers */
		for (lp = gc; lp; lp = lp->next) {
			x = lp->str;
			fn = (int (*)(void *))(((char *)lp->str)+sizeof(char *));
			if (fn(x)) {
				tries++;
				goto retry_l;
			}
		}
		errno = ENOMEM;
	}
	return x;
}
void mem_free(void *x)
{
	/* this assumes a flat address space */
	if (((char *)x) >= space && ((char *)x) <= space + MEM_PRE)
		return;
	free(x);
}
void mem_register_gc(void *x, int (*fn)(void *x))
{
	bin_t c;

	if (!fn) return;

	bomb_gc = 1;
	bin_init(c);
	bin_copy(c, (char *)&x, sizeof(char *));
	bin_cat(c, (char *)&fn, sizeof(char *));
	list_push(&gc, caddr(c));
	bomb_gc = 0;
}



syntax highlighted by Code2HTML, v. 0.9.1