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