~ubuntu-branches/ubuntu/maverick/sflphone/maverick

« back to all changes in this revision

Viewing changes to sflphone-common/libs/pjproject/pjlib/src/pj/pool.c

  • Committer: Bazaar Package Importer
  • Author(s): Francois Marier
  • Date: 2010-06-03 15:59:46 UTC
  • Revision ID: james.westby@ubuntu.com-20100603155946-ybe8d8o8zx8lp0m8
Tags: upstream-0.9.8.3
ImportĀ upstreamĀ versionĀ 0.9.8.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: pool.c 2963 2009-10-24 02:06:40Z bennylp $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
 
4
 * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
 
5
 *
 
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
 *  Additional permission under GNU GPL version 3 section 7:
 
21
 *
 
22
 *  If you modify this program, or any covered work, by linking or
 
23
 *  combining it with the OpenSSL project's OpenSSL library (or a
 
24
 *  modified version of that library), containing parts covered by the
 
25
 *  terms of the OpenSSL or SSLeay licenses, Teluu Inc. (http://www.teluu.com)
 
26
 *  grants you additional permission to convey the resulting work.
 
27
 *  Corresponding Source for a non-source form of such a combination
 
28
 *  shall include the source code for the parts of OpenSSL used as well
 
29
 *  as that of the covered work.
 
30
 */
 
31
#include <pj/pool.h>
 
32
#include <pj/log.h>
 
33
#include <pj/except.h>
 
34
#include <pj/assert.h>
 
35
#include <pj/os.h>
 
36
 
 
37
#if !PJ_HAS_POOL_ALT_API
 
38
 
 
39
 
 
40
/* Include inline definitions when inlining is disabled. */
 
41
#if !PJ_FUNCTIONS_ARE_INLINED
 
42
#  include <pj/pool_i.h>
 
43
#endif
 
44
 
 
45
#define LOG(expr)   PJ_LOG(6,expr)
 
46
 
 
47
PJ_DEF_DATA(int) PJ_NO_MEMORY_EXCEPTION;
 
48
 
 
49
PJ_DEF(int) pj_NO_MEMORY_EXCEPTION()
 
50
{
 
51
    return PJ_NO_MEMORY_EXCEPTION;
 
52
}
 
53
 
 
54
/*
 
55
 * Create new block.
 
56
 * Create a new big chunk of memory block, from which user allocation will be
 
57
 * taken from.
 
58
 */
 
59
static pj_pool_block *pj_pool_create_block( pj_pool_t *pool, pj_size_t size)
 
60
{
 
61
    pj_pool_block *block;
 
62
 
 
63
    PJ_CHECK_STACK();
 
64
    pj_assert(size >= sizeof(pj_pool_block));
 
65
 
 
66
    LOG((pool->obj_name, "create_block(sz=%u), cur.cap=%u, cur.used=%u", 
 
67
         size, pool->capacity, pj_pool_get_used_size(pool)));
 
68
 
 
69
    /* Request memory from allocator. */
 
70
    block = (pj_pool_block*) 
 
71
        (*pool->factory->policy.block_alloc)(pool->factory, size);
 
72
    if (block == NULL) {
 
73
        (*pool->callback)(pool, size);
 
74
        return NULL;
 
75
    }
 
76
 
 
77
    /* Add capacity. */
 
78
    pool->capacity += size;
 
79
 
 
80
    /* Set start and end of buffer. */
 
81
    block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
 
82
    block->end = ((unsigned char*)block) + size;
 
83
 
 
84
    /* Set the start pointer, aligning it as needed */
 
85
    block->cur = (unsigned char*)
 
86
                 (((unsigned long)block->buf + PJ_POOL_ALIGNMENT - 1) & 
 
87
                  ~(PJ_POOL_ALIGNMENT - 1));
 
88
 
 
89
    /* Insert in the front of the list. */
 
90
    pj_list_insert_after(&pool->block_list, block);
 
91
 
 
92
    LOG((pool->obj_name," block created, buffer=%p-%p",block->buf, block->end));
 
93
 
 
94
    return block;
 
95
}
 
96
 
 
97
/*
 
98
 * Allocate memory chunk for user from available blocks.
 
99
 * This will iterate through block list to find space to allocate the chunk.
 
100
 * If no space is available in all the blocks, a new block might be created
 
101
 * (depending on whether the pool is allowed to resize).
 
102
 */
 
103
PJ_DEF(void*) pj_pool_allocate_find(pj_pool_t *pool, unsigned size)
 
104
{
 
105
    pj_pool_block *block = pool->block_list.next;
 
106
    void *p;
 
107
    unsigned block_size;
 
108
 
 
109
    PJ_CHECK_STACK();
 
110
 
 
111
    while (block != &pool->block_list) {
 
112
        p = pj_pool_alloc_from_block(block, size);
 
113
        if (p != NULL)
 
114
            return p;
 
115
        block = block->next;
 
116
    }
 
117
    /* No available space in all blocks. */
 
118
 
 
119
    /* If pool is configured NOT to expand, return error. */
 
120
    if (pool->increment_size == 0) {
 
121
        LOG((pool->obj_name, "Can't expand pool to allocate %u bytes "
 
122
             "(used=%u, cap=%u)",
 
123
             size, pj_pool_get_used_size(pool), pool->capacity));
 
124
        (*pool->callback)(pool, size);
 
125
        return NULL;
 
126
    }
 
127
 
 
128
    /* If pool is configured to expand, but the increment size
 
129
     * is less than the required size, expand the pool by multiple
 
130
     * increment size. Also count the size wasted due to aligning
 
131
     * the block.
 
132
     */
 
133
    if (pool->increment_size < 
 
134
            size + sizeof(pj_pool_block) + PJ_POOL_ALIGNMENT) 
 
135
    {
 
136
        unsigned count;
 
137
        count = (size + pool->increment_size + sizeof(pj_pool_block) +
 
138
                 PJ_POOL_ALIGNMENT) / 
 
139
                pool->increment_size;
 
140
        block_size = count * pool->increment_size;
 
141
 
 
142
    } else {
 
143
        block_size = pool->increment_size;
 
144
    }
 
145
 
 
146
    LOG((pool->obj_name, 
 
147
         "%u bytes requested, resizing pool by %u bytes (used=%u, cap=%u)",
 
148
         size, block_size, pj_pool_get_used_size(pool), pool->capacity));
 
149
 
 
150
    block = pj_pool_create_block(pool, block_size);
 
151
    if (!block)
 
152
        return NULL;
 
153
 
 
154
    p = pj_pool_alloc_from_block(block, size);
 
155
    pj_assert(p != NULL);
 
156
#if PJ_DEBUG
 
157
    if (p == NULL) {
 
158
        p = p;
 
159
    }
 
160
#endif
 
161
    return p;
 
162
}
 
163
 
 
164
/*
 
165
 * Internal function to initialize pool.
 
166
 */
 
167
PJ_DEF(void) pj_pool_init_int(  pj_pool_t *pool, 
 
168
                                const char *name,
 
169
                                pj_size_t increment_size,
 
170
                                pj_pool_callback *callback)
 
171
{
 
172
    PJ_CHECK_STACK();
 
173
 
 
174
    pool->increment_size = increment_size;
 
175
    pool->callback = callback;
 
176
 
 
177
    if (name) {
 
178
        if (strchr(name, '%') != NULL) {
 
179
            pj_ansi_snprintf(pool->obj_name, sizeof(pool->obj_name), 
 
180
                             name, pool);
 
181
        } else {
 
182
            pj_ansi_strncpy(pool->obj_name, name, PJ_MAX_OBJ_NAME);
 
183
            pool->obj_name[PJ_MAX_OBJ_NAME-1] = '\0';
 
184
        }
 
185
    } else {
 
186
        pool->obj_name[0] = '\0';
 
187
    }
 
188
}
 
189
 
 
190
/*
 
191
 * Create new memory pool.
 
192
 */
 
193
PJ_DEF(pj_pool_t*) pj_pool_create_int( pj_pool_factory *f, const char *name,
 
194
                                       pj_size_t initial_size, 
 
195
                                       pj_size_t increment_size,
 
196
                                       pj_pool_callback *callback)
 
197
{
 
198
    pj_pool_t *pool;
 
199
    pj_pool_block *block;
 
200
    pj_uint8_t *buffer;
 
201
 
 
202
    PJ_CHECK_STACK();
 
203
 
 
204
    /* Size must be at least sizeof(pj_pool)+sizeof(pj_pool_block) */
 
205
    PJ_ASSERT_RETURN(initial_size >= sizeof(pj_pool_t)+sizeof(pj_pool_block),
 
206
                     NULL);
 
207
 
 
208
    /* If callback is NULL, set calback from the policy */
 
209
    if (callback == NULL)
 
210
        callback = f->policy.callback;
 
211
 
 
212
    /* Allocate initial block */
 
213
    buffer = (pj_uint8_t*) (*f->policy.block_alloc)(f, initial_size);
 
214
    if (!buffer)
 
215
        return NULL;
 
216
 
 
217
    /* Set pool administrative data. */
 
218
    pool = (pj_pool_t*)buffer;
 
219
    pj_bzero(pool, sizeof(*pool));
 
220
 
 
221
    pj_list_init(&pool->block_list);
 
222
    pool->factory = f;
 
223
 
 
224
    /* Create the first block from the memory. */
 
225
    block = (pj_pool_block*) (buffer + sizeof(*pool));
 
226
    block->cur = block->buf = ((unsigned char*)block) + sizeof(pj_pool_block);
 
227
    block->end = buffer + initial_size;
 
228
    pj_list_insert_after(&pool->block_list, block);
 
229
 
 
230
    pj_pool_init_int(pool, name, increment_size, callback);
 
231
 
 
232
    /* Pool initial capacity and used size */
 
233
    pool->capacity = initial_size;
 
234
 
 
235
    LOG((pool->obj_name, "pool created, size=%u", pool->capacity));
 
236
    return pool;
 
237
}
 
238
 
 
239
/*
 
240
 * Reset the pool to the state when it was created.
 
241
 * All blocks will be deallocated except the first block. All memory areas
 
242
 * are marked as free.
 
243
 */
 
244
static void reset_pool(pj_pool_t *pool)
 
245
{
 
246
    pj_pool_block *block;
 
247
 
 
248
    PJ_CHECK_STACK();
 
249
 
 
250
    block = pool->block_list.prev;
 
251
    if (block == &pool->block_list)
 
252
        return;
 
253
 
 
254
    /* Skip the first block because it is occupying the same memory
 
255
       as the pool itself.
 
256
    */
 
257
    block = block->prev;
 
258
    
 
259
    while (block != &pool->block_list) {
 
260
        pj_pool_block *prev = block->prev;
 
261
        pj_list_erase(block);
 
262
        (*pool->factory->policy.block_free)(pool->factory, block, 
 
263
                                            block->end - (unsigned char*)block);
 
264
        block = prev;
 
265
    }
 
266
 
 
267
    block = pool->block_list.next;
 
268
    block->cur = block->buf;
 
269
    pool->capacity = block->end - (unsigned char*)pool;
 
270
}
 
271
 
 
272
/*
 
273
 * The public function to reset pool.
 
274
 */
 
275
PJ_DEF(void) pj_pool_reset(pj_pool_t *pool)
 
276
{
 
277
    LOG((pool->obj_name, "reset(): cap=%d, used=%d(%d%%)", 
 
278
        pool->capacity, pj_pool_get_used_size(pool), 
 
279
        pj_pool_get_used_size(pool)*100/pool->capacity));
 
280
 
 
281
    reset_pool(pool);
 
282
}
 
283
 
 
284
/*
 
285
 * Destroy the pool.
 
286
 */
 
287
PJ_DEF(void) pj_pool_destroy_int(pj_pool_t *pool)
 
288
{
 
289
    pj_size_t initial_size;
 
290
 
 
291
    LOG((pool->obj_name, "destroy(): cap=%d, used=%d(%d%%), block0=%p-%p", 
 
292
        pool->capacity, pj_pool_get_used_size(pool), 
 
293
        pj_pool_get_used_size(pool)*100/pool->capacity,
 
294
        ((pj_pool_block*)pool->block_list.next)->buf, 
 
295
        ((pj_pool_block*)pool->block_list.next)->end));
 
296
 
 
297
    reset_pool(pool);
 
298
    initial_size = ((pj_pool_block*)pool->block_list.next)->end - 
 
299
                   (unsigned char*)pool;
 
300
    if (pool->factory->policy.block_free)
 
301
        (*pool->factory->policy.block_free)(pool->factory, pool, initial_size);
 
302
}
 
303
 
 
304
 
 
305
#endif  /* PJ_HAS_POOL_ALT_API */
 
306