1
/* $Id: pool.c 4298 2012-11-22 05:00:01Z nanang $ */
3
* Copyright (C) 2008-2011 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
22
#include <pj/except.h>
23
#include <pj/assert.h>
26
#if !PJ_HAS_POOL_ALT_API
29
/* Include inline definitions when inlining is disabled. */
30
#if !PJ_FUNCTIONS_ARE_INLINED
31
# include <pj/pool_i.h>
34
#define LOG(expr) PJ_LOG(6,expr)
35
#define ALIGN_PTR(PTR,ALIGNMENT) (PTR + (-(long)(PTR) & (ALIGNMENT-1)))
37
PJ_DEF_DATA(int) PJ_NO_MEMORY_EXCEPTION;
39
PJ_DEF(int) pj_NO_MEMORY_EXCEPTION()
41
return PJ_NO_MEMORY_EXCEPTION;
46
* Create a new big chunk of memory block, from which user allocation will be
49
static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
54
pj_assert(size >= sizeof(pj_pool_block));
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)));
59
/* Request memory from allocator. */
60
block = (pj_pool_block*)
61
(*pool->factory->policy.block_alloc)(pool->factory, size);
63
(*pool->callback)(pool, size);
68
pool->capacity += size;
70
/* Set start and end of buffer. */
71
block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
72
block->end = ((unsigned char*)block) + size;
74
/* Set the start pointer, aligning it as needed */
75
block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);
77
/* Insert in the front of the list. */
78
pj_list_insert_after(&pool->block_list, block);
80
LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
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).
91
PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, pj_size_t size)
93
pj_pool_block *block = pool->block_list.next;
99
while (block != &pool->block_list) {
100
p = pj_pool_alloc_from_block(block, size);
105
/* No available space in all blocks. */
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 "
111
size, pj_pool_get_used_size(pool), pool->capacity));
112
(*pool->callback)(pool, size);
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
121
if (pool->increment_size <
122
size + sizeof(pj_pool_block) + PJ_POOL_ALIGNMENT)
125
count = (size + pool->increment_size + sizeof(pj_pool_block) +
127
pool->increment_size;
128
block_size = count * pool->increment_size;
131
block_size = pool->increment_size;
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));
138
block = pj_pool_create_block(pool, block_size);
142
p = pj_pool_alloc_from_block(block, size);
143
pj_assert(p != NULL);
153
* Internal function to initialize pool.
155
PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
157
pj_size_t increment_size,
158
pj_pool_callback *callback)
162
pool->increment_size = increment_size;
163
pool->callback = callback;
166
if (strchr(name, '%') != NULL) {
167
pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
170
pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
171
pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
174
pool->obj_name[0] = '\0';
179
* Create new memory pool.
181
PJ_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)
187
pj_pool_block *block;
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),
196
/* If callback is NULL, set calback from the policy */
197
if (callback == NULL)
198
callback = f->policy.callback;
200
/* Allocate initial block */
201
buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
205
/* Set pool administrative data. */
206
pool = (pj_pool_t*)buffer;
207
pj_bzero(pool, sizeof(*pool));
209
pj_list_init(&pool->block_list);
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;
217
/* Set the start pointer, aligning it as needed */
218
block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);
220
pj_list_insert_after(&pool->block_list, block);
222
pj_pool_init_int(pool, name, increment_size, callback);
224
/* Pool initial capacity and used size */
225
pool->capacity = initial_size;
227
LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
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.
236
static void reset_pool(pj_pool_t *pool)
238
pj_pool_block *block;
242
block = pool->block_list.prev;
243
if (block == &pool->block_list)
246
/* Skip the first block because it is occupying the same memory
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);
259
block = pool->block_list.next;
261
/* Set the start pointer, aligning it as needed */
262
block->cur = ALIGN_PTR(block->buf, PJ_POOL_ALIGNMENT);
264
pool->capacity = block->end - (unsigned char*)pool;
268
* The public function to reset pool.
270
PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
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));
282
PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
284
pj_size_t initial_size;
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));
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);
300
#endif /* PJ_HAS_POOL_ALT_API */