|
|
e09104 |
/*****************************************************************************/
|
|
|
e09104 |
/* dalist: a zero-dependency book-keeping library */
|
|
|
0553af |
/* Copyright (C) 2013--2021 SysDeer Technologies, LLC */
|
|
|
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 */
|
|
|
256283 |
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)
|
|
|
6d5902 |
pmemfn = (dalist_memfn_custom *)(uintptr_t)dlist->memfn_ptr;
|
|
|
e09104 |
else
|
|
|
e09104 |
pmemfn = dalist_memfn_internal;
|
|
|
e09104 |
|
|
|
e09104 |
/* allocate: try */
|
|
|
e47d7f |
addr = 0;
|
|
|
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 |
|
|
|
6d5902 |
pfn_malloc = (memfn_malloc *)(uintptr_t)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:
|
|
|
6d5902 |
pfn_mmap = (memfn_mmap * )(uintptr_t)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;
|
|
|
6d5902 |
pfn_allocvm = (memfn_allocvm *)(uintptr_t)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 |
}
|