blob: 9f47892dfadaabe44f9ce8b0ca67d78815ea2325 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
Benny Prijonoa771a512007-02-19 01:13:53 +00003 * Copyright (C)2003-2007 Benny Prijono <benny@prijono.org>
Benny Prijono9033e312005-11-21 02:08:39 +00004 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/pool.h>
20#include <pj/log.h>
21#include <pj/except.h>
22#include <pj/assert.h>
23#include <pj/os.h>
Benny Prijono9033e312005-11-21 02:08:39 +000024
Benny Prijono8508aa02006-03-30 15:56:01 +000025#if !PJ_HAS_POOL_ALT_API
26
27
Benny Prijono9033e312005-11-21 02:08:39 +000028/* Include inline definitions when inlining is disabled. */
29#if !PJ_FUNCTIONS_ARE_INLINED
30# include <pj/pool_i.h>
31#endif
32
Benny Prijonoc81dfef2006-01-07 18:41:22 +000033#define LOG(expr) PJ_LOG(6,expr)
Benny Prijono9033e312005-11-21 02:08:39 +000034
35int PJ_NO_MEMORY_EXCEPTION;
36
37/*
38 * Create new block.
39 * Create a new big chunk of memory block, from which user allocation will be
40 * taken from.
41 */
42static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
43{
44 pj_pool_block *block;
45
46 PJ_CHECK_STACK();
47 pj_assert(size >= sizeof(pj_pool_block));
48
49 LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
Benny Prijonod4934802005-11-21 16:58:03 +000050 size, pool->capacity, pj_pool_get_used_size(pool)));
Benny Prijono9033e312005-11-21 02:08:39 +000051
52 /* Request memory from allocator. */
53 block = (pj_pool_block*)
54 (*pool->factory->policy.block_alloc)(pool->factory, size);
55 if (block == NULL) {
56 (*pool->callback)(pool, size);
57 return NULL;
58 }
59
60 /* Add capacity. */
61 pool->capacity += size;
Benny Prijono9033e312005-11-21 02:08:39 +000062
63 /* Set block attribytes. */
64 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
65 block->end = ((unsigned char*)block) + size;
66
67 /* Insert in the front of the list. */
68 pj_list_insert_after(&pool->block_list, block);
69
70 LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
71
72 return block;
73}
74
75/*
76 * Allocate memory chunk for user from available blocks.
77 * This will iterate through block list to find space to allocate the chunk.
78 * If no space is available in all the blocks, a new block might be created
79 * (depending on whether the pool is allowed to resize).
80 */
81PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
82{
83 pj_pool_block *block = pool->block_list.next;
84 void *p;
85 unsigned block_size;
86
87 PJ_CHECK_STACK();
88
89 while (block != &pool->block_list) {
Benny Prijonod4934802005-11-21 16:58:03 +000090 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +000091 if (p != NULL)
92 return p;
93 block = block->next;
94 }
95 /* No available space in all blocks. */
96
97 /* If pool is configured NOT to expand, return error. */
98 if (pool->increment_size == 0) {
99 LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
100 "(used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000101 size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000102 (*pool->callback)(pool, size);
103 return NULL;
104 }
105
106 /* If pool is configured to expand, but the increment size
107 * is less than the required size, expand the pool by multiple
108 * increment size
109 */
110 if (pool->increment_size < size + sizeof(pj_pool_block)) {
111 unsigned count;
112 count = (size + pool->increment_size + sizeof(pj_pool_block)) /
113 pool->increment_size;
114 block_size = count * pool->increment_size;
115
116 } else {
117 block_size = pool->increment_size;
118 }
119
120 LOG((pool->obj_name,
121 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000122 size, block_size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000123
124 block = pj_pool_create_block(pool, block_size);
125 if (!block)
126 return NULL;
127
Benny Prijonod4934802005-11-21 16:58:03 +0000128 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +0000129 pj_assert(p != NULL);
130#if PJ_DEBUG
131 if (p == NULL) {
132 p = p;
133 }
134#endif
135 return p;
136}
137
138/*
139 * Internal function to initialize pool.
140 */
141PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
142 const char *name,
143 pj_size_t increment_size,
144 pj_pool_callback *callback)
145{
Benny Prijono9033e312005-11-21 02:08:39 +0000146 PJ_CHECK_STACK();
147
148 pool->increment_size = increment_size;
149 pool->callback = callback;
Benny Prijono9033e312005-11-21 02:08:39 +0000150
151 if (name) {
152 if (strchr(name, '%') != NULL) {
Benny Prijonoe85bc412006-07-29 20:29:24 +0000153 pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
154 name, pool);
Benny Prijono9033e312005-11-21 02:08:39 +0000155 } else {
Benny Prijonoed811d72006-03-10 12:57:12 +0000156 pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
Benny Prijono9033e312005-11-21 02:08:39 +0000157 }
158 } else {
159 pool->obj_name[0] = '\0';
160 }
161}
162
163/*
164 * Create new memory pool.
165 */
166PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
167 pj_size_t initial_size,
168 pj_size_t increment_size,
169 pj_pool_callback *callback)
170{
171 pj_pool_t *pool;
172 pj_pool_block *block;
Benny Prijonof260e462007-04-30 21:03:32 +0000173 pj_uint8_t *buffer;
Benny Prijono9033e312005-11-21 02:08:39 +0000174
175 PJ_CHECK_STACK();
176
Benny Prijono83217fa2007-02-16 21:44:36 +0000177 /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
178 PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
179 NULL);
180
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000181 /* If callback is NULL, set calback from the policy */
182 if (callback == NULL)
183 callback = f->policy.callback;
184
185 /* Allocate initial block */
Benny Prijonof260e462007-04-30 21:03:32 +0000186 buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000187 if (!buffer)
188 return NULL;
189
190 /* Set pool administrative data. */
191 pool = (pj_pool_t*)buffer;
Benny Prijonoac623b32006-07-03 15:19:31 +0000192 pj_bzero(pool, sizeof(*pool));
Benny Prijono9033e312005-11-21 02:08:39 +0000193
194 pj_list_init(&pool->block_list);
195 pool->factory = f;
196
197 /* Create the first block from the memory. */
198 block = (pj_pool_block*) (buffer + sizeof(*pool));
199 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
200 block->end = buffer + initial_size;
201 pj_list_insert_after(&pool->block_list, block);
202
203 pj_pool_init_int(pool, name, increment_size, callback);
204
205 /* Pool initial capacity and used size */
206 pool->capacity = initial_size;
207
208 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
209 return pool;
210}
211
212/*
213 * Reset the pool to the state when it was created.
214 * All blocks will be deallocated except the first block. All memory areas
215 * are marked as free.
216 */
217static void reset_pool(pj_pool_t *pool)
218{
219 pj_pool_block *block;
220
221 PJ_CHECK_STACK();
222
223 block = pool->block_list.prev;
224 if (block == &pool->block_list)
225 return;
226
227 /* Skip the first block because it is occupying the same memory
228 as the pool itself.
229 */
230 block = block->prev;
231
232 while (block != &pool->block_list) {
233 pj_pool_block *prev = block->prev;
234 pj_list_erase(block);
235 (*pool->factory->policy.block_free)(pool->factory, block,
236 block->end - (unsigned char*)block);
237 block = prev;
238 }
239
240 block = pool->block_list.next;
241 block->cur = block->buf;
242 pool->capacity = block->end - (unsigned char*)pool;
Benny Prijono9033e312005-11-21 02:08:39 +0000243}
244
245/*
246 * The public function to reset pool.
247 */
248PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
249{
250 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
Benny Prijonod4934802005-11-21 16:58:03 +0000251 pool->capacity, pj_pool_get_used_size(pool),
252 pj_pool_get_used_size(pool)*100/pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000253
254 reset_pool(pool);
255}
256
257/*
258 * Destroy the pool.
259 */
260PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
261{
262 pj_size_t initial_size;
263
264 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
Benny Prijonod4934802005-11-21 16:58:03 +0000265 pool->capacity, pj_pool_get_used_size(pool),
266 pj_pool_get_used_size(pool)*100/pool->capacity,
Benny Prijono9033e312005-11-21 02:08:39 +0000267 ((pj_pool_block*)pool->block_list.next)->buf,
268 ((pj_pool_block*)pool->block_list.next)->end));
269
270 reset_pool(pool);
271 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
272 (unsigned char*)pool;
Benny Prijono7d93d4e2006-09-17 19:54:23 +0000273 if (pool->factory->policy.block_free)
274 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000275}
276
277
Benny Prijono8508aa02006-03-30 15:56:01 +0000278#endif /* PJ_HAS_POOL_ALT_API */
279