/*
 * allocate uncached memory
 */
#include "u.h"
#include "../port/lib.h"
#include "mem.h"
#include "dat.h"
#include "fns.h"

#include <pool.h>

typedef struct Private Private;
struct Private {
	Lock;
	char	msg[256];
	char*	cur;
};

static Private ucprivate;

static void
ucpoolpanic(Pool* p, char* fmt, ...)
{
	va_list v;
	Private *pv;
	char msg[sizeof pv->msg];

	pv = p->private;
	va_start(v, fmt);
	vseprint(pv->cur, &pv->msg[sizeof pv->msg], fmt, v);
	va_end(v);
	memmove(msg, pv->msg, sizeof msg);
	iunlock(pv);
	panic("%s", msg);
}

static void
ucpoolprint(Pool* p, char* fmt, ...)
{
	va_list v;
	Private *pv;

	pv = p->private;
	va_start(v, fmt);
	pv->cur = vseprint(pv->cur, &pv->msg[sizeof pv->msg], fmt, v);
	va_end(v);
}

static void
ucpoolunlock(Pool* p)
{
	Private *pv;
	char msg[sizeof pv->msg];

	pv = p->private;
	if(pv->cur == pv->msg){
		iunlock(pv);
		return;
	}

	memmove(msg, pv->msg, sizeof msg);
	pv->cur = pv->msg;
	iunlock(pv);

	iprint("%.*s", sizeof pv->msg, msg);
}

static void
ucpoollock(Pool* p)
{
	Private *pv;

	pv = p->private;
	ilock(pv);
	pv->pc = getcallerpc(&p);
	pv->cur = pv->msg;
}

static void*
ucarena(usize size)
{
	void *uv, *v;

	assert(size == 1*MiB);

	mainmem->maxsize += 1*MiB;
	if((v = mallocalign(1*MiB, 1*MiB, 0, 0)) == nil ||
	    (uv = mmuuncache(v, 1*MiB)) == nil){
		free(v);
		mainmem->maxsize -= 1*MiB;
		return nil;
	}
	return uv;
}

static Pool ucpool = {
	.name		= "Uncached",
	.maxsize	= 4*MiB,
	.minarena	= 1*MiB-32,
	.quantum	= 32,
	.alloc		= ucarena,
	.merge		= nil,
	.flags		= /*POOL_TOLERANCE|POOL_ANTAGONISM|POOL_PARANOIA|*/0,

	.lock		= ucpoollock,
	.unlock		= ucpoolunlock,
	.print		= ucpoolprint,
	.panic		= ucpoolpanic,

	.private	= &ucprivate,
};

void
ucfree(void* v)
{
	if(v == nil)
		return;
	poolfree(&ucpool, v);
}

void*
ucallocalign(usize size, int align, usize span)
{
	void *v;

	assert(size < ucpool.minarena-128);
	v = poolallocalign(&ucpool, size, align, 0, span);
	if(v)
		memset(v, 0, size);
	return v;
}

void*
ucalloc(usize size)
{
	return ucallocalign(size, 32, 0);
}
