blob: dcded85377bf5fd82c0ac8a5ab2139516428c067 [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
69 /* Set block attribytes. */
70 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
71 block->end = ((unsigned char*)block) + size;
72
73 /* Insert in the front of the list. */
74 pj_list_insert_after(&pool->block_list, block);
75
76 LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
77
78 return block;
79}
80
81/*
82 * Allocate memory chunk for user from available blocks.
83 * This will iterate through block list to find space to allocate the chunk.
84 * If no space is available in all the blocks, a new block might be created
85 * (depending on whether the pool is allowed to resize).
86 */
87PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
88{
89 pj_pool_block *block = pool->block_list.next;
90 void *p;
91 unsigned block_size;
92
93 PJ_CHECK_STACK();
94
95 while (block != &pool->block_list) {
Benny Prijonod4934802005-11-21 16:58:03 +000096 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +000097 if (p != NULL)
98 return p;
99 block = block->next;
100 }
101 /* No available space in all blocks. */
102
103 /* If pool is configured NOT to expand, return error. */
104 if (pool->increment_size == 0) {
105 LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
106 "(used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000107 size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000108 (*pool->callback)(pool, size);
109 return NULL;
110 }
111
112 /* If pool is configured to expand, but the increment size
113 * is less than the required size, expand the pool by multiple
114 * increment size
115 */
116 if (pool->increment_size < size + sizeof(pj_pool_block)) {
117 unsigned count;
118 count = (size + pool->increment_size + sizeof(pj_pool_block)) /
119 pool->increment_size;
120 block_size = count * pool->increment_size;
121
122 } else {
123 block_size = pool->increment_size;
124 }
125
126 LOG((pool->obj_name,
127 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
Benny Prijonod4934802005-11-21 16:58:03 +0000128 size, block_size, pj_pool_get_used_size(pool), pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000129
130 block = pj_pool_create_block(pool, block_size);
131 if (!block)
132 return NULL;
133
Benny Prijonod4934802005-11-21 16:58:03 +0000134 p = pj_pool_alloc_from_block(block, size);
Benny Prijono9033e312005-11-21 02:08:39 +0000135 pj_assert(p != NULL);
136#if PJ_DEBUG
137 if (p == NULL) {
138 p = p;
139 }
140#endif
141 return p;
142}
143
144/*
145 * Internal function to initialize pool.
146 */
147PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
148 const char *name,
149 pj_size_t increment_size,
150 pj_pool_callback *callback)
151{
Benny Prijono9033e312005-11-21 02:08:39 +0000152 PJ_CHECK_STACK();
153
154 pool->increment_size = increment_size;
155 pool->callback = callback;
Benny Prijono9033e312005-11-21 02:08:39 +0000156
157 if (name) {
158 if (strchr(name, '%') != NULL) {
Benny Prijonoe85bc412006-07-29 20:29:24 +0000159 pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name),
160 name, pool);
Benny Prijono9033e312005-11-21 02:08:39 +0000161 } else {
Benny Prijonoed811d72006-03-10 12:57:12 +0000162 pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
Benny Prijono152d1e52007-12-14 17:27:13 +0000163 pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
Benny Prijono9033e312005-11-21 02:08:39 +0000164 }
165 } else {
166 pool->obj_name[0] = '\0';
167 }
168}
169
170/*
171 * Create new memory pool.
172 */
173PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
174 pj_size_t initial_size,
175 pj_size_t increment_size,
176 pj_pool_callback *callback)
177{
178 pj_pool_t *pool;
179 pj_pool_block *block;
Benny Prijonof260e462007-04-30 21:03:32 +0000180 pj_uint8_t *buffer;
Benny Prijono9033e312005-11-21 02:08:39 +0000181
182 PJ_CHECK_STACK();
183
Benny Prijono83217fa2007-02-16 21:44:36 +0000184 /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
185 PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
186 NULL);
187
Benny Prijono42c5b9e2006-05-10 19:24:40 +0000188 /* If callback is NULL, set calback from the policy */
189 if (callback == NULL)
190 callback = f->policy.callback;
191
192 /* Allocate initial block */
Benny Prijonof260e462007-04-30 21:03:32 +0000193 buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000194 if (!buffer)
195 return NULL;
196
197 /* Set pool administrative data. */
198 pool = (pj_pool_t*)buffer;
Benny Prijonoac623b32006-07-03 15:19:31 +0000199 pj_bzero(pool, sizeof(*pool));
Benny Prijono9033e312005-11-21 02:08:39 +0000200
201 pj_list_init(&pool->block_list);
202 pool->factory = f;
203
204 /* Create the first block from the memory. */
205 block = (pj_pool_block*) (buffer + sizeof(*pool));
206 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
207 block->end = buffer + initial_size;
208 pj_list_insert_after(&pool->block_list, block);
209
210 pj_pool_init_int(pool, name, increment_size, callback);
211
212 /* Pool initial capacity and used size */
213 pool->capacity = initial_size;
214
215 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
216 return pool;
217}
218
219/*
220 * Reset the pool to the state when it was created.
221 * All blocks will be deallocated except the first block. All memory areas
222 * are marked as free.
223 */
224static void reset_pool(pj_pool_t *pool)
225{
226 pj_pool_block *block;
227
228 PJ_CHECK_STACK();
229
230 block = pool->block_list.prev;
231 if (block == &pool->block_list)
232 return;
233
234 /* Skip the first block because it is occupying the same memory
235 as the pool itself.
236 */
237 block = block->prev;
238
239 while (block != &pool->block_list) {
240 pj_pool_block *prev = block->prev;
241 pj_list_erase(block);
242 (*pool->factory->policy.block_free)(pool->factory, block,
243 block->end - (unsigned char*)block);
244 block = prev;
245 }
246
247 block = pool->block_list.next;
248 block->cur = block->buf;
249 pool->capacity = block->end - (unsigned char*)pool;
Benny Prijono9033e312005-11-21 02:08:39 +0000250}
251
252/*
253 * The public function to reset pool.
254 */
255PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
256{
257 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
Benny Prijonod4934802005-11-21 16:58:03 +0000258 pool->capacity, pj_pool_get_used_size(pool),
259 pj_pool_get_used_size(pool)*100/pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000260
261 reset_pool(pool);
262}
263
264/*
265 * Destroy the pool.
266 */
267PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
268{
269 pj_size_t initial_size;
270
271 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
Benny Prijonod4934802005-11-21 16:58:03 +0000272 pool->capacity, pj_pool_get_used_size(pool),
273 pj_pool_get_used_size(pool)*100/pool->capacity,
Benny Prijono9033e312005-11-21 02:08:39 +0000274 ((pj_pool_block*)pool->block_list.next)->buf,
275 ((pj_pool_block*)pool->block_list.next)->end));
276
277 reset_pool(pool);
278 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
279 (unsigned char*)pool;
Benny Prijono7d93d4e2006-09-17 19:54:23 +0000280 if (pool->factory->policy.block_free)
281 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
Benny Prijono9033e312005-11-21 02:08:39 +0000282}
283
284
Benny Prijono8508aa02006-03-30 15:56:01 +0000285#endif /* PJ_HAS_POOL_ALT_API */
286