1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/mempool.c Tue Oct 17 16:15:41 2017 +0200 1.3 @@ -0,0 +1,211 @@ 1.4 +/* 1.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 1.6 + * 1.7 + * Copyright 2017 Olaf Wintermann. All rights reserved. 1.8 + * 1.9 + * Redistribution and use in source and binary forms, with or without 1.10 + * modification, are permitted provided that the following conditions are met: 1.11 + * 1.12 + * 1. Redistributions of source code must retain the above copyright 1.13 + * notice, this list of conditions and the following disclaimer. 1.14 + * 1.15 + * 2. Redistributions in binary form must reproduce the above copyright 1.16 + * notice, this list of conditions and the following disclaimer in the 1.17 + * documentation and/or other materials provided with the distribution. 1.18 + * 1.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1.29 + * POSSIBILITY OF SUCH DAMAGE. 1.30 + */ 1.31 + 1.32 +#include "ucx/mempool.h" 1.33 + 1.34 +#include <stdlib.h> 1.35 +#include <string.h> 1.36 +#include <stdio.h> 1.37 +#ifdef __cplusplus 1.38 +#define __STDC_FORMAT_MACROS 1.39 +#endif 1.40 +#include <inttypes.h> 1.41 + 1.42 +/** Capsule for destructible memory chunks. */ 1.43 +typedef struct { 1.44 + /** The destructor for the memory chunk. */ 1.45 + ucx_destructor destructor; 1.46 + /** 1.47 + * First byte of the memory chunk. 1.48 + * Note, that the address <code>&c</code> is also the address 1.49 + * of the whole memory chunk. 1.50 + */ 1.51 + char c; 1.52 +} ucx_memchunk; 1.53 + 1.54 +/** Capsule for data and its destructor. */ 1.55 +typedef struct { 1.56 + /** The destructor for the data. */ 1.57 + ucx_destructor destructor; 1.58 + /** A pointer to the data. */ 1.59 + void *ptr; 1.60 +} ucx_regdestr; 1.61 + 1.62 +UCX_EXTERN void ucx_mempool_shared_destr(void* ptr) { 1.63 + ucx_regdestr *rd = (ucx_regdestr*)ptr; 1.64 + rd->destructor(rd->ptr); 1.65 +} 1.66 + 1.67 +UcxMempool *ucx_mempool_new(size_t n) { 1.68 + UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool)); 1.69 + if (!pool) { 1.70 + return NULL; 1.71 + } 1.72 + 1.73 + pool->data = (void**) malloc(n * sizeof(void*)); 1.74 + if (pool->data == NULL) { 1.75 + free(pool); 1.76 + return NULL; 1.77 + } 1.78 + 1.79 + pool->ndata = 0; 1.80 + pool->size = n; 1.81 + 1.82 + UcxAllocator *allocator = (UcxAllocator*)malloc(sizeof(UcxAllocator)); 1.83 + if(!allocator) { 1.84 + free(pool->data); 1.85 + free(pool); 1.86 + return NULL; 1.87 + } 1.88 + allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; 1.89 + allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; 1.90 + allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; 1.91 + allocator->free = (ucx_allocator_free)ucx_mempool_free; 1.92 + allocator->pool = pool; 1.93 + pool->allocator = allocator; 1.94 + 1.95 + return pool; 1.96 +} 1.97 + 1.98 +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) { 1.99 + if (newcap < pool->ndata) { 1.100 + return 1; 1.101 + } 1.102 + 1.103 + void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); 1.104 + if (data) { 1.105 + pool->data = data; 1.106 + pool->size = newcap; 1.107 + return 0; 1.108 + } else { 1.109 + return 1; 1.110 + } 1.111 +} 1.112 + 1.113 +void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { 1.114 + if (pool->ndata >= pool->size) { 1.115 + size_t newcap = pool->size*2; 1.116 + if (newcap < pool->size || ucx_mempool_chcap(pool, newcap)) { 1.117 + return NULL; 1.118 + } 1.119 + } 1.120 + 1.121 + void *p = malloc(sizeof(ucx_destructor) + n); 1.122 + ucx_memchunk *mem = (ucx_memchunk*)p; 1.123 + if (!mem) { 1.124 + return NULL; 1.125 + } 1.126 + 1.127 + mem->destructor = NULL; 1.128 + pool->data[pool->ndata] = mem; 1.129 + pool->ndata++; 1.130 + 1.131 + return &(mem->c); 1.132 +} 1.133 + 1.134 +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) { 1.135 + void *ptr = ucx_mempool_malloc(pool, nelem*elsize); 1.136 + if (!ptr) { 1.137 + return NULL; 1.138 + } 1.139 + memset(ptr, 0, nelem * elsize); 1.140 + return ptr; 1.141 +} 1.142 + 1.143 +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) { 1.144 + char *mem = ((char*)ptr) - sizeof(ucx_destructor); 1.145 + char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor)); 1.146 + if (!newm) { 1.147 + return NULL; 1.148 + } 1.149 + if (mem != newm) { 1.150 + for(size_t i=0 ; i < pool->ndata ; i++) { 1.151 + if(pool->data[i] == mem) { 1.152 + pool->data[i] = newm; 1.153 + return newm + sizeof(ucx_destructor); 1.154 + } 1.155 + } 1.156 + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", 1.157 + (intptr_t)ptr, (intptr_t)pool); 1.158 + abort(); 1.159 + } else { 1.160 + return newm + sizeof(ucx_destructor); 1.161 + } 1.162 +} 1.163 + 1.164 +void ucx_mempool_free(UcxMempool *pool, void *ptr) { 1.165 + ucx_memchunk *chunk = (ucx_memchunk*)((char*)ptr-sizeof(ucx_destructor)); 1.166 + for(size_t i=0 ; i<pool->ndata ; i++) { 1.167 + if(chunk == pool->data[i]) { 1.168 + if(chunk->destructor != NULL) { 1.169 + chunk->destructor(&(chunk->c)); 1.170 + } 1.171 + free(chunk); 1.172 + size_t last_index = pool->ndata - 1; 1.173 + if(i != last_index) { 1.174 + pool->data[i] = pool->data[last_index]; 1.175 + pool->data[last_index] = NULL; 1.176 + } 1.177 + pool->ndata--; 1.178 + return; 1.179 + } 1.180 + } 1.181 + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", 1.182 + (intptr_t)ptr, (intptr_t)pool); 1.183 + abort(); 1.184 +} 1.185 + 1.186 +void ucx_mempool_destroy(UcxMempool *pool) { 1.187 + ucx_memchunk *chunk; 1.188 + for(size_t i=0 ; i<pool->ndata ; i++) { 1.189 + chunk = (ucx_memchunk*) pool->data[i]; 1.190 + if(chunk) { 1.191 + if(chunk->destructor) { 1.192 + chunk->destructor(&(chunk->c)); 1.193 + } 1.194 + free(chunk); 1.195 + } 1.196 + } 1.197 + free(pool->data); 1.198 + free(pool->allocator); 1.199 + free(pool); 1.200 +} 1.201 + 1.202 +void ucx_mempool_set_destr(void *ptr, ucx_destructor func) { 1.203 + *(ucx_destructor*)((char*)ptr-sizeof(ucx_destructor)) = func; 1.204 +} 1.205 + 1.206 +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr) { 1.207 + ucx_regdestr *rd = (ucx_regdestr*)ucx_mempool_malloc( 1.208 + pool, 1.209 + sizeof(ucx_regdestr)); 1.210 + rd->destructor = destr; 1.211 + rd->ptr = ptr; 1.212 + ucx_mempool_set_destr(rd, ucx_mempool_shared_destr); 1.213 +} 1.214 +