Blame src/dalist_memfn.c

e09104
/*****************************************************************************/
e09104
/*  dalist: a zero-dependency book-keeping library                           */
e09104
/*  Copyright (C) 2013,2014,2015  Z. Gilboa                                  */
e09104
/*  Released under GPLv2 and GPLv3; see COPYING.DALIST.                      */
e09104
/*****************************************************************************/
e09104
e09104
#include <dalist/dalist.h>
e09104
#include "dalist_impl.h"
e09104
e09104
/* private prototypes */
e09104
static void * dalist_alloc(struct dalist_ex * dlist);
e09104
e09104
static int dalist_memfn_internal(
e09104
	struct dalist_ex *	dlist,
e09104
	void **			addr,
e09104
	size_t *		alloc_size);
e09104
e09104
e09104
dalist_api
e09104
int dalist_get_free_node(
e09104
	struct dalist_ex *	dlist,
e09104
	void **			fnode)
e09104
{
e09104
	int			ret;
e09104
	struct dalist_node *	nfree;
e09104
e09104
	/* in case we fail */
e09104
	*fnode = (void *)0;
e09104
e09104
	if (dlist->free)
e09104
		/* allocation is not needed */
e09104
		nfree  = (struct dalist_node *)dlist->free;
e09104
	else
e09104
		nfree = (struct dalist_node *)dalist_alloc(dlist);
e09104
e09104
	if (nfree) {
e09104
		*fnode = nfree;
e09104
		dlist->free = nfree->next;
e09104
e09104
		if (nfree->next) /* new head of dlist->free */
e09104
			nfree->next->prev = 0;
e09104
e09104
		/* bookkeeping */
e09104
		dlist->info.free_nodes--;
e09104
e09104
		/* and for good measure */
e09104
		nfree->prev = nfree->next = 0;
e09104
		ret = DALIST_OK;
e09104
	} else
e09104
		ret = DALIST_EMEMFN;
e09104
e09104
	return ret;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_deposit_free_node(
e09104
	struct dalist_ex *	dlist,
e09104
	void *			fnode)
e09104
{
e09104
	int			ret;
e09104
	struct dalist_node *	nfree;
e09104
e09104
	if (fnode) {
e09104
		nfree       = (struct dalist_node *)fnode;
e09104
		nfree->next = (struct dalist_node *)dlist->free;
e09104
e09104
		/* fnode is now the head free node */
e09104
		nfree->prev = 0;
e09104
		dlist->free = fnode;
e09104
e09104
		/* bookkeeping */
e09104
		dlist->info.free_nodes++;
e09104
		ret = DALIST_OK;
e09104
	} else {
e09104
		ret = DALIST_ENODE;
e09104
	}
e09104
e09104
	return ret;
e09104
}
e09104
e09104
e09104
dalist_api
e09104
int dalist_deposit_memory_block(
e09104
	struct dalist_ex *	dlist,
e09104
	void *			addr,
e09104
	size_t			alloc_size)
e09104
{
e09104
	struct dalist_node *	fnode;
e09104
	struct dalist_node *	fnode_next;
e09104
	char *			naddr;
e09104
	char *			naddr_next;
e09104
	char *			naddr_upper;
e09104
	size_t			node_size;
e09104
e09104
	/* node_size: before alignment */
e09104
	if (dlist->dblock_size == 0)
e09104
		node_size = sizeof(struct dalist_node);
e09104
	else
e09104
		node_size = (size_t)&((struct dalist_node_ex *)0)->dblock
e09104
				+ dlist->dblock_size;
e09104
e09104
	/* node_size: after alignment */
e09104
	node_size += sizeof(uintptr_t)-1;
e09104
	node_size |= sizeof(uintptr_t)-1;
e09104
	node_size ^= sizeof(uintptr_t)-1;
e09104
e09104
	/* validate block size */
e09104
	if (alloc_size < node_size)
e09104
		return DALIST_EMEMBLOCK;
e09104
e09104
	/* marks */
e09104
	naddr       = (char *)addr;
e09104
	naddr_next  = naddr + node_size;
e09104
	naddr_upper = naddr + alloc_size;
e09104
e09104
	/* chain of free nodes */
e09104
	while ((naddr_next + node_size) < naddr_upper) {
e09104
		fnode      = (struct dalist_node *)naddr;
e09104
		fnode_next = (struct dalist_node *)naddr_next;
e09104
e09104
		fnode->next      = fnode_next;
e09104
		fnode_next->prev = fnode;
e09104
e09104
		naddr      += node_size;
e09104
		naddr_next += node_size;
e09104
	}
e09104
e09104
	/* free nodes block: head and tail */
e09104
	fnode       = (struct dalist_node *)addr;
e09104
	fnode_next  = (struct dalist_node *)naddr;
e09104
e09104
	if (dlist->free) {
e09104
		/* link with pre-allocated free nodes */
e09104
		fnode_next->next = (struct dalist_node *)dlist->free;
e09104
		((struct dalist_node *)dlist->free)->prev = fnode_next;
e09104
	} else {
e09104
		/* no pre-allocated free nodes */
e09104
		fnode_next->next = 0;
e09104
	}
e09104
e09104
	/* fnode is now the head free node */
e09104
	fnode->prev = 0;
e09104
	dlist->free = fnode;
e09104
e09104
	/* bookkeeping */
e09104
	dlist->info.free_nodes += (alloc_size / node_size);
e09104
e09104
	return DALIST_OK;
e09104
}
e09104
e09104
e09104
static void * __cdecl dalist_alloc(struct dalist_ex * dlist)
e09104
{
e09104
	int			ret;
e09104
	void *			addr;
e09104
	size_t			alloc_size;
e09104
	memfn_custom *		pmemfn;
e09104
	struct dalist_node *	fnode;
e09104
e09104
	/* pmemfn */
e09104
	if (dlist->memfn_method == DALIST_MEMFN_CUSTOM)
e09104
		pmemfn = (dalist_memfn_custom *)dlist->memfn_ptr;
e09104
	else
e09104
		pmemfn = dalist_memfn_internal;
e09104
e09104
	/* allocate: try */
e09104
	fnode = 0;
e09104
	ret   = pmemfn(dlist,&addr,&alloc_size);
e09104
e09104
	/* allocate: verify */
e09104
	if (ret == DALIST_OK) {
e09104
		if (dlist->memfn_method == DALIST_MEMFN_MALLOC)
e09104
			fnode = (struct dalist_node *)addr;
e09104
		else if (dalist_deposit_memory_block(
e09104
				dlist,
e09104
				addr,
e09104
				alloc_size) == DALIST_OK)
e09104
			fnode = (struct dalist_node *)dlist->free;
e09104
	}
e09104
e09104
	return fnode;
e09104
}
e09104
e09104
e09104
static int __cdecl dalist_memfn_internal(
e09104
	struct dalist_ex *	dlist,
e09104
	void **			address,
e09104
	size_t *		alloc_size)
e09104
{
e09104
	int		ret;
e09104
	void *		addr;
e09104
	size_t		size;
e09104
e09104
	memfn_mmap *	pfn_mmap;
e09104
	memfn_malloc *	pfn_malloc;
e09104
	memfn_allocvm * pfn_allocvm;
e09104
e09104
	switch (dlist->memfn_method) {
e09104
		case DALIST_MEMFN_MALLOC:
e09104
			if (dlist->dblock_size == 0)
e09104
				size = sizeof(struct dalist_node);
e09104
			else
e09104
				size = (size_t)((struct dalist_node_ex *)0)->dblock
e09104
					+ dlist->dblock_size;
e09104
e09104
			pfn_malloc = (memfn_malloc * )dlist->memfn_ptr;
e09104
			addr = pfn_malloc(size);
e09104
e09104
			if (addr) {
e09104
				*address = addr;
e09104
				*alloc_size = size;
e09104
				ret = dlist->memfn_status = DALIST_OK;
e09104
			} else {
e09104
				ret = DALIST_EMEMFN;
e09104
				dlist->memfn_status = dalist_errno(ret);
e09104
			}
e09104
			break;
e09104
e09104
		case DALIST_MEMFN_MMAP:
e09104
			pfn_mmap = (memfn_mmap * )dlist->memfn_ptr;
e09104
e09104
			addr = pfn_mmap(
e09104
				(void *)0,
e09104
				dlist->lblock_size,
e09104
				PROT_READ | PROT_WRITE,
e09104
				MAP_ANON | MAP_SHARED,
e09104
				0,0);
e09104
e09104
			if (addr) {
e09104
				*address = addr;
e09104
				*alloc_size = dlist->lblock_size;
e09104
				ret = dlist->memfn_status = DALIST_OK;
e09104
			} else {
e09104
				ret = DALIST_EMEMFN;
e09104
				dlist->memfn_status = dalist_errno(ret);
e09104
			}
e09104
			break;
e09104
e09104
		case DALIST_MEMFN_NT_ALLOCATE_VIRTUAL_MEMORY:
e09104
			addr       = (void *)0;
e09104
			size = dlist->lblock_size;
e09104
			pfn_allocvm = (memfn_allocvm * )dlist->memfn_ptr;
e09104
e09104
			dlist->memfn_status = pfn_allocvm(
e09104
				NT_CURRENT_PROCESS_HANDLE,
e09104
				&addr,
e09104
				0,
e09104
				&size,
e09104
				NT_MEM_COMMIT,
e09104
				NT_PAGE_READWRITE);
e09104
e09104
			if (dlist->memfn_status == NT_STATUS_SUCCESS) {
e09104
				*address = addr;
e09104
				*alloc_size = size;
e09104
				ret = DALIST_OK;
e09104
			} else {
e09104
				ret = DALIST_EMEMFN;
e09104
			}
e09104
			break;
e09104
		default:
e09104
			ret = DALIST_EINTERNAL;
e09104
			break;
e09104
	}
e09104
e09104
	return ret;
e09104
}