~ubuntu-branches/ubuntu/trusty/sflphone/trusty

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.1.0/pjlib/src/pj/pool_caching.c

  • Committer: Package Import Robot
  • Author(s): Mark Purcell
  • Date: 2014-01-28 18:23:36 UTC
  • mfrom: (4.3.4 sid)
  • Revision ID: package-import@ubuntu.com-20140128182336-jrsv0k9u6cawc068
Tags: 1.3.0-1
* New upstream release 
  - Fixes "New Upstream Release" (Closes: #735846)
  - Fixes "Ringtone does not stop" (Closes: #727164)
  - Fixes "[sflphone-kde] crash on startup" (Closes: #718178)
  - Fixes "sflphone GUI crashes when call is hung up" (Closes: #736583)
* Build-Depends: ensure GnuTLS 2.6
  - libucommon-dev (>= 6.0.7-1.1), libccrtp-dev (>= 2.0.6-3)
  - Fixes "FTBFS Build-Depends libgnutls{26,28}-dev" (Closes: #722040)
* Fix "boost 1.49 is going away" unversioned Build-Depends: (Closes: #736746)
* Add Build-Depends: libsndfile-dev, nepomuk-core-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id: pool_caching.c 4298 2012-11-22 05:00:01Z nanang $ */
 
2
/* 
 
3
 * Copyright (C) 2008-2011 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
#include <pj/pool.h>
 
21
#include <pj/log.h>
 
22
#include <pj/string.h>
 
23
#include <pj/assert.h>
 
24
#include <pj/lock.h>
 
25
#include <pj/os.h>
 
26
#include <pj/pool_buf.h>
 
27
 
 
28
#if !PJ_HAS_POOL_ALT_API
 
29
 
 
30
static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
 
31
                                    const char *name,
 
32
                                    pj_size_t initial_size, 
 
33
                                    pj_size_t increment_sz,
 
34
                                    pj_pool_callback *callback);
 
35
static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);
 
36
static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );
 
37
static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz);
 
38
static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz);
 
39
 
 
40
 
 
41
static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = 
 
42
{
 
43
    256, 512, 1024, 2048, 4096, 8192, 12288, 16384, 
 
44
    20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
 
45
};
 
46
 
 
47
/* Index where the search for size should begin.
 
48
 * Start with pool_sizes[5], which is 8192.
 
49
 */
 
50
#define START_SIZE  5
 
51
 
 
52
 
 
53
PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, 
 
54
                                   const pj_pool_factory_policy *policy,
 
55
                                   pj_size_t max_capacity)
 
56
{
 
57
    int i;
 
58
    pj_pool_t *pool;
 
59
 
 
60
    PJ_CHECK_STACK();
 
61
 
 
62
    pj_bzero(cp, sizeof(*cp));
 
63
    
 
64
    cp->max_capacity = max_capacity;
 
65
    pj_list_init(&cp->used_list);
 
66
    for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
 
67
        pj_list_init(&cp->free_list[i]);
 
68
 
 
69
    if (policy == NULL) {
 
70
        policy = &pj_pool_factory_default_policy;
 
71
    }
 
72
    
 
73
    pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
 
74
    cp->factory.create_pool = &cpool_create_pool;
 
75
    cp->factory.release_pool = &cpool_release_pool;
 
76
    cp->factory.dump_status = &cpool_dump_status;
 
77
    cp->factory.on_block_alloc = &cpool_on_block_alloc;
 
78
    cp->factory.on_block_free = &cpool_on_block_free;
 
79
 
 
80
    pool = pj_pool_create_on_buf("cachingpool", cp->pool_buf, sizeof(cp->pool_buf));
 
81
    pj_lock_create_simple_mutex(pool, "cachingpool", &cp->lock);
 
82
}
 
83
 
 
84
PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
 
85
{
 
86
    int i;
 
87
    pj_pool_t *pool;
 
88
 
 
89
    PJ_CHECK_STACK();
 
90
 
 
91
    /* Delete all pool in free list */
 
92
    for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
 
93
        pj_pool_t *pool = (pj_pool_t*) cp->free_list[i].next;
 
94
        pj_pool_t *next;
 
95
        for (; pool != (void*)&cp->free_list[i]; pool = next) {
 
96
            next = pool->next;
 
97
            pj_list_erase(pool);
 
98
            pj_pool_destroy_int(pool);
 
99
        }
 
100
    }
 
101
 
 
102
    /* Delete all pools in used list */
 
103
    pool = (pj_pool_t*) cp->used_list.next;
 
104
    while (pool != (pj_pool_t*) &cp->used_list) {
 
105
        pj_pool_t *next = pool->next;
 
106
        pj_list_erase(pool);
 
107
        PJ_LOG(4,(pool->obj_name, 
 
108
                  "Pool is not released by application, releasing now"));
 
109
        pj_pool_destroy_int(pool);
 
110
        pool = next;
 
111
    }
 
112
 
 
113
    if (cp->lock) {
 
114
        pj_lock_destroy(cp->lock);
 
115
        pj_lock_create_null_mutex(NULL, "cachingpool", &cp->lock);
 
116
    }
 
117
}
 
118
 
 
119
static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, 
 
120
                                              const char *name, 
 
121
                                              pj_size_t initial_size, 
 
122
                                              pj_size_t increment_sz, 
 
123
                                              pj_pool_callback *callback)
 
124
{
 
125
    pj_caching_pool *cp = (pj_caching_pool*)pf;
 
126
    pj_pool_t *pool;
 
127
    int idx;
 
128
 
 
129
    PJ_CHECK_STACK();
 
130
 
 
131
    pj_lock_acquire(cp->lock);
 
132
 
 
133
    /* Use pool factory's policy when callback is NULL */
 
134
    if (callback == NULL) {
 
135
        callback = pf->policy.callback;
 
136
    }
 
137
 
 
138
    /* Search the suitable size for the pool. 
 
139
     * We'll just do linear search to the size array, as the array size itself
 
140
     * is only a few elements. Binary search I suspect will be less efficient
 
141
     * for this purpose.
 
142
     */
 
143
    if (initial_size <= pool_sizes[START_SIZE]) {
 
144
        for (idx=START_SIZE-1; 
 
145
             idx >= 0 && pool_sizes[idx] >= initial_size;
 
146
             --idx)
 
147
            ;
 
148
        ++idx;
 
149
    } else {
 
150
        for (idx=START_SIZE+1; 
 
151
             idx < PJ_CACHING_POOL_ARRAY_SIZE && 
 
152
                  pool_sizes[idx] < initial_size;
 
153
             ++idx)
 
154
            ;
 
155
    }
 
156
 
 
157
    /* Check whether there's a pool in the list. */
 
158
    if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
 
159
        /* No pool is available. */
 
160
        /* Set minimum size. */
 
161
        if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
 
162
            initial_size =  pool_sizes[idx];
 
163
 
 
164
        /* Create new pool */
 
165
        pool = pj_pool_create_int(&cp->factory, name, initial_size, 
 
166
                                  increment_sz, callback);
 
167
        if (!pool) {
 
168
            pj_lock_release(cp->lock);
 
169
            return NULL;
 
170
        }
 
171
 
 
172
    } else {
 
173
        /* Get one pool from the list. */
 
174
        pool = (pj_pool_t*) cp->free_list[idx].next;
 
175
        pj_list_erase(pool);
 
176
 
 
177
        /* Initialize the pool. */
 
178
        pj_pool_init_int(pool, name, increment_sz, callback);
 
179
 
 
180
        /* Update pool manager's free capacity. */
 
181
        if (cp->capacity > pj_pool_get_capacity(pool)) {
 
182
            cp->capacity -= pj_pool_get_capacity(pool);
 
183
        } else {
 
184
            cp->capacity = 0;
 
185
        }
 
186
 
 
187
        PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
 
188
    }
 
189
 
 
190
    /* Put in used list. */
 
191
    pj_list_insert_before( &cp->used_list, pool );
 
192
 
 
193
    /* Mark factory data */
 
194
    pool->factory_data = (void*) (long) idx;
 
195
 
 
196
    /* Increment used count. */
 
197
    ++cp->used_count;
 
198
 
 
199
    pj_lock_release(cp->lock);
 
200
    return pool;
 
201
}
 
202
 
 
203
static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
 
204
{
 
205
    pj_caching_pool *cp = (pj_caching_pool*)pf;
 
206
    pj_size_t pool_capacity;
 
207
    unsigned i;
 
208
 
 
209
    PJ_CHECK_STACK();
 
210
 
 
211
    PJ_ASSERT_ON_FAIL(pf && pool, return);
 
212
 
 
213
    pj_lock_acquire(cp->lock);
 
214
 
 
215
#if PJ_SAFE_POOL
 
216
    /* Make sure pool is still in our used list */
 
217
    if (pj_list_find_node(&cp->used_list, pool) != pool) {
 
218
        pj_assert(!"Attempt to destroy pool that has been destroyed before");
 
219
        return;
 
220
    }
 
221
#endif
 
222
 
 
223
    /* Erase from the used list. */
 
224
    pj_list_erase(pool);
 
225
 
 
226
    /* Decrement used count. */
 
227
    --cp->used_count;
 
228
 
 
229
    pool_capacity = pj_pool_get_capacity(pool);
 
230
 
 
231
    /* Destroy the pool if the size is greater than our size or if the total
 
232
     * capacity in our recycle list (plus the size of the pool) exceeds 
 
233
     * maximum capacity.
 
234
   . */
 
235
    if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
 
236
        cp->capacity + pool_capacity > cp->max_capacity)
 
237
    {
 
238
        pj_pool_destroy_int(pool);
 
239
        pj_lock_release(cp->lock);
 
240
        return;
 
241
    }
 
242
 
 
243
    /* Reset pool. */
 
244
    PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", 
 
245
               pool_capacity, pj_pool_get_used_size(pool), 
 
246
               pj_pool_get_used_size(pool)*100/pool_capacity));
 
247
    pj_pool_reset(pool);
 
248
 
 
249
    pool_capacity = pj_pool_get_capacity(pool);
 
250
 
 
251
    /*
 
252
     * Otherwise put the pool in our recycle list.
 
253
     */
 
254
    i = (unsigned) (unsigned long) pool->factory_data;
 
255
 
 
256
    pj_assert(i<PJ_CACHING_POOL_ARRAY_SIZE);
 
257
    if (i >= PJ_CACHING_POOL_ARRAY_SIZE ) {
 
258
        /* Something has gone wrong with the pool. */
 
259
        pj_pool_destroy_int(pool);
 
260
        pj_lock_release(cp->lock);
 
261
        return;
 
262
    }
 
263
 
 
264
    pj_list_insert_after(&cp->free_list[i], pool);
 
265
    cp->capacity += pool_capacity;
 
266
 
 
267
    pj_lock_release(cp->lock);
 
268
}
 
269
 
 
270
static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
 
271
{
 
272
#if PJ_LOG_MAX_LEVEL >= 3
 
273
    pj_caching_pool *cp = (pj_caching_pool*)factory;
 
274
 
 
275
    pj_lock_acquire(cp->lock);
 
276
 
 
277
    PJ_LOG(3,("cachpool", " Dumping caching pool:"));
 
278
    PJ_LOG(3,("cachpool", "   Capacity=%u, max_capacity=%u, used_cnt=%u", \
 
279
                             cp->capacity, cp->max_capacity, cp->used_count));
 
280
    if (detail) {
 
281
        pj_pool_t *pool = (pj_pool_t*) cp->used_list.next;
 
282
        pj_uint32_t total_used = 0, total_capacity = 0;
 
283
        PJ_LOG(3,("cachpool", "  Dumping all active pools:"));
 
284
        while (pool != (void*)&cp->used_list) {
 
285
            unsigned pool_capacity = pj_pool_get_capacity(pool);
 
286
            PJ_LOG(3,("cachpool", "   %16s: %8d of %8d (%d%%) used", 
 
287
                                  pj_pool_getobjname(pool), 
 
288
                                  pj_pool_get_used_size(pool), 
 
289
                                  pool_capacity,
 
290
                                  pj_pool_get_used_size(pool)*100/pool_capacity));
 
291
            total_used += pj_pool_get_used_size(pool);
 
292
            total_capacity += pool_capacity;
 
293
            pool = pool->next;
 
294
        }
 
295
        if (total_capacity) {
 
296
            PJ_LOG(3,("cachpool", "  Total %9d of %9d (%d %%) used!",
 
297
                                  total_used, total_capacity,
 
298
                                  total_used * 100 / total_capacity));
 
299
        }
 
300
    }
 
301
 
 
302
    pj_lock_release(cp->lock);
 
303
#else
 
304
    PJ_UNUSED_ARG(factory);
 
305
    PJ_UNUSED_ARG(detail);
 
306
#endif
 
307
}
 
308
 
 
309
 
 
310
static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz)
 
311
{
 
312
    pj_caching_pool *cp = (pj_caching_pool*)f;
 
313
 
 
314
    //Can't lock because mutex is not recursive
 
315
    //if (cp->mutex) pj_mutex_lock(cp->mutex);
 
316
 
 
317
    cp->used_size += sz;
 
318
    if (cp->used_size > cp->peak_used_size)
 
319
        cp->peak_used_size = cp->used_size;
 
320
 
 
321
    //if (cp->mutex) pj_mutex_unlock(cp->mutex);
 
322
 
 
323
    return PJ_TRUE;
 
324
}
 
325
 
 
326
 
 
327
static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz)
 
328
{
 
329
    pj_caching_pool *cp = (pj_caching_pool*)f;
 
330
 
 
331
    //pj_mutex_lock(cp->mutex);
 
332
    cp->used_size -= sz;
 
333
    //pj_mutex_unlock(cp->mutex);
 
334
}
 
335
 
 
336
 
 
337
#endif  /* PJ_HAS_POOL_ALT_API */
 
338