#define	JEMALLOC_BASE_C_
#include "jemalloc/internal/jemalloc_internal.h"


static bool
base_pages_alloc(pool_t *pool, size_t minsize)
{
	size_t csize;
	void* base_pages;

	assert(minsize != 0);
	csize = CHUNK_CEILING(minsize);
	base_pages = chunk_alloc_base(pool, csize);
	if (base_pages == NULL)
		return (true);
	pool->base_next_addr = base_pages;
	pool->base_past_addr = (void *)((uintptr_t)base_pages + csize);

	return (false);
}

void *
base_alloc(pool_t *pool, size_t size)
{
	void *ret;
	size_t csize;

	/* Round size up to nearest multiple of the cacheline size. */
	csize = CACHELINE_CEILING(size);

	malloc_mutex_lock(&pool->base_mtx);
	/* Make sure there's enough space for the allocation. */
	if ((uintptr_t)pool->base_next_addr + csize > (uintptr_t)pool->base_past_addr) {
		if (base_pages_alloc(pool, csize)) {
			malloc_mutex_unlock(&pool->base_mtx);
			return (NULL);
		}
	}
	/* Allocate. */
	ret = pool->base_next_addr;
	pool->base_next_addr = (void *)((uintptr_t)pool->base_next_addr + csize);
	malloc_mutex_unlock(&pool->base_mtx);
	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret, csize);

	return (ret);
}

void *
base_calloc(pool_t *pool, size_t number, size_t size)
{
	void *ret = base_alloc(pool, number * size);

	if (ret != NULL)
		memset(ret, 0, number * size);

	return (ret);
}

extent_node_t *
base_node_alloc(pool_t *pool)
{
	extent_node_t *ret;

	malloc_mutex_lock(&pool->base_node_mtx);
	if (pool->base_nodes != NULL) {
		ret = pool->base_nodes;
		pool->base_nodes = *(extent_node_t **)ret;
		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(ret,
			sizeof(extent_node_t));
	} else {
		/* preallocated nodes for pools other than 0 */
		if (pool->pool_id == 0) {
			ret = (extent_node_t *)base_alloc(pool, sizeof(extent_node_t));
		} else {
			ret = NULL;
		}
	}
	malloc_mutex_unlock(&pool->base_node_mtx);
	return (ret);
}

void
base_node_dalloc(pool_t *pool, extent_node_t *node)
{

	JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t));
	malloc_mutex_lock(&pool->base_node_mtx);
	*(extent_node_t **)node = pool->base_nodes;
	pool->base_nodes = node;
	malloc_mutex_unlock(&pool->base_node_mtx);
}

size_t
base_node_prealloc(pool_t *pool, size_t number)
{
	extent_node_t *node;
	malloc_mutex_lock(&pool->base_node_mtx);
	for (; number > 0; --number) {
		node = (extent_node_t *)base_alloc(pool, sizeof(extent_node_t));
		if (node == NULL)
			break;
		JEMALLOC_VALGRIND_MAKE_MEM_UNDEFINED(node, sizeof(extent_node_t));
		*(extent_node_t **)node = pool->base_nodes;
		pool->base_nodes = node;
	}
	malloc_mutex_unlock(&pool->base_node_mtx);

	/* return number of nodes that couldn't be allocated */
	return number;
}

/*
 * Called at each pool opening.
 */
bool
base_boot(pool_t *pool)
{
	if (malloc_mutex_init(&pool->base_mtx))
		return (true);

	if (malloc_mutex_init(&pool->base_node_mtx))
		return (true);

	return (false);
}

/*
 * Called only at pool creation.
 */
bool
base_init(pool_t *pool)
{
	if (base_boot(pool))
		return (true);

	pool->base_nodes = NULL;

	return (false);
}

void
base_prefork(pool_t *pool)
{

	malloc_mutex_prefork(&pool->base_mtx);
}

void
base_postfork_parent(pool_t *pool)
{

	malloc_mutex_postfork_parent(&pool->base_mtx);
}

void
base_postfork_child(pool_t *pool)
{

	malloc_mutex_postfork_child(&pool->base_mtx);
}
