blob: a9f658c50c03ceb2ec0ea16fedd6c85aa553a9d8 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
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 Prijonoed811d72006-03-10 12:57:12 +0000153 pj_ansi_sprintf(pool->obj_name, name, pool);
Benny Prijono9033e312005-11-21 02:08:39 +0000154 } else {
Benny Prijonoed811d72006-03-10 12:57:12 +0000155 pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
Benny Prijono9033e312005-11-21 02:08:39 +0000156 }
157 } else {
158 pool->obj_name[0] = '\0';
159 }
160}
161
162/*
163 * Create new memory pool.
164 */
165PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
166 pj_size_t initial_size,
167 pj_size_t increment_size,
168 pj_pool_callback *callback)
169{
170 pj_pool_t *pool;
171 pj_pool_block *block;
172 unsigned char *buffer;
173
174 PJ_CHECK_STACK();
175
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000176 /* If callback is NULL, set calback from the policy */
177 if (callback == NULL)
178 callback = f->policy.callback;
179
180 /* Allocate initial block */
Benny Prijono9033e312005-11-21 02:08:39 +0000181 buffer = (*f->policy.block_alloc)(f, initial_size);
182 if (!buffer)
183 return NULL;
184
185 /* Set pool administrative data. */
186 pool = (pj_pool_t*)buffer;
187 pj_memset(pool, 0, sizeof(*pool));
188
189 pj_list_init(&pool->block_list);
190 pool->factory = f;
191
192 /* Create the first block from the memory. */
193 block = (pj_pool_block*) (buffer + sizeof(*pool));
194 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
195 block->end = buffer + initial_size;
196 pj_list_insert_after(&pool->block_list, block);
197
198 pj_pool_init_int(pool, name, increment_size, callback);
199
200 /* Pool initial capacity and used size */
201 pool->capacity = initial_size;
202
203 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
204 return pool;
205}
206
207/*
208 * Reset the pool to the state when it was created.
209 * All blocks will be deallocated except the first block. All memory areas
210 * are marked as free.
211 */
212static void reset_pool(pj_pool_t *pool)
213{
214 pj_pool_block *block;
215
216 PJ_CHECK_STACK();
217
218 block = pool->block_list.prev;
219 if (block == &pool->block_list)
220 return;
221
222 /* Skip the first block because it is occupying the same memory
223 as the pool itself.
224 */
225 block = block->prev;
226
227 while (block != &pool->block_list) {
228 pj_pool_block *prev = block->prev;
229 pj_list_erase(block);
230 (*pool->factory->policy.block_free)(pool->factory, block,
231 block->end - (unsigned char*)block);
232 block = prev;
233 }
234
235 block = pool->block_list.next;
236 block->cur = block->buf;
237 pool->capacity = block->end - (unsigned char*)pool;
Benny Prijono9033e312005-11-21 02:08:39 +0000238}
239
240/*
241 * The public function to reset pool.
242 */
243PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
244{
245 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
Benny Prijonod4934802005-11-21 16:58:03 +0000246 pool->capacity, pj_pool_get_used_size(pool),
247 pj_pool_get_used_size(pool)*100/pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000248
249 reset_pool(pool);
250}
251
252/*
253 * Destroy the pool.
254 */
255PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
256{
257 pj_size_t initial_size;
258
259 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
Benny Prijonod4934802005-11-21 16:58:03 +0000260 pool->capacity, pj_pool_get_used_size(pool),
261 pj_pool_get_used_size(pool)*100/pool->capacity,
Benny Prijono9033e312005-11-21 02:08:39 +0000262 ((pj_pool_block*)pool->block_list.next)->buf,
263 ((pj_pool_block*)pool->block_list.next)->end));
264
265 reset_pool(pool);
266 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
267 (unsigned char*)pool;
268 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
269}
270
271
Benny Prijono8508aa02006-03-30 15:56:01 +0000272#endif /* PJ_HAS_POOL_ALT_API */
273