1 1.1 christos /* $NetBSD: pool.c,v 1.1 2024/02/18 20:57:50 christos Exp $ */ 2 1.1 christos 3 1.1 christos /* 4 1.1 christos * Copyright (C) Internet Systems Consortium, Inc. ("ISC") 5 1.1 christos * 6 1.1 christos * SPDX-License-Identifier: MPL-2.0 7 1.1 christos * 8 1.1 christos * This Source Code Form is subject to the terms of the Mozilla Public 9 1.1 christos * License, v. 2.0. If a copy of the MPL was not distributed with this 10 1.1 christos * file, you can obtain one at https://mozilla.org/MPL/2.0/. 11 1.1 christos * 12 1.1 christos * See the COPYRIGHT file distributed with this work for additional 13 1.1 christos * information regarding copyright ownership. 14 1.1 christos */ 15 1.1 christos 16 1.1 christos /*! \file */ 17 1.1 christos 18 1.1 christos #include <string.h> 19 1.1 christos 20 1.1 christos #include <isc/mem.h> 21 1.1 christos #include <isc/pool.h> 22 1.1 christos #include <isc/random.h> 23 1.1 christos #include <isc/util.h> 24 1.1 christos 25 1.1 christos /*** 26 1.1 christos *** Types. 27 1.1 christos ***/ 28 1.1 christos 29 1.1 christos struct isc_pool { 30 1.1 christos isc_mem_t *mctx; 31 1.1 christos unsigned int count; 32 1.1 christos isc_pooldeallocator_t free; 33 1.1 christos isc_poolinitializer_t init; 34 1.1 christos void *initarg; 35 1.1 christos void **pool; 36 1.1 christos }; 37 1.1 christos 38 1.1 christos /*** 39 1.1 christos *** Functions. 40 1.1 christos ***/ 41 1.1 christos 42 1.1 christos static isc_result_t 43 1.1 christos alloc_pool(isc_mem_t *mctx, unsigned int count, isc_pool_t **poolp) { 44 1.1 christos isc_pool_t *pool; 45 1.1 christos 46 1.1 christos pool = isc_mem_get(mctx, sizeof(*pool)); 47 1.1 christos pool->count = count; 48 1.1 christos pool->free = NULL; 49 1.1 christos pool->init = NULL; 50 1.1 christos pool->initarg = NULL; 51 1.1 christos pool->mctx = NULL; 52 1.1 christos isc_mem_attach(mctx, &pool->mctx); 53 1.1 christos pool->pool = isc_mem_get(mctx, count * sizeof(void *)); 54 1.1 christos memset(pool->pool, 0, count * sizeof(void *)); 55 1.1 christos 56 1.1 christos *poolp = pool; 57 1.1 christos return (ISC_R_SUCCESS); 58 1.1 christos } 59 1.1 christos 60 1.1 christos isc_result_t 61 1.1 christos isc_pool_create(isc_mem_t *mctx, unsigned int count, 62 1.1 christos isc_pooldeallocator_t release, isc_poolinitializer_t init, 63 1.1 christos void *initarg, isc_pool_t **poolp) { 64 1.1 christos isc_pool_t *pool = NULL; 65 1.1 christos isc_result_t result; 66 1.1 christos unsigned int i; 67 1.1 christos 68 1.1 christos INSIST(count > 0); 69 1.1 christos 70 1.1 christos /* Allocate the pool structure */ 71 1.1 christos result = alloc_pool(mctx, count, &pool); 72 1.1 christos if (result != ISC_R_SUCCESS) { 73 1.1 christos return (result); 74 1.1 christos } 75 1.1 christos 76 1.1 christos pool->free = release; 77 1.1 christos pool->init = init; 78 1.1 christos pool->initarg = initarg; 79 1.1 christos 80 1.1 christos /* Populate the pool */ 81 1.1 christos for (i = 0; i < count; i++) { 82 1.1 christos result = init(&pool->pool[i], initarg); 83 1.1 christos if (result != ISC_R_SUCCESS) { 84 1.1 christos isc_pool_destroy(&pool); 85 1.1 christos return (result); 86 1.1 christos } 87 1.1 christos } 88 1.1 christos 89 1.1 christos *poolp = pool; 90 1.1 christos return (ISC_R_SUCCESS); 91 1.1 christos } 92 1.1 christos 93 1.1 christos void * 94 1.1 christos isc_pool_get(isc_pool_t *pool) { 95 1.1 christos return (pool->pool[isc_random_uniform(pool->count)]); 96 1.1 christos } 97 1.1 christos 98 1.1 christos int 99 1.1 christos isc_pool_count(isc_pool_t *pool) { 100 1.1 christos REQUIRE(pool != NULL); 101 1.1 christos return (pool->count); 102 1.1 christos } 103 1.1 christos 104 1.1 christos isc_result_t 105 1.1 christos isc_pool_expand(isc_pool_t **sourcep, unsigned int count, 106 1.1 christos isc_pool_t **targetp) { 107 1.1 christos isc_result_t result; 108 1.1 christos isc_pool_t *pool; 109 1.1 christos 110 1.1 christos REQUIRE(sourcep != NULL && *sourcep != NULL); 111 1.1 christos REQUIRE(targetp != NULL && *targetp == NULL); 112 1.1 christos 113 1.1 christos pool = *sourcep; 114 1.1 christos *sourcep = NULL; 115 1.1 christos if (count > pool->count) { 116 1.1 christos isc_pool_t *newpool = NULL; 117 1.1 christos unsigned int i; 118 1.1 christos 119 1.1 christos /* Allocate a new pool structure */ 120 1.1 christos result = alloc_pool(pool->mctx, count, &newpool); 121 1.1 christos if (result != ISC_R_SUCCESS) { 122 1.1 christos return (result); 123 1.1 christos } 124 1.1 christos 125 1.1 christos newpool->free = pool->free; 126 1.1 christos newpool->init = pool->init; 127 1.1 christos newpool->initarg = pool->initarg; 128 1.1 christos 129 1.1 christos /* Populate the new entries */ 130 1.1 christos for (i = pool->count; i < count; i++) { 131 1.1 christos result = newpool->init(&newpool->pool[i], 132 1.1 christos newpool->initarg); 133 1.1 christos if (result != ISC_R_SUCCESS) { 134 1.1 christos isc_pool_destroy(&newpool); 135 1.1 christos return (result); 136 1.1 christos } 137 1.1 christos } 138 1.1 christos 139 1.1 christos /* Copy over the objects from the old pool */ 140 1.1 christos for (i = 0; i < pool->count; i++) { 141 1.1 christos newpool->pool[i] = pool->pool[i]; 142 1.1 christos pool->pool[i] = NULL; 143 1.1 christos } 144 1.1 christos 145 1.1 christos isc_pool_destroy(&pool); 146 1.1 christos pool = newpool; 147 1.1 christos } 148 1.1 christos 149 1.1 christos *targetp = pool; 150 1.1 christos return (ISC_R_SUCCESS); 151 1.1 christos } 152 1.1 christos 153 1.1 christos void 154 1.1 christos isc_pool_destroy(isc_pool_t **poolp) { 155 1.1 christos unsigned int i; 156 1.1 christos isc_pool_t *pool = *poolp; 157 1.1 christos *poolp = NULL; 158 1.1 christos for (i = 0; i < pool->count; i++) { 159 1.1 christos if (pool->free != NULL && pool->pool[i] != NULL) { 160 1.1 christos pool->free(&pool->pool[i]); 161 1.1 christos } 162 1.1 christos } 163 1.1 christos isc_mem_put(pool->mctx, pool->pool, pool->count * sizeof(void *)); 164 1.1 christos isc_mem_putanddetach(&pool->mctx, pool, sizeof(*pool)); 165 1.1 christos } 166