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