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