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

« back to all changes in this revision

Viewing changes to daemon/libs/pjproject-2.0.1/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 3553 2011-05-05 06:14:19Z 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
 
        cp->capacity -= pj_pool_get_capacity(pool);
182
 
 
183
 
        PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
184
 
    }
185
 
 
186
 
    /* Put in used list. */
187
 
    pj_list_insert_before( &cp->used_list, pool );
188
 
 
189
 
    /* Mark factory data */
190
 
    pool->factory_data = (void*) (long) idx;
191
 
 
192
 
    /* Increment used count. */
193
 
    ++cp->used_count;
194
 
 
195
 
    pj_lock_release(cp->lock);
196
 
    return pool;
197
 
}
198
 
 
199
 
static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
200
 
{
201
 
    pj_caching_pool *cp = (pj_caching_pool*)pf;
202
 
    unsigned pool_capacity;
203
 
    unsigned i;
204
 
 
205
 
    PJ_CHECK_STACK();
206
 
 
207
 
    PJ_ASSERT_ON_FAIL(pf && pool, return);
208
 
 
209
 
    pj_lock_acquire(cp->lock);
210
 
 
211
 
#if PJ_SAFE_POOL
212
 
    /* Make sure pool is still in our used list */
213
 
    if (pj_list_find_node(&cp->used_list, pool) != pool) {
214
 
        pj_assert(!"Attempt to destroy pool that has been destroyed before");
215
 
        return;
216
 
    }
217
 
#endif
218
 
 
219
 
    /* Erase from the used list. */
220
 
    pj_list_erase(pool);
221
 
 
222
 
    /* Decrement used count. */
223
 
    --cp->used_count;
224
 
 
225
 
    pool_capacity = pj_pool_get_capacity(pool);
226
 
 
227
 
    /* Destroy the pool if the size is greater than our size or if the total
228
 
     * capacity in our recycle list (plus the size of the pool) exceeds
229
 
     * maximum capacity.
230
 
   . */
231
 
    if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
232
 
        cp->capacity + pool_capacity > cp->max_capacity)
233
 
    {
234
 
        pj_pool_destroy_int(pool);
235
 
        pj_lock_release(cp->lock);
236
 
        return;
237
 
    }
238
 
 
239
 
    /* Reset pool. */
240
 
    PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)",
241
 
               pool_capacity, pj_pool_get_used_size(pool),
242
 
               pj_pool_get_used_size(pool)*100/pool_capacity));
243
 
    pj_pool_reset(pool);
244
 
 
245
 
    pool_capacity = pj_pool_get_capacity(pool);
246
 
 
247
 
    /*
248
 
     * Otherwise put the pool in our recycle list.
249
 
     */
250
 
    i = (unsigned) (unsigned long) pool->factory_data;
251
 
 
252
 
    pj_assert(i<PJ_CACHING_POOL_ARRAY_SIZE);
253
 
    if (i >= PJ_CACHING_POOL_ARRAY_SIZE ) {
254
 
        /* Something has gone wrong with the pool. */
255
 
        pj_pool_destroy_int(pool);
256
 
        pj_lock_release(cp->lock);
257
 
        return;
258
 
    }
259
 
 
260
 
    pj_list_insert_after(&cp->free_list[i], pool);
261
 
    cp->capacity += pool_capacity;
262
 
 
263
 
    pj_lock_release(cp->lock);
264
 
}
265
 
 
266
 
static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
267
 
{
268
 
#if PJ_LOG_MAX_LEVEL >= 3
269
 
    pj_caching_pool *cp = (pj_caching_pool*)factory;
270
 
 
271
 
    pj_lock_acquire(cp->lock);
272
 
 
273
 
    PJ_LOG(3,("cachpool", " Dumping caching pool:"));
274
 
    PJ_LOG(3,("cachpool", "   Capacity=%u, max_capacity=%u, used_cnt=%u", \
275
 
                             cp->capacity, cp->max_capacity, cp->used_count));
276
 
    if (detail) {
277
 
        pj_pool_t *pool = (pj_pool_t*) cp->used_list.next;
278
 
        pj_uint32_t total_used = 0, total_capacity = 0;
279
 
        PJ_LOG(3,("cachpool", "  Dumping all active pools:"));
280
 
        while (pool != (void*)&cp->used_list) {
281
 
            unsigned pool_capacity = pj_pool_get_capacity(pool);
282
 
            PJ_LOG(3,("cachpool", "   %16s: %8d of %8d (%d%%) used",
283
 
                                  pj_pool_getobjname(pool),
284
 
                                  pj_pool_get_used_size(pool),
285
 
                                  pool_capacity,
286
 
                                  pj_pool_get_used_size(pool)*100/pool_capacity));
287
 
            total_used += pj_pool_get_used_size(pool);
288
 
            total_capacity += pool_capacity;
289
 
            pool = pool->next;
290
 
        }
291
 
        if (total_capacity) {
292
 
            PJ_LOG(3,("cachpool", "  Total %9d of %9d (%d %%) used!",
293
 
                                  total_used, total_capacity,
294
 
                                  total_used * 100 / total_capacity));
295
 
        }
296
 
    }
297
 
 
298
 
    pj_lock_release(cp->lock);
299
 
#else
300
 
    PJ_UNUSED_ARG(factory);
301
 
    PJ_UNUSED_ARG(detail);
302
 
#endif
303
 
}
304
 
 
305
 
 
306
 
static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz)
307
 
{
308
 
    pj_caching_pool *cp = (pj_caching_pool*)f;
309
 
 
310
 
    //Can't lock because mutex is not recursive
311
 
    //if (cp->mutex) pj_mutex_lock(cp->mutex);
312
 
 
313
 
    cp->used_size += sz;
314
 
    if (cp->used_size > cp->peak_used_size)
315
 
        cp->peak_used_size = cp->used_size;
316
 
 
317
 
    //if (cp->mutex) pj_mutex_unlock(cp->mutex);
318
 
 
319
 
    return PJ_TRUE;
320
 
}
321
 
 
322
 
 
323
 
static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz)
324
 
{
325
 
    pj_caching_pool *cp = (pj_caching_pool*)f;
326
 
 
327
 
    //pj_mutex_lock(cp->mutex);
328
 
    cp->used_size -= sz;
329
 
    //pj_mutex_unlock(cp->mutex);
330
 
}
331
 
 
332
 
 
333
 
#endif  /* PJ_HAS_POOL_ALT_API */