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