blob: d3242237a3ae866d2283f2141b7438b9efbc750d [file] [log] [blame]
Alexandre Lision8af73cb2013-12-10 14:11:20 -05001/* $Id: pool.c 4537 2013-06-19 06:47:43Z riza $ */
Tristan Matthews0a329cc2013-07-17 13:20:14 -04002/*
3 * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#include <pj/pool.h>
21#include <pj/log.h>
22#include <pj/except.h>
23#include <pj/assert.h>
24#include <pj/os.h>
25
26#if !PJ_HAS_POOL_ALT_API
27
28
29/* Include inline definitions when inlining is disabled. */
30#if !PJ_FUNCTIONS_ARE_INLINED
31# include <pj/pool_i.h>
32#endif
33
34#define LOG(expr) PJ_LOG(6,expr)
35#define ALIGN_PTR(PTR,ALIGNMENT) (PTR + (-(pj_ssize_t)(PTR) & (ALIGNMENT-1)))
36
37PJ_DEF_DATA(int) PJ_NO_MEMORY_EXCEPTION;
38
39PJ_DEF(int) pj_NO_MEMORY_EXCEPTION()
40{
41 return PJ_NO_MEMORY_EXCEPTION;
42}
43
44/*
45 * Create new block.
46 * Create a new big chunk of memory block, from which user allocation will be
47 * taken from.
48 */
49static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
50{
51 pj_pool_block *block;
52
53 PJ_CHECK_STACK();
54 pj_assert(size >= sizeof(pj_pool_block));
55
56 LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
57 size, pool->capacity, pj_pool_get_used_size(pool)));
58
59 /* Request memory from allocator. */
60 block = (pj_pool_block*)
61 (*pool->factory->policy.block_alloc)(pool->factory, size);
62 if (block == NULL) {
63 (*pool->callback)(pool, size);
64 return NULL;
65 }
66
67 /* Add capacity. */
68 pool->capacity += size;
69
70 /* Set start and end of buffer. */
71 block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
72 block->end = ((unsigned char*)block) + size;
73
74 /* Set the start pointer, aligning it as needed */
75 block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);
76
77 /* Insert in the front of the list. */
78 pj_list_insert_after(&pool->block_list, block);
79
80 LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
81
82 return block;
83}
84
85/*
86 * Allocate memory chunk for user from available blocks.
87 * This will iterate through block list to find space to allocate the chunk.
88 * If no space is available in all the blocks, a new block might be created
89 * (depending on whether the pool is allowed to resize).
90 */
91PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size)
92{
93 pj_pool_block *block = pool->block_list.next;
94 void *p;
95 pj_size_t block_size;
96
97 PJ_CHECK_STACK();
98
99 while (block != &pool->block_list) {
100 p = pj_pool_alloc_from_block(block, size);
101 if (p != NULL)
102 return p;
103 block = block->next;
104 }
105 /* No available space in all blocks. */
106
107 /* If pool is configured NOT to expand, return error. */
108 if (pool->increment_size == 0) {
109 LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
110 "(used=%u, cap=%u)",
111 size, pj_pool_get_used_size(pool), pool->capacity));
112 (*pool->callback)(pool, size);
113 return NULL;
114 }
115
116 /* If pool is configured to expand, but the increment size
117 * is less than the required size, expand the pool by multiple
118 * increment size. Also count the size wasted due to aligning
119 * the block.
120 */
121 if (pool->increment_size <
122 size + sizeof(pj_pool_block) + PJ_POOL_ALIGNMENT)
123 {
124 pj_size_t count;
125 count = (size + pool->increment_size + sizeof(pj_pool_block) +
126 PJ_POOL_ALIGNMENT) /
127 pool->increment_size;
128 block_size = count * pool->increment_size;
129
130 } else {
131 block_size = pool->increment_size;
132 }
133
134 LOG((pool->obj_name,
135 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
136 size, block_size, pj_pool_get_used_size(pool), pool->capacity));
137
138 block = pj_pool_create_block(pool, block_size);
139 if (!block)
140 return NULL;
141
142 p = pj_pool_alloc_from_block(block, size);
143 pj_assert(p != NULL);
144#if PJ_DEBUG
145 if (p == NULL) {
146 p = p;
147 }
148#endif
149 return p;
150}
151
152/*
153 * Internal function to initialize pool.
154 */
155PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
156 const char *name,
157 pj_size_t increment_size,
158 pj_pool_callback *callback)
159{
160 PJ_CHECK_STACK();
161
162 pool->increment_size = increment_size;
163 pool->callback = callback;
164
165 if (name) {
166 if (strchr(name, '%') != NULL) {
167 pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
168 name, pool);
169 } else {
170 pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
171 pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
172 }
173 } else {
174 pool->obj_name[0] = '\0';
175 }
176}
177
178/*
179 * Create new memory pool.
180 */
181PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
182 pj_size_t initial_size,
183 pj_size_t increment_size,
184 pj_pool_callback *callback)
185{
186 pj_pool_t *pool;
187 pj_pool_block *block;
188 pj_uint8_t *buffer;
189
190 PJ_CHECK_STACK();
191
192 /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
193 PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
194 NULL);
195
196 /* If callback is NULL, set calback from the policy */
197 if (callback == NULL)
198 callback = f->policy.callback;
199
200 /* Allocate initial block */
201 buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
202 if (!buffer)
203 return NULL;
204
205 /* Set pool administrative data. */
206 pool = (pj_pool_t*)buffer;
207 pj_bzero(pool, sizeof(*pool));
208
209 pj_list_init(&pool->block_list);
210 pool->factory = f;
211
212 /* Create the first block from the memory. */
213 block = (pj_pool_block*) (buffer + sizeof(*pool));
214 block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
215 block->end = buffer + initial_size;
216
217 /* Set the start pointer, aligning it as needed */
218 block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);
219
220 pj_list_insert_after(&pool->block_list, block);
221
222 pj_pool_init_int(pool, name, increment_size, callback);
223
224 /* Pool initial capacity and used size */
225 pool->capacity = initial_size;
226
227 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
228 return pool;
229}
230
231/*
232 * Reset the pool to the state when it was created.
233 * All blocks will be deallocated except the first block. All memory areas
234 * are marked as free.
235 */
236static void reset_pool(pj_pool_t *pool)
237{
238 pj_pool_block *block;
239
240 PJ_CHECK_STACK();
241
242 block = pool->block_list.prev;
243 if (block == &pool->block_list)
244 return;
245
246 /* Skip the first block because it is occupying the same memory
247 as the pool itself.
248 */
249 block = block->prev;
250
251 while (block != &pool->block_list) {
252 pj_pool_block *prev = block->prev;
253 pj_list_erase(block);
254 (*pool->factory->policy.block_free)(pool->factory, block,
255 block->end - (unsigned char*)block);
256 block = prev;
257 }
258
259 block = pool->block_list.next;
260
261 /* Set the start pointer, aligning it as needed */
262 block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);
263
264 pool->capacity = block->end - (unsigned char*)pool;
265}
266
267/*
268 * The public function to reset pool.
269 */
270PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
271{
272 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
273 pool->capacity, pj_pool_get_used_size(pool),
274 pj_pool_get_used_size(pool)*100/pool->capacity));
275
276 reset_pool(pool);
277}
278
279/*
280 * Destroy the pool.
281 */
282PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
283{
284 pj_size_t initial_size;
285
286 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
287 pool->capacity, pj_pool_get_used_size(pool),
288 pj_pool_get_used_size(pool)*100/pool->capacity,
289 ((pj_pool_block*)pool->block_list.next)->buf,
290 ((pj_pool_block*)pool->block_list.next)->end));
291
292 reset_pool(pool);
293 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
294 (unsigned char*)pool;
295 if (pool->factory->policy.block_free)
296 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
297}
298
299
300#endif /* PJ_HAS_POOL_ALT_API */
301