From f3ab456a17af1c89a6e3be4d20c5944853df1cb0 Mon Sep 17 00:00:00 2001 From: "David M. Lee" Date: Mon, 7 Jan 2013 14:24:28 -0600 Subject: Import pjproject-2.0.1 --- pjlib/src/pj/pool_caching.c | 334 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 334 insertions(+) create mode 100644 pjlib/src/pj/pool_caching.c (limited to 'pjlib/src/pj/pool_caching.c') diff --git a/pjlib/src/pj/pool_caching.c b/pjlib/src/pj/pool_caching.c new file mode 100644 index 0000000..a15c3d9 --- /dev/null +++ b/pjlib/src/pj/pool_caching.c @@ -0,0 +1,334 @@ +/* $Id: pool_caching.c 3553 2011-05-05 06:14:19Z nanang $ */ +/* + * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com) + * Copyright (C) 2003-2008 Benny Prijono + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include + +#if !PJ_HAS_POOL_ALT_API + +static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, + const char *name, + pj_size_t initial_size, + pj_size_t increment_sz, + pj_pool_callback *callback); +static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool); +static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ); +static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz); +static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz); + + +static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] = +{ + 256, 512, 1024, 2048, 4096, 8192, 12288, 16384, + 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536 +}; + +/* Index where the search for size should begin. + * Start with pool_sizes[5], which is 8192. + */ +#define START_SIZE 5 + + +PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp, + const pj_pool_factory_policy *policy, + pj_size_t max_capacity) +{ + int i; + pj_pool_t *pool; + + PJ_CHECK_STACK(); + + pj_bzero(cp, sizeof(*cp)); + + cp->max_capacity = max_capacity; + pj_list_init(&cp->used_list); + for (i=0; ifree_list[i]); + + if (policy == NULL) { + policy = &pj_pool_factory_default_policy; + } + + pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy)); + cp->factory.create_pool = &cpool_create_pool; + cp->factory.release_pool = &cpool_release_pool; + cp->factory.dump_status = &cpool_dump_status; + cp->factory.on_block_alloc = &cpool_on_block_alloc; + cp->factory.on_block_free = &cpool_on_block_free; + + pool = pj_pool_create_on_buf("cachingpool", cp->pool_buf, sizeof(cp->pool_buf)); + pj_lock_create_simple_mutex(pool, "cachingpool", &cp->lock); +} + +PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp ) +{ + int i; + pj_pool_t *pool; + + PJ_CHECK_STACK(); + + /* Delete all pool in free list */ + for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) { + pj_pool_t *pool = (pj_pool_t*) cp->free_list[i].next; + pj_pool_t *next; + for (; pool != (void*)&cp->free_list[i]; pool = next) { + next = pool->next; + pj_list_erase(pool); + pj_pool_destroy_int(pool); + } + } + + /* Delete all pools in used list */ + pool = (pj_pool_t*) cp->used_list.next; + while (pool != (pj_pool_t*) &cp->used_list) { + pj_pool_t *next = pool->next; + pj_list_erase(pool); + PJ_LOG(4,(pool->obj_name, + "Pool is not released by application, releasing now")); + pj_pool_destroy_int(pool); + pool = next; + } + + if (cp->lock) { + pj_lock_destroy(cp->lock); + pj_lock_create_null_mutex(NULL, "cachingpool", &cp->lock); + } +} + +static pj_pool_t* cpool_create_pool(pj_pool_factory *pf, + const char *name, + pj_size_t initial_size, + pj_size_t increment_sz, + pj_pool_callback *callback) +{ + pj_caching_pool *cp = (pj_caching_pool*)pf; + pj_pool_t *pool; + int idx; + + PJ_CHECK_STACK(); + + pj_lock_acquire(cp->lock); + + /* Use pool factory's policy when callback is NULL */ + if (callback == NULL) { + callback = pf->policy.callback; + } + + /* Search the suitable size for the pool. + * We'll just do linear search to the size array, as the array size itself + * is only a few elements. Binary search I suspect will be less efficient + * for this purpose. + */ + if (initial_size <= pool_sizes[START_SIZE]) { + for (idx=START_SIZE-1; + idx >= 0 && pool_sizes[idx] >= initial_size; + --idx) + ; + ++idx; + } else { + for (idx=START_SIZE+1; + idx < PJ_CACHING_POOL_ARRAY_SIZE && + pool_sizes[idx] < initial_size; + ++idx) + ; + } + + /* Check whether there's a pool in the list. */ + if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) { + /* No pool is available. */ + /* Set minimum size. */ + if (idx < PJ_CACHING_POOL_ARRAY_SIZE) + initial_size = pool_sizes[idx]; + + /* Create new pool */ + pool = pj_pool_create_int(&cp->factory, name, initial_size, + increment_sz, callback); + if (!pool) { + pj_lock_release(cp->lock); + return NULL; + } + + } else { + /* Get one pool from the list. */ + pool = (pj_pool_t*) cp->free_list[idx].next; + pj_list_erase(pool); + + /* Initialize the pool. */ + pj_pool_init_int(pool, name, increment_sz, callback); + + /* Update pool manager's free capacity. */ + cp->capacity -= pj_pool_get_capacity(pool); + + PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity)); + } + + /* Put in used list. */ + pj_list_insert_before( &cp->used_list, pool ); + + /* Mark factory data */ + pool->factory_data = (void*) (long) idx; + + /* Increment used count. */ + ++cp->used_count; + + pj_lock_release(cp->lock); + return pool; +} + +static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool) +{ + pj_caching_pool *cp = (pj_caching_pool*)pf; + unsigned pool_capacity; + unsigned i; + + PJ_CHECK_STACK(); + + PJ_ASSERT_ON_FAIL(pf && pool, return); + + pj_lock_acquire(cp->lock); + +#if PJ_SAFE_POOL + /* Make sure pool is still in our used list */ + if (pj_list_find_node(&cp->used_list, pool) != pool) { + pj_assert(!"Attempt to destroy pool that has been destroyed before"); + return; + } +#endif + + /* Erase from the used list. */ + pj_list_erase(pool); + + /* Decrement used count. */ + --cp->used_count; + + pool_capacity = pj_pool_get_capacity(pool); + + /* Destroy the pool if the size is greater than our size or if the total + * capacity in our recycle list (plus the size of the pool) exceeds + * maximum capacity. + . */ + if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] || + cp->capacity + pool_capacity > cp->max_capacity) + { + pj_pool_destroy_int(pool); + pj_lock_release(cp->lock); + return; + } + + /* Reset pool. */ + PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)", + pool_capacity, pj_pool_get_used_size(pool), + pj_pool_get_used_size(pool)*100/pool_capacity)); + pj_pool_reset(pool); + + pool_capacity = pj_pool_get_capacity(pool); + + /* + * Otherwise put the pool in our recycle list. + */ + i = (unsigned) (unsigned long) pool->factory_data; + + pj_assert(i= PJ_CACHING_POOL_ARRAY_SIZE ) { + /* Something has gone wrong with the pool. */ + pj_pool_destroy_int(pool); + pj_lock_release(cp->lock); + return; + } + + pj_list_insert_after(&cp->free_list[i], pool); + cp->capacity += pool_capacity; + + pj_lock_release(cp->lock); +} + +static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail ) +{ +#if PJ_LOG_MAX_LEVEL >= 3 + pj_caching_pool *cp = (pj_caching_pool*)factory; + + pj_lock_acquire(cp->lock); + + PJ_LOG(3,("cachpool", " Dumping caching pool:")); + PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \ + cp->capacity, cp->max_capacity, cp->used_count)); + if (detail) { + pj_pool_t *pool = (pj_pool_t*) cp->used_list.next; + pj_uint32_t total_used = 0, total_capacity = 0; + PJ_LOG(3,("cachpool", " Dumping all active pools:")); + while (pool != (void*)&cp->used_list) { + unsigned pool_capacity = pj_pool_get_capacity(pool); + PJ_LOG(3,("cachpool", " %16s: %8d of %8d (%d%%) used", + pj_pool_getobjname(pool), + pj_pool_get_used_size(pool), + pool_capacity, + pj_pool_get_used_size(pool)*100/pool_capacity)); + total_used += pj_pool_get_used_size(pool); + total_capacity += pool_capacity; + pool = pool->next; + } + if (total_capacity) { + PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!", + total_used, total_capacity, + total_used * 100 / total_capacity)); + } + } + + pj_lock_release(cp->lock); +#else + PJ_UNUSED_ARG(factory); + PJ_UNUSED_ARG(detail); +#endif +} + + +static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz) +{ + pj_caching_pool *cp = (pj_caching_pool*)f; + + //Can't lock because mutex is not recursive + //if (cp->mutex) pj_mutex_lock(cp->mutex); + + cp->used_size += sz; + if (cp->used_size > cp->peak_used_size) + cp->peak_used_size = cp->used_size; + + //if (cp->mutex) pj_mutex_unlock(cp->mutex); + + return PJ_TRUE; +} + + +static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz) +{ + pj_caching_pool *cp = (pj_caching_pool*)f; + + //pj_mutex_lock(cp->mutex); + cp->used_size -= sz; + //pj_mutex_unlock(cp->mutex); +} + + +#endif /* PJ_HAS_POOL_ALT_API */ + -- cgit v1.2.3