1
/* $Id: pool.c 2963 2009-10-24 02:06:40Z bennylp $ */
3
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
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.
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.
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
20
* Additional permission under GNU GPL version 3 section 7:
22
* If you modify this program, or any covered work, by linking or
23
* combining it with the OpenSSL project's OpenSSL library (or a
24
* modified version of that library), containing parts covered by the
25
* terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
26
* grants you additional permission to convey the resulting work.
27
* Corresponding Source for a non-source form of such a combination
28
* shall include the source code for the parts of OpenSSL used as well
29
* as that of the covered work.
33
#include <pj/except.h>
34
#include <pj/assert.h>
37
#if !PJ_HAS_POOL_ALT_API
40
/* Include inline definitions when inlining is disabled. */
41
#if !PJ_FUNCTIONS_ARE_INLINED
42
# include <pj/pool_i.h>
45
#define LOG(expr) PJ_LOG(6,expr)
47
PJ_DEF_DATA(int) PJ_NO_MEMORY_EXCEPTION;
49
PJ_DEF(int) pj_NO_MEMORY_EXCEPTION()
51
return PJ_NO_MEMORY_EXCEPTION;
56
* Create a new big chunk of memory block, from which user allocation will be
59
static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
64
pj_assert(size >= sizeof(pj_pool_block));
66
LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
67
size, pool->capacity, pj_pool_get_used_size(pool)));
69
/* Request memory from allocator. */
70
block = (pj_pool_block*)
71
(*pool->factory->policy.block_alloc)(pool->factory, size);
73
(*pool->callback)(pool, size);
78
pool->capacity += size;
80
/* Set start and end of buffer. */
81
block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
82
block->end = ((unsigned char*)block) + size;
84
/* Set the start pointer, aligning it as needed */
85
block->cur = (unsigned char*)
86
(((unsigned long)block->buf + PJ_POOL_ALIGNMENT - 1) &
87
~(PJ_POOL_ALIGNMENT - 1));
89
/* Insert in the front of the list. */
90
pj_list_insert_after(&pool->block_list, block);
92
LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
98
* Allocate memory chunk for user from available blocks.
99
* This will iterate through block list to find space to allocate the chunk.
100
* If no space is available in all the blocks, a new block might be created
101
* (depending on whether the pool is allowed to resize).
103
PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
105
pj_pool_block *block = pool->block_list.next;
111
while (block != &pool->block_list) {
112
p = pj_pool_alloc_from_block(block, size);
117
/* No available space in all blocks. */
119
/* If pool is configured NOT to expand, return error. */
120
if (pool->increment_size == 0) {
121
LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
123
size, pj_pool_get_used_size(pool), pool->capacity));
124
(*pool->callback)(pool, size);
128
/* If pool is configured to expand, but the increment size
129
* is less than the required size, expand the pool by multiple
130
* increment size. Also count the size wasted due to aligning
133
if (pool->increment_size <
134
size + sizeof(pj_pool_block) + PJ_POOL_ALIGNMENT)
137
count = (size + pool->increment_size + sizeof(pj_pool_block) +
139
pool->increment_size;
140
block_size = count * pool->increment_size;
143
block_size = pool->increment_size;
147
"%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
148
size, block_size, pj_pool_get_used_size(pool), pool->capacity));
150
block = pj_pool_create_block(pool, block_size);
154
p = pj_pool_alloc_from_block(block, size);
155
pj_assert(p != NULL);
165
* Internal function to initialize pool.
167
PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
169
pj_size_t increment_size,
170
pj_pool_callback *callback)
174
pool->increment_size = increment_size;
175
pool->callback = callback;
178
if (strchr(name, '%') != NULL) {
179
pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
182
pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
183
pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
186
pool->obj_name[0] = '\0';
191
* Create new memory pool.
193
PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
194
pj_size_t initial_size,
195
pj_size_t increment_size,
196
pj_pool_callback *callback)
199
pj_pool_block *block;
204
/* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
205
PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
208
/* If callback is NULL, set calback from the policy */
209
if (callback == NULL)
210
callback = f->policy.callback;
212
/* Allocate initial block */
213
buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
217
/* Set pool administrative data. */
218
pool = (pj_pool_t*)buffer;
219
pj_bzero(pool, sizeof(*pool));
221
pj_list_init(&pool->block_list);
224
/* Create the first block from the memory. */
225
block = (pj_pool_block*) (buffer + sizeof(*pool));
226
block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
227
block->end = buffer + initial_size;
228
pj_list_insert_after(&pool->block_list, block);
230
pj_pool_init_int(pool, name, increment_size, callback);
232
/* Pool initial capacity and used size */
233
pool->capacity = initial_size;
235
LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
240
* Reset the pool to the state when it was created.
241
* All blocks will be deallocated except the first block. All memory areas
242
* are marked as free.
244
static void reset_pool(pj_pool_t *pool)
246
pj_pool_block *block;
250
block = pool->block_list.prev;
251
if (block == &pool->block_list)
254
/* Skip the first block because it is occupying the same memory
259
while (block != &pool->block_list) {
260
pj_pool_block *prev = block->prev;
261
pj_list_erase(block);
262
(*pool->factory->policy.block_free)(pool->factory, block,
263
block->end - (unsigned char*)block);
267
block = pool->block_list.next;
268
block->cur = block->buf;
269
pool->capacity = block->end - (unsigned char*)pool;
273
* The public function to reset pool.
275
PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
277
LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
278
pool->capacity, pj_pool_get_used_size(pool),
279
pj_pool_get_used_size(pool)*100/pool->capacity));
287
PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
289
pj_size_t initial_size;
291
LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
292
pool->capacity, pj_pool_get_used_size(pool),
293
pj_pool_get_used_size(pool)*100/pool->capacity,
294
((pj_pool_block*)pool->block_list.next)->buf,
295
((pj_pool_block*)pool->block_list.next)->end));
298
initial_size = ((pj_pool_block*)pool->block_list.next)->end -
299
(unsigned char*)pool;
300
if (pool->factory->policy.block_free)
301
(*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
305
#endif /* PJ_HAS_POOL_ALT_API */