From e09104e6e294bed185227d5a2065d7a1877562b9 Mon Sep 17 00:00:00 2001 From: midipix Date: Sun, 12 Apr 2015 12:23:25 -0400 Subject: dalist: initial commit. --- src/dalist_memfn.c | 267 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 src/dalist_memfn.c (limited to 'src/dalist_memfn.c') diff --git a/src/dalist_memfn.c b/src/dalist_memfn.c new file mode 100644 index 0000000..e1fa9f0 --- /dev/null +++ b/src/dalist_memfn.c @@ -0,0 +1,267 @@ +/*****************************************************************************/ +/* dalist: a zero-dependency book-keeping library */ +/* Copyright (C) 2013,2014,2015 Z. Gilboa */ +/* Released under GPLv2 and GPLv3; see COPYING.DALIST. */ +/*****************************************************************************/ + +#include +#include "dalist_impl.h" + +/* private prototypes */ +static void * dalist_alloc(struct dalist_ex * dlist); + +static int dalist_memfn_internal( + struct dalist_ex * dlist, + void ** addr, + size_t * alloc_size); + + +dalist_api +int dalist_get_free_node( + struct dalist_ex * dlist, + void ** fnode) +{ + int ret; + struct dalist_node * nfree; + + /* in case we fail */ + *fnode = (void *)0; + + if (dlist->free) + /* allocation is not needed */ + nfree = (struct dalist_node *)dlist->free; + else + nfree = (struct dalist_node *)dalist_alloc(dlist); + + if (nfree) { + *fnode = nfree; + dlist->free = nfree->next; + + if (nfree->next) /* new head of dlist->free */ + nfree->next->prev = 0; + + /* bookkeeping */ + dlist->info.free_nodes--; + + /* and for good measure */ + nfree->prev = nfree->next = 0; + ret = DALIST_OK; + } else + ret = DALIST_EMEMFN; + + return ret; +} + + +dalist_api +int dalist_deposit_free_node( + struct dalist_ex * dlist, + void * fnode) +{ + int ret; + struct dalist_node * nfree; + + if (fnode) { + nfree = (struct dalist_node *)fnode; + nfree->next = (struct dalist_node *)dlist->free; + + /* fnode is now the head free node */ + nfree->prev = 0; + dlist->free = fnode; + + /* bookkeeping */ + dlist->info.free_nodes++; + ret = DALIST_OK; + } else { + ret = DALIST_ENODE; + } + + return ret; +} + + +dalist_api +int dalist_deposit_memory_block( + struct dalist_ex * dlist, + void * addr, + size_t alloc_size) +{ + struct dalist_node * fnode; + struct dalist_node * fnode_next; + char * naddr; + char * naddr_next; + char * naddr_upper; + size_t node_size; + + /* node_size: before alignment */ + if (dlist->dblock_size == 0) + node_size = sizeof(struct dalist_node); + else + node_size = (size_t)&((struct dalist_node_ex *)0)->dblock + + dlist->dblock_size; + + /* node_size: after alignment */ + node_size += sizeof(uintptr_t)-1; + node_size |= sizeof(uintptr_t)-1; + node_size ^= sizeof(uintptr_t)-1; + + /* validate block size */ + if (alloc_size < node_size) + return DALIST_EMEMBLOCK; + + /* marks */ + naddr = (char *)addr; + naddr_next = naddr + node_size; + naddr_upper = naddr + alloc_size; + + /* chain of free nodes */ + while ((naddr_next + node_size) < naddr_upper) { + fnode = (struct dalist_node *)naddr; + fnode_next = (struct dalist_node *)naddr_next; + + fnode->next = fnode_next; + fnode_next->prev = fnode; + + naddr += node_size; + naddr_next += node_size; + } + + /* free nodes block: head and tail */ + fnode = (struct dalist_node *)addr; + fnode_next = (struct dalist_node *)naddr; + + if (dlist->free) { + /* link with pre-allocated free nodes */ + fnode_next->next = (struct dalist_node *)dlist->free; + ((struct dalist_node *)dlist->free)->prev = fnode_next; + } else { + /* no pre-allocated free nodes */ + fnode_next->next = 0; + } + + /* fnode is now the head free node */ + fnode->prev = 0; + dlist->free = fnode; + + /* bookkeeping */ + dlist->info.free_nodes += (alloc_size / node_size); + + return DALIST_OK; +} + + +static void * __cdecl dalist_alloc(struct dalist_ex * dlist) +{ + int ret; + void * addr; + size_t alloc_size; + memfn_custom * pmemfn; + struct dalist_node * fnode; + + /* pmemfn */ + if (dlist->memfn_method == DALIST_MEMFN_CUSTOM) + pmemfn = (dalist_memfn_custom *)dlist->memfn_ptr; + else + pmemfn = dalist_memfn_internal; + + /* allocate: try */ + fnode = 0; + ret = pmemfn(dlist,&addr,&alloc_size); + + /* allocate: verify */ + if (ret == DALIST_OK) { + if (dlist->memfn_method == DALIST_MEMFN_MALLOC) + fnode = (struct dalist_node *)addr; + else if (dalist_deposit_memory_block( + dlist, + addr, + alloc_size) == DALIST_OK) + fnode = (struct dalist_node *)dlist->free; + } + + return fnode; +} + + +static int __cdecl dalist_memfn_internal( + struct dalist_ex * dlist, + void ** address, + size_t * alloc_size) +{ + int ret; + void * addr; + size_t size; + + memfn_mmap * pfn_mmap; + memfn_malloc * pfn_malloc; + memfn_allocvm * pfn_allocvm; + + switch (dlist->memfn_method) { + case DALIST_MEMFN_MALLOC: + if (dlist->dblock_size == 0) + size = sizeof(struct dalist_node); + else + size = (size_t)((struct dalist_node_ex *)0)->dblock + + dlist->dblock_size; + + pfn_malloc = (memfn_malloc * )dlist->memfn_ptr; + addr = pfn_malloc(size); + + if (addr) { + *address = addr; + *alloc_size = size; + ret = dlist->memfn_status = DALIST_OK; + } else { + ret = DALIST_EMEMFN; + dlist->memfn_status = dalist_errno(ret); + } + break; + + case DALIST_MEMFN_MMAP: + pfn_mmap = (memfn_mmap * )dlist->memfn_ptr; + + addr = pfn_mmap( + (void *)0, + dlist->lblock_size, + PROT_READ | PROT_WRITE, + MAP_ANON | MAP_SHARED, + 0,0); + + if (addr) { + *address = addr; + *alloc_size = dlist->lblock_size; + ret = dlist->memfn_status = DALIST_OK; + } else { + ret = DALIST_EMEMFN; + dlist->memfn_status = dalist_errno(ret); + } + break; + + case DALIST_MEMFN_NT_ALLOCATE_VIRTUAL_MEMORY: + addr = (void *)0; + size = dlist->lblock_size; + pfn_allocvm = (memfn_allocvm * )dlist->memfn_ptr; + + dlist->memfn_status = pfn_allocvm( + NT_CURRENT_PROCESS_HANDLE, + &addr, + 0, + &size, + NT_MEM_COMMIT, + NT_PAGE_READWRITE); + + if (dlist->memfn_status == NT_STATUS_SUCCESS) { + *address = addr; + *alloc_size = size; + ret = DALIST_OK; + } else { + ret = DALIST_EMEMFN; + } + break; + default: + ret = DALIST_EINTERNAL; + break; + } + + return ret; +} -- cgit v1.2.3