blob: 1aed730a680ce0c52600cd73296165227607fa62 [file] [log] [blame]
Benny Prijono9033e312005-11-21 02:08:39 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pj/pool.h>
20#include <pj/log.h>
21#include <pj/string.h>
22#include <pj/assert.h>
23#include <pj/os.h>
24
Benny Prijono8508aa02006-03-30 15:56:01 +000025#if !PJ_HAS_POOL_ALT_API
26
Benny Prijono9033e312005-11-21 02:08:39 +000027static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
28 const char *name,
29 pj_size_t initial_size,
30 pj_size_t increment_sz,
31 pj_pool_callback *callback);
32static void cpool_release_pool(pj_pool_factory *pf, pj_pool_t *pool);
33static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail );
34
35static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] =
36{
37 256, 512, 1024, 2048, 4096, 8192, 12288, 16384,
38 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
39};
40
41
42PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp,
43 const pj_pool_factory_policy *policy,
44 pj_size_t max_capacity)
45{
46 int i;
47
48 PJ_CHECK_STACK();
49
Benny Prijonoac623b32006-07-03 15:19:31 +000050 pj_bzero(cp, sizeof(*cp));
Benny Prijono9033e312005-11-21 02:08:39 +000051
52 cp->max_capacity = max_capacity;
53 pj_list_init(&cp->used_list);
54 for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
55 pj_list_init(&cp->free_list[i]);
56
57 pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
58 cp->factory.create_pool = &cpool_create_pool;
59 cp->factory.release_pool = &cpool_release_pool;
60 cp->factory.dump_status = &cpool_dump_status;
Benny Prijonoc8322f32006-02-26 21:18:42 +000061
Benny Prijonoe67d99a2006-03-20 12:39:24 +000062 cp->pool = pj_pool_create_int(&cp->factory, "cachingpool", 256,
Benny Prijonoc8322f32006-02-26 21:18:42 +000063 0, NULL);
64 i = pj_mutex_create_simple(cp->pool, "cachingpool", &cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +000065}
66
67PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
68{
69 int i;
70 pj_pool_t *pool;
71
72 PJ_CHECK_STACK();
73
74 /* Delete all pool in free list */
75 for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
76 pj_pool_t *pool = cp->free_list[i].next;
77 pj_pool_t *next;
78 for (; pool != (void*)&cp->free_list[i]; pool = next) {
79 next = pool->next;
80 pj_list_erase(pool);
81 pj_pool_destroy_int(pool);
82 }
83 }
84
85 /* Delete all pools in used list */
86 pool = cp->used_list.next;
87 while (pool != (pj_pool_t*) &cp->used_list) {
88 pj_pool_t *next = pool->next;
89 pj_list_erase(pool);
90 pj_pool_destroy_int(pool);
91 pool = next;
92 }
Benny Prijonoc8322f32006-02-26 21:18:42 +000093
94 pj_mutex_destroy(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +000095}
96
97static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
98 const char *name,
99 pj_size_t initial_size,
100 pj_size_t increment_sz,
101 pj_pool_callback *callback)
102{
103 pj_caching_pool *cp = (pj_caching_pool*)pf;
104 pj_pool_t *pool;
105 int idx;
106
107 PJ_CHECK_STACK();
108
Benny Prijonoc8322f32006-02-26 21:18:42 +0000109 pj_mutex_lock(cp->mutex);
110
Benny Prijono9033e312005-11-21 02:08:39 +0000111 /* Use pool factory's policy when callback is NULL */
112 if (callback == NULL) {
113 callback = pf->policy.callback;
114 }
115
116 /* Search the suitable size for the pool.
117 * We'll just do linear search to the size array, as the array size itself
118 * is only a few elements. Binary search I suspect will be less efficient
119 * for this purpose.
120 */
121 for (idx=0;
122 idx < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[idx] < initial_size;
123 ++idx)
124 ;
125
126 /* Check whether there's a pool in the list. */
127 if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
128 /* No pool is available. */
129 /* Set minimum size. */
130 if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
131 initial_size = pool_sizes[idx];
132
133 /* Create new pool */
134 pool = pj_pool_create_int(&cp->factory, name, initial_size,
135 increment_sz, callback);
Benny Prijonoc8322f32006-02-26 21:18:42 +0000136 if (!pool) {
137 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000138 return NULL;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000139 }
Benny Prijono9033e312005-11-21 02:08:39 +0000140
141 } else {
142 /* Get one pool from the list. */
143 pool = cp->free_list[idx].next;
144 pj_list_erase(pool);
145
146 /* Initialize the pool. */
147 pj_pool_init_int(pool, name, increment_sz, callback);
148
149 /* Update pool manager's free capacity. */
150 cp->capacity -= pj_pool_get_capacity(pool);
151
Benny Prijonoc81dfef2006-01-07 18:41:22 +0000152 PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000153 }
154
155 /* Put in used list. */
156 pj_list_insert_before( &cp->used_list, pool );
157
158 /* Increment used count. */
159 ++cp->used_count;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000160
161 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000162 return pool;
163}
164
165static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
166{
167 pj_caching_pool *cp = (pj_caching_pool*)pf;
Benny Prijono8508aa02006-03-30 15:56:01 +0000168 unsigned pool_capacity;
Benny Prijono9033e312005-11-21 02:08:39 +0000169 int i;
170
171 PJ_CHECK_STACK();
172
Benny Prijonoc8322f32006-02-26 21:18:42 +0000173 pj_mutex_lock(cp->mutex);
174
Benny Prijono9033e312005-11-21 02:08:39 +0000175 /* Erase from the used list. */
176 pj_list_erase(pool);
177
178 /* Decrement used count. */
179 --cp->used_count;
180
Benny Prijono8508aa02006-03-30 15:56:01 +0000181 pool_capacity = pj_pool_get_capacity(pool);
182
Benny Prijono9033e312005-11-21 02:08:39 +0000183 /* Destroy the pool if the size is greater than our size or if the total
184 * capacity in our recycle list (plus the size of the pool) exceeds
185 * maximum capacity.
186 . */
Benny Prijono8508aa02006-03-30 15:56:01 +0000187 if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
188 cp->capacity + pool_capacity > cp->max_capacity)
Benny Prijono9033e312005-11-21 02:08:39 +0000189 {
190 pj_pool_destroy_int(pool);
Benny Prijonoc8322f32006-02-26 21:18:42 +0000191 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000192 return;
193 }
194
195 /* Reset pool. */
Benny Prijonoc81dfef2006-01-07 18:41:22 +0000196 PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)",
Benny Prijono8508aa02006-03-30 15:56:01 +0000197 pool_capacity, pj_pool_get_used_size(pool),
198 pj_pool_get_used_size(pool)*100/pool_capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000199 pj_pool_reset(pool);
200
Benny Prijono1479b652006-07-03 14:18:17 +0000201 pool_capacity = pj_pool_get_capacity(pool);
202
Benny Prijono9033e312005-11-21 02:08:39 +0000203 /*
204 * Otherwise put the pool in our recycle list.
205 */
Benny Prijono8508aa02006-03-30 15:56:01 +0000206 for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE && pool_sizes[i] != pool_capacity; ++i)
Benny Prijono9033e312005-11-21 02:08:39 +0000207 ;
208
209 pj_assert( i != PJ_CACHING_POOL_ARRAY_SIZE );
210 if (i == PJ_CACHING_POOL_ARRAY_SIZE) {
211 /* Something has gone wrong with the pool. */
212 pj_pool_destroy_int(pool);
Benny Prijonoc8322f32006-02-26 21:18:42 +0000213 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000214 return;
215 }
216
217 pj_list_insert_after(&cp->free_list[i], pool);
Benny Prijono8508aa02006-03-30 15:56:01 +0000218 cp->capacity += pool_capacity;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000219
220 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000221}
222
223static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
224{
225#if PJ_LOG_MAX_LEVEL >= 3
226 pj_caching_pool *cp = (pj_caching_pool*)factory;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000227
228 pj_mutex_lock(cp->mutex);
229
Benny Prijono9033e312005-11-21 02:08:39 +0000230 PJ_LOG(3,("cachpool", " Dumping caching pool:"));
231 PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \
232 cp->capacity, cp->max_capacity, cp->used_count));
233 if (detail) {
234 pj_pool_t *pool = cp->used_list.next;
235 pj_uint32_t total_used = 0, total_capacity = 0;
236 PJ_LOG(3,("cachpool", " Dumping all active pools:"));
237 while (pool != (void*)&cp->used_list) {
Benny Prijono8508aa02006-03-30 15:56:01 +0000238 unsigned pool_capacity = pj_pool_get_capacity(pool);
239 PJ_LOG(3,("cachpool", " %12s: %8d of %8d (%d%%) used",
240 pj_pool_getobjname(pool),
241 pj_pool_get_used_size(pool),
242 pool_capacity,
243 pj_pool_get_used_size(pool)*100/pool_capacity));
Benny Prijonod4934802005-11-21 16:58:03 +0000244 total_used += pj_pool_get_used_size(pool);
Benny Prijono8508aa02006-03-30 15:56:01 +0000245 total_capacity += pool_capacity;
Benny Prijono9033e312005-11-21 02:08:39 +0000246 pool = pool->next;
247 }
248 PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!",
249 total_used, total_capacity,
250 total_used * 100 / total_capacity));
251 }
Benny Prijonoc8322f32006-02-26 21:18:42 +0000252
253 pj_mutex_unlock(cp->mutex);
Benny Prijonoaf12bfc2005-11-23 11:23:12 +0000254#else
255 PJ_UNUSED_ARG(factory);
256 PJ_UNUSED_ARG(detail);
Benny Prijono9033e312005-11-21 02:08:39 +0000257#endif
258}
Benny Prijono8508aa02006-03-30 15:56:01 +0000259
260#endif /* PJ_HAS_POOL_ALT_API */
261