1/* 2 * Copyright (C) 2013 Internet Systems Consortium, Inc. ("ISC") 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14 * PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17/* $Id$ */ 18 19/*! \file */ 20 21#include <config.h> 22 23#include <string.h> 24 25#include <isc/mem.h> 26#include <isc/random.h> 27#include <isc/pool.h> 28#include <isc/util.h> 29 30/*** 31 *** Types. 32 ***/ 33 34struct isc_pool { 35 isc_mem_t * mctx; 36 unsigned int count; 37 isc_pooldeallocator_t free; 38 isc_poolinitializer_t init; 39 void * initarg; 40 void ** pool; 41}; 42 43/*** 44 *** Functions. 45 ***/ 46 47static isc_result_t 48alloc_pool(isc_mem_t *mctx, unsigned int count, isc_pool_t **poolp) { 49 isc_pool_t *pool; 50 51 pool = isc_mem_get(mctx, sizeof(*pool)); 52 if (pool == NULL) 53 return (ISC_R_NOMEMORY); 54 pool->count = count; 55 pool->free = NULL; 56 pool->init = NULL; 57 pool->initarg = NULL; 58 pool->mctx = NULL; 59 isc_mem_attach(mctx, &pool->mctx); 60 pool->pool = isc_mem_get(mctx, count * sizeof(void *)); 61 if (pool->pool == NULL) { 62 isc_mem_put(mctx, pool, sizeof(*pool)); 63 return (ISC_R_NOMEMORY); 64 } 65 memset(pool->pool, 0, count * sizeof(void *)); 66 67 *poolp = pool; 68 return (ISC_R_SUCCESS); 69} 70 71isc_result_t 72isc_pool_create(isc_mem_t *mctx, unsigned int count, 73 isc_pooldeallocator_t free, 74 isc_poolinitializer_t init, void *initarg, 75 isc_pool_t **poolp) 76{ 77 isc_pool_t *pool = NULL; 78 isc_result_t result; 79 unsigned int i; 80 81 INSIST(count > 0); 82 83 /* Allocate the pool structure */ 84 result = alloc_pool(mctx, count, &pool); 85 if (result != ISC_R_SUCCESS) 86 return (result); 87 88 pool->free = free; 89 pool->init = init; 90 pool->initarg = initarg; 91 92 /* Populate the pool */ 93 for (i = 0; i < count; i++) { 94 result = init(&pool->pool[i], initarg); 95 if (result != ISC_R_SUCCESS) { 96 isc_pool_destroy(&pool); 97 return (result); 98 } 99 } 100 101 *poolp = pool; 102 return (ISC_R_SUCCESS); 103} 104 105void * 106isc_pool_get(isc_pool_t *pool) { 107 isc_uint32_t i; 108 isc_random_get(&i); 109 return (pool->pool[i % pool->count]); 110} 111 112int 113isc_pool_count(isc_pool_t *pool) { 114 REQUIRE(pool != NULL); 115 return (pool->count); 116} 117 118isc_result_t 119isc_pool_expand(isc_pool_t **sourcep, unsigned int count, 120 isc_pool_t **targetp) 121{ 122 isc_result_t result; 123 isc_pool_t *pool; 124 125 REQUIRE(sourcep != NULL && *sourcep != NULL); 126 REQUIRE(targetp != NULL && *targetp == NULL); 127 128 pool = *sourcep; 129 if (count > pool->count) { 130 isc_pool_t *newpool = NULL; 131 unsigned int i; 132 133 /* Allocate a new pool structure */ 134 result = alloc_pool(pool->mctx, count, &newpool); 135 if (result != ISC_R_SUCCESS) 136 return (result); 137 138 newpool->free = pool->free; 139 newpool->init = pool->init; 140 newpool->initarg = pool->initarg; 141 142 /* Copy over the objects from the old pool */ 143 for (i = 0; i < pool->count; i++) { 144 newpool->pool[i] = pool->pool[i]; 145 pool->pool[i] = NULL; 146 } 147 148 /* Populate the new entries */ 149 for (i = pool->count; i < count; i++) { 150 result = pool->init(&newpool->pool[i], pool->initarg); 151 if (result != ISC_R_SUCCESS) { 152 isc_pool_destroy(&pool); 153 return (result); 154 } 155 } 156 157 isc_pool_destroy(&pool); 158 pool = newpool; 159 } 160 161 *sourcep = NULL; 162 *targetp = pool; 163 return (ISC_R_SUCCESS); 164} 165 166void 167isc_pool_destroy(isc_pool_t **poolp) { 168 unsigned int i; 169 isc_pool_t *pool = *poolp; 170 for (i = 0; i < pool->count; i++) { 171 if (pool->free != NULL && pool->pool[i] != NULL) 172 pool->free(&pool->pool[i]); 173 } 174 isc_mem_put(pool->mctx, pool->pool, pool->count * sizeof(void *)); 175 isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool)); 176 *poolp = NULL; 177} 178