blob: 5b022a8c6d3f9859895dfb51e249abf7d2d085a6 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
4 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00005 *
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>
Benny Prijono9033e312005-11-21 02:08:39 +000025
Benny Prijono8508aa02006-03-30 15:56:01 +000026#if !PJ_HAS_POOL_ALT_API
27
28
Benny Prijono9033e312005-11-21 02:08:39 +000029/* Include inline definitions when inlining is disabled. */
30#if !PJ_FUNCTIONS_ARE_INLINED
31# include <pj/pool_i.h>
32#endif
33
Benny Prijonoc81dfef2006-01-07 18:41:22 +000034#define LOG(expr) PJ_LOG(6,expr)
Benny Prijono9033e312005-11-21 02:08:39 +000035
Benny Prijono1f61a8f2007-08-16 10:11:44 +000036PJ_DEF_DATA(int) PJ_NO_MEMORY_EXCEPTION;
37
38PJ_DEF(int) pj_NO_MEMORY_EXCEPTION()
39{
40 return PJ_NO_MEMORY_EXCEPTION;
41}
Benny Prijono9033e312005-11-21 02:08:39 +000042
43/*
44 * Create new block.
45 * Create a new big chunk of memory block, from which user allocation will be
46 * taken from.
47 */
48static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
49{
50 pj_pool_block *block;
51
52 PJ_CHECK_STACK();
53 pj_assert(size >= sizeof(pj_pool_block));
54
55 LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
Benny Prijonod4934802005-11-21 16:58:03 +000056 size, pool->capacity, pj_pool_get_used_size(pool)));
Benny Prijono9033e312005-11-21 02:08:39 +000057
58 /* Request memory from allocator. */
59 block = (pj_pool_block*)
60 (*pool->factory->policy.block_alloc)(pool->factory, size);
61 if (block == NULL) {
62 (*pool->callback)(pool, size);
63 return NULL;
64 }
65
66 /* Add capacity. */
67 pool->capacity += size;
Benny Prijono9033e312005-11-21 02:08:39 +000068
Benny Prijono17412422009-10-24 02:06:40 +000069 /* Set start and end of buffer. */
70 block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
Benny Prijono9033e312005-11-21 02:08:39 +000071 block->end = ((unsigned char*)block) + size;
72
Benny Prijono17412422009-10-24 02:06:40 +000073 /* Set the start pointer, aligning it as needed */
74 block->cur = (unsigned char*)
75 (((unsigned long)block->buf + PJ_POOL_ALIGNMENT - 1) &
76 ~(PJ_POOL_ALIGNMENT - 1));
77
Benny Prijono9033e312005-11-21 02:08:39 +000078 /* Insert in the front of the list. */
79 pj_list_insert_after(&pool->block_list, block);
80
81 LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
82
83 return block;
84}
85
86/*
87 * Allocate memory chunk for user from available blocks.
88 * This will iterate through block list to find space to allocate the chunk.
89 * If no space is available in all the blocks, a new block might be created
90 * (depending on whether the pool is allowed to resize).
91 */
92PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
93{
94 pj_pool_block *block = pool->block_list.next;
95 void *p;
96 unsigned block_size;
97
98 PJ_CHECK_STACK();
99
100 while (block != &pool->block_list) {
Benny Prijonod4934802005-11-21 16:58:03 +0000101 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +0000102 if (p != NULL)
103 return p;
104 block = block->next;
105 }
106 /* No available space in all blocks. */
107
108 /* If pool is configured NOT to expand, return error. */
109 if (pool->increment_size == 0) {
110 LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
111 "(used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000112 size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000113 (*pool->callback)(pool, size);
114 return NULL;
115 }
116
117 /* If pool is configured to expand, but the increment size
118 * is less than the required size, expand the pool by multiple
Benny Prijono17412422009-10-24 02:06:40 +0000119 * increment size. Also count the size wasted due to aligning
120 * the block.
Benny Prijono9033e312005-11-21 02:08:39 +0000121 */
Benny Prijono17412422009-10-24 02:06:40 +0000122 if (pool->increment_size <
123 size + sizeof(pj_pool_block) + PJ_POOL_ALIGNMENT)
124 {
Benny Prijono9033e312005-11-21 02:08:39 +0000125 unsigned count;
Benny Prijono17412422009-10-24 02:06:40 +0000126 count = (size + pool->increment_size + sizeof(pj_pool_block) +
127 PJ_POOL_ALIGNMENT) /
Benny Prijono9033e312005-11-21 02:08:39 +0000128 pool->increment_size;
129 block_size = count * pool->increment_size;
130
131 } else {
132 block_size = pool->increment_size;
133 }
134
135 LOG((pool->obj_name,
136 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000137 size, block_size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000138
139 block = pj_pool_create_block(pool, block_size);
140 if (!block)
141 return NULL;
142
Benny Prijonod4934802005-11-21 16:58:03 +0000143 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +0000144 pj_assert(p != NULL);
145#if PJ_DEBUG
146 if (p == NULL) {
147 p = p;
148 }
149#endif
150 return p;
151}
152
153/*
154 * Internal function to initialize pool.
155 */
156PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
157 const char *name,
158 pj_size_t increment_size,
159 pj_pool_callback *callback)
160{
Benny Prijono9033e312005-11-21 02:08:39 +0000161 PJ_CHECK_STACK();
162
163 pool->increment_size = increment_size;
164 pool->callback = callback;
Benny Prijono9033e312005-11-21 02:08:39 +0000165
166 if (name) {
167 if (strchr(name, '%') != NULL) {
Benny Prijonoe85bc412006-07-29 20:29:24 +0000168 pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
169 name, pool);
Benny Prijono9033e312005-11-21 02:08:39 +0000170 } else {
Benny Prijonoed811d72006-03-10 12:57:12 +0000171 pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
Benny Prijono152d1e52007-12-14 17:27:13 +0000172 pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
Benny Prijono9033e312005-11-21 02:08:39 +0000173 }
174 } else {
175 pool->obj_name[0] = '\0';
176 }
177}
178
179/*
180 * Create new memory pool.
181 */
182PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
183 pj_size_t initial_size,
184 pj_size_t increment_size,
185 pj_pool_callback *callback)
186{
187 pj_pool_t *pool;
188 pj_pool_block *block;
Benny Prijonof260e462007-04-30 21:03:32 +0000189 pj_uint8_t *buffer;
Benny Prijono9033e312005-11-21 02:08:39 +0000190
191 PJ_CHECK_STACK();
192
Benny Prijono83217fa2007-02-16 21:44:36 +0000193 /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
194 PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
195 NULL);
196
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000197 /* If callback is NULL, set calback from the policy */
198 if (callback == NULL)
199 callback = f->policy.callback;
200
201 /* Allocate initial block */
Benny Prijonof260e462007-04-30 21:03:32 +0000202 buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000203 if (!buffer)
204 return NULL;
205
206 /* Set pool administrative data. */
207 pool = (pj_pool_t*)buffer;
Benny Prijonoac623b32006-07-03 15:19:31 +0000208 pj_bzero(pool, sizeof(*pool));
Benny Prijono9033e312005-11-21 02:08:39 +0000209
210 pj_list_init(&pool->block_list);
211 pool->factory = f;
212
213 /* Create the first block from the memory. */
214 block = (pj_pool_block*) (buffer + sizeof(*pool));
215 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
216 block->end = buffer + initial_size;
217 pj_list_insert_after(&pool->block_list, block);
218
219 pj_pool_init_int(pool, name, increment_size, callback);
220
221 /* Pool initial capacity and used size */
222 pool->capacity = initial_size;
223
224 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
225 return pool;
226}
227
228/*
229 * Reset the pool to the state when it was created.
230 * All blocks will be deallocated except the first block. All memory areas
231 * are marked as free.
232 */
233static void reset_pool(pj_pool_t *pool)
234{
235 pj_pool_block *block;
236
237 PJ_CHECK_STACK();
238
239 block = pool->block_list.prev;
240 if (block == &pool->block_list)
241 return;
242
243 /* Skip the first block because it is occupying the same memory
244 as the pool itself.
245 */
246 block = block->prev;
247
248 while (block != &pool->block_list) {
249 pj_pool_block *prev = block->prev;
250 pj_list_erase(block);
251 (*pool->factory->policy.block_free)(pool->factory, block,
252 block->end - (unsigned char*)block);
253 block = prev;
254 }
255
256 block = pool->block_list.next;
257 block->cur = block->buf;
258 pool->capacity = block->end - (unsigned char*)pool;
Benny Prijono9033e312005-11-21 02:08:39 +0000259}
260
261/*
262 * The public function to reset pool.
263 */
264PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
265{
266 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
Benny Prijonod4934802005-11-21 16:58:03 +0000267 pool->capacity, pj_pool_get_used_size(pool),
268 pj_pool_get_used_size(pool)*100/pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000269
270 reset_pool(pool);
271}
272
273/*
274 * Destroy the pool.
275 */
276PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
277{
278 pj_size_t initial_size;
279
280 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
Benny Prijonod4934802005-11-21 16:58:03 +0000281 pool->capacity, pj_pool_get_used_size(pool),
282 pj_pool_get_used_size(pool)*100/pool->capacity,
Benny Prijono9033e312005-11-21 02:08:39 +0000283 ((pj_pool_block*)pool->block_list.next)->buf,
284 ((pj_pool_block*)pool->block_list.next)->end));
285
286 reset_pool(pool);
287 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
288 (unsigned char*)pool;
Benny Prijono7d93d4e2006-09-17 19:54:23 +0000289 if (pool->factory->policy.block_free)
290 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000291}
292
293
Benny Prijono8508aa02006-03-30 15:56:01 +0000294#endif /* PJ_HAS_POOL_ALT_API */
295