blob: 10947808bbcea8f7e53270d6287d77fe36a1b112 [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
Benny Prijono1f61a8f2007-08-16 10:11:44 +000035PJ_DEF_DATA(int) PJ_NO_MEMORY_EXCEPTION;
36
37PJ_DEF(int) pj_NO_MEMORY_EXCEPTION()
38{
39 return PJ_NO_MEMORY_EXCEPTION;
40}
Benny Prijono9033e312005-11-21 02:08:39 +000041
42/*
43 * Create new block.
44 * Create a new big chunk of memory block, from which user allocation will be
45 * taken from.
46 */
47static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
48{
49 pj_pool_block *block;
50
51 PJ_CHECK_STACK();
52 pj_assert(size >= sizeof(pj_pool_block));
53
54 LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
Benny Prijonod4934802005-11-21 16:58:03 +000055 size, pool->capacity, pj_pool_get_used_size(pool)));
Benny Prijono9033e312005-11-21 02:08:39 +000056
57 /* Request memory from allocator. */
58 block = (pj_pool_block*)
59 (*pool->factory->policy.block_alloc)(pool->factory, size);
60 if (block == NULL) {
61 (*pool->callback)(pool, size);
62 return NULL;
63 }
64
65 /* Add capacity. */
66 pool->capacity += size;
Benny Prijono9033e312005-11-21 02:08:39 +000067
68 /* Set block attribytes. */
69 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
70 block->end = ((unsigned char*)block) + size;
71
72 /* Insert in the front of the list. */
73 pj_list_insert_after(&pool->block_list, block);
74
75 LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
76
77 return block;
78}
79
80/*
81 * Allocate memory chunk for user from available blocks.
82 * This will iterate through block list to find space to allocate the chunk.
83 * If no space is available in all the blocks, a new block might be created
84 * (depending on whether the pool is allowed to resize).
85 */
86PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
87{
88 pj_pool_block *block = pool->block_list.next;
89 void *p;
90 unsigned block_size;
91
92 PJ_CHECK_STACK();
93
94 while (block != &pool->block_list) {
Benny Prijonod4934802005-11-21 16:58:03 +000095 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +000096 if (p != NULL)
97 return p;
98 block = block->next;
99 }
100 /* No available space in all blocks. */
101
102 /* If pool is configured NOT to expand, return error. */
103 if (pool->increment_size == 0) {
104 LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
105 "(used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000106 size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000107 (*pool->callback)(pool, size);
108 return NULL;
109 }
110
111 /* If pool is configured to expand, but the increment size
112 * is less than the required size, expand the pool by multiple
113 * increment size
114 */
115 if (pool->increment_size < size + sizeof(pj_pool_block)) {
116 unsigned count;
117 count = (size + pool->increment_size + sizeof(pj_pool_block)) /
118 pool->increment_size;
119 block_size = count * pool->increment_size;
120
121 } else {
122 block_size = pool->increment_size;
123 }
124
125 LOG((pool->obj_name,
126 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000127 size, block_size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000128
129 block = pj_pool_create_block(pool, block_size);
130 if (!block)
131 return NULL;
132
Benny Prijonod4934802005-11-21 16:58:03 +0000133 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +0000134 pj_assert(p != NULL);
135#if PJ_DEBUG
136 if (p == NULL) {
137 p = p;
138 }
139#endif
140 return p;
141}
142
143/*
144 * Internal function to initialize pool.
145 */
146PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
147 const char *name,
148 pj_size_t increment_size,
149 pj_pool_callback *callback)
150{
Benny Prijono9033e312005-11-21 02:08:39 +0000151 PJ_CHECK_STACK();
152
153 pool->increment_size = increment_size;
154 pool->callback = callback;
Benny Prijono9033e312005-11-21 02:08:39 +0000155
156 if (name) {
157 if (strchr(name, '%') != NULL) {
Benny Prijonoe85bc412006-07-29 20:29:24 +0000158 pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
159 name, pool);
Benny Prijono9033e312005-11-21 02:08:39 +0000160 } else {
Benny Prijonoed811d72006-03-10 12:57:12 +0000161 pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
Benny Prijono152d1e52007-12-14 17:27:13 +0000162 pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
Benny Prijono9033e312005-11-21 02:08:39 +0000163 }
164 } else {
165 pool->obj_name[0] = '\0';
166 }
167}
168
169/*
170 * Create new memory pool.
171 */
172PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
173 pj_size_t initial_size,
174 pj_size_t increment_size,
175 pj_pool_callback *callback)
176{
177 pj_pool_t *pool;
178 pj_pool_block *block;
Benny Prijonof260e462007-04-30 21:03:32 +0000179 pj_uint8_t *buffer;
Benny Prijono9033e312005-11-21 02:08:39 +0000180
181 PJ_CHECK_STACK();
182
Benny Prijono83217fa2007-02-16 21:44:36 +0000183 /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
184 PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
185 NULL);
186
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000187 /* If callback is NULL, set calback from the policy */
188 if (callback == NULL)
189 callback = f->policy.callback;
190
191 /* Allocate initial block */
Benny Prijonof260e462007-04-30 21:03:32 +0000192 buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000193 if (!buffer)
194 return NULL;
195
196 /* Set pool administrative data. */
197 pool = (pj_pool_t*)buffer;
Benny Prijonoac623b32006-07-03 15:19:31 +0000198 pj_bzero(pool, sizeof(*pool));
Benny Prijono9033e312005-11-21 02:08:39 +0000199
200 pj_list_init(&pool->block_list);
201 pool->factory = f;
202
203 /* Create the first block from the memory. */
204 block = (pj_pool_block*) (buffer + sizeof(*pool));
205 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
206 block->end = buffer + initial_size;
207 pj_list_insert_after(&pool->block_list, block);
208
209 pj_pool_init_int(pool, name, increment_size, callback);
210
211 /* Pool initial capacity and used size */
212 pool->capacity = initial_size;
213
214 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
215 return pool;
216}
217
218/*
219 * Reset the pool to the state when it was created.
220 * All blocks will be deallocated except the first block. All memory areas
221 * are marked as free.
222 */
223static void reset_pool(pj_pool_t *pool)
224{
225 pj_pool_block *block;
226
227 PJ_CHECK_STACK();
228
229 block = pool->block_list.prev;
230 if (block == &pool->block_list)
231 return;
232
233 /* Skip the first block because it is occupying the same memory
234 as the pool itself.
235 */
236 block = block->prev;
237
238 while (block != &pool->block_list) {
239 pj_pool_block *prev = block->prev;
240 pj_list_erase(block);
241 (*pool->factory->policy.block_free)(pool->factory, block,
242 block->end - (unsigned char*)block);
243 block = prev;
244 }
245
246 block = pool->block_list.next;
247 block->cur = block->buf;
248 pool->capacity = block->end - (unsigned char*)pool;
Benny Prijono9033e312005-11-21 02:08:39 +0000249}
250
251/*
252 * The public function to reset pool.
253 */
254PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
255{
256 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
Benny Prijonod4934802005-11-21 16:58:03 +0000257 pool->capacity, pj_pool_get_used_size(pool),
258 pj_pool_get_used_size(pool)*100/pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000259
260 reset_pool(pool);
261}
262
263/*
264 * Destroy the pool.
265 */
266PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
267{
268 pj_size_t initial_size;
269
270 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
Benny Prijonod4934802005-11-21 16:58:03 +0000271 pool->capacity, pj_pool_get_used_size(pool),
272 pj_pool_get_used_size(pool)*100/pool->capacity,
Benny Prijono9033e312005-11-21 02:08:39 +0000273 ((pj_pool_block*)pool->block_list.next)->buf,
274 ((pj_pool_block*)pool->block_list.next)->end));
275
276 reset_pool(pool);
277 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
278 (unsigned char*)pool;
Benny Prijono7d93d4e2006-09-17 19:54:23 +0000279 if (pool->factory->policy.block_free)
280 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000281}
282
283
Benny Prijono8508aa02006-03-30 15:56:01 +0000284#endif /* PJ_HAS_POOL_ALT_API */
285