blob: 55bfba6559a797d25de5fde2df652e2242ab1630 [file] [log] [blame]
Benny Prijono4766ffe2005-11-01 17:56:59 +00001/* $Id$
2 *
Benny Prijonodd859a62005-11-01 16:42:51 +00003 */
4#include <pj/pool.h>
5#include <pj/log.h>
6#include <pj/except.h>
7#include <pj/assert.h>
8#include <pj/os.h>
9#include <pj/compat/sprintf.h>
10
11/* Include inline definitions when inlining is disabled. */
12#if !PJ_FUNCTIONS_ARE_INLINED
13# include <pj/pool_i.h>
14#endif
15
16#define LOG(expr) PJ_LOG(5,expr)
17
18int PJ_NO_MEMORY_EXCEPTION;
19
20/*
21 * Create new block.
22 * Create a new big chunk of memory block, from which user allocation will be
23 * taken from.
24 */
25static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
26{
27 pj_pool_block *block;
28
29 PJ_CHECK_STACK();
30 pj_assert(size >= sizeof(pj_pool_block));
31
32 LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u",
33 size, pool->capacity, pool->used_size));
34
35 /* Request memory from allocator. */
36 block = (pj_pool_block*)
37 (*pool->factory->policy.block_alloc)(pool->factory, size);
38 if (block == NULL) {
39 (*pool->callback)(pool, size);
40 return NULL;
41 }
42
43 /* Add capacity. */
44 pool->capacity += size;
45 pool->used_size += sizeof(pj_pool_block);
46
47 /* Set block attribytes. */
48 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
49 block->end = ((unsigned char*)block) + size;
50
51 /* Insert in the front of the list. */
52 pj_list_insert_after(&pool->block_list, block);
53
54 LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
55
56 return block;
57}
58
59/*
60 * Allocate memory chunk for user from available blocks.
61 * This will iterate through block list to find space to allocate the chunk.
62 * If no space is available in all the blocks, a new block might be created
63 * (depending on whether the pool is allowed to resize).
64 */
65PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
66{
67 pj_pool_block *block = pool->block_list.next;
68 void *p;
69 unsigned block_size;
70
71 PJ_CHECK_STACK();
72
73 while (block != &pool->block_list) {
74 p = pj_pool_alloc_from_block(pool, block, size);
75 if (p != NULL)
76 return p;
77 block = block->next;
78 }
79 /* No available space in all blocks. */
80
81 /* If pool is configured NOT to expand, return error. */
82 if (pool->increment_size == 0) {
83 LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
84 "(used=%u, cap=%u)",
85 size, pool->used_size, pool->capacity));
86 (*pool->callback)(pool, size);
87 return NULL;
88 }
89
90 /* If pool is configured to expand, but the increment size
91 * is less than the required size, expand the pool by multiple
92 * increment size
93 */
94 if (pool->increment_size < size + sizeof(pj_pool_block)) {
95 unsigned count;
96 count = (size + pool->increment_size + sizeof(pj_pool_block)) /
97 pool->increment_size;
98 block_size = count * pool->increment_size;
99
100 } else {
101 block_size = pool->increment_size;
102 }
103
104 LOG((pool->obj_name,
105 "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
106 size, block_size, pool->used_size, pool->capacity));
107
108 block = pj_pool_create_block(pool, block_size);
109 if (!block)
110 return NULL;
111
112 p = pj_pool_alloc_from_block(pool, block, size);
113 pj_assert(p != NULL);
114#if PJ_DEBUG
115 if (p == NULL) {
116 p = p;
117 }
118#endif
119 return p;
120}
121
122/*
123 * Internal function to initialize pool.
124 */
125PJ_DEF(void) pj_pool_init_int( pj_pool_t *pool,
126 const char *name,
127 pj_size_t increment_size,
128 pj_pool_callback *callback)
129{
130 pj_pool_block *block;
131
132 PJ_CHECK_STACK();
133
134 pool->increment_size = increment_size;
135 pool->callback = callback;
136 pool->used_size = sizeof(*pool);
137 block = pool->block_list.next;
138 while (block != &pool->block_list) {
139 pool->used_size += sizeof(pj_pool_block);
140 block = block->next;
141 }
142
143 if (name) {
144 if (strchr(name, '%') != NULL) {
145 sprintf(pool->obj_name, name, pool);
146 } else {
147 strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
148 }
149 } else {
150 pool->obj_name[0] = '\0';
151 }
152}
153
154/*
155 * Create new memory pool.
156 */
157PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
158 pj_size_t initial_size,
159 pj_size_t increment_size,
160 pj_pool_callback *callback)
161{
162 pj_pool_t *pool;
163 pj_pool_block *block;
164 unsigned char *buffer;
165
166 PJ_CHECK_STACK();
167
168 buffer = (*f->policy.block_alloc)(f, initial_size);
169 if (!buffer)
170 return NULL;
171
172 /* Set pool administrative data. */
173 pool = (pj_pool_t*)buffer;
174 pj_memset(pool, 0, sizeof(*pool));
175
176 pj_list_init(&pool->block_list);
177 pool->factory = f;
178
179 /* Create the first block from the memory. */
180 block = (pj_pool_block*) (buffer + sizeof(*pool));
181 block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
182 block->end = buffer + initial_size;
183 pj_list_insert_after(&pool->block_list, block);
184
185 pj_pool_init_int(pool, name, increment_size, callback);
186
187 /* Pool initial capacity and used size */
188 pool->capacity = initial_size;
189
190 LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
191 return pool;
192}
193
194/*
195 * Reset the pool to the state when it was created.
196 * All blocks will be deallocated except the first block. All memory areas
197 * are marked as free.
198 */
199static void reset_pool(pj_pool_t *pool)
200{
201 pj_pool_block *block;
202
203 PJ_CHECK_STACK();
204
205 block = pool->block_list.prev;
206 if (block == &pool->block_list)
207 return;
208
209 /* Skip the first block because it is occupying the same memory
210 as the pool itself.
211 */
212 block = block->prev;
213
214 while (block != &pool->block_list) {
215 pj_pool_block *prev = block->prev;
216 pj_list_erase(block);
217 (*pool->factory->policy.block_free)(pool->factory, block,
218 block->end - (unsigned char*)block);
219 block = prev;
220 }
221
222 block = pool->block_list.next;
223 block->cur = block->buf;
224 pool->capacity = block->end - (unsigned char*)pool;
225 pool->used_size = 0;
226}
227
228/*
229 * The public function to reset pool.
230 */
231PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
232{
233 LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)",
234 pool->capacity, pool->used_size, pool->used_size*100/pool->capacity));
235
236 reset_pool(pool);
237}
238
239/*
240 * Destroy the pool.
241 */
242PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
243{
244 pj_size_t initial_size;
245
246 LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p",
247 pool->capacity, pool->used_size, pool->used_size*100/pool->capacity,
248 ((pj_pool_block*)pool->block_list.next)->buf,
249 ((pj_pool_block*)pool->block_list.next)->end));
250
251 reset_pool(pool);
252 initial_size = ((pj_pool_block*)pool->block_list.next)->end -
253 (unsigned char*)pool;
254 (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
255}
256
257