blob: e0eecd4d1ef80c4998cf5856fdaaebd565faf61d [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 );
Benny Prijonoc6e165f2006-07-09 10:05:46 +000034static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz);
35static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz);
36
Benny Prijono9033e312005-11-21 02:08:39 +000037
38static pj_size_t pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE] =
39{
40 256, 512, 1024, 2048, 4096, 8192, 12288, 16384,
41 20480, 24576, 28672, 32768, 40960, 49152, 57344, 65536
42};
43
Benny Prijono53e3ffd2006-07-06 14:27:31 +000044/* Index where the search for size should begin.
45 * Start with pool_sizes[5], which is 8192.
46 */
47#define START_SIZE 5
48
Benny Prijono9033e312005-11-21 02:08:39 +000049
50PJ_DEF(void) pj_caching_pool_init( pj_caching_pool *cp,
51 const pj_pool_factory_policy *policy,
52 pj_size_t max_capacity)
53{
54 int i;
55
56 PJ_CHECK_STACK();
57
Benny Prijonoac623b32006-07-03 15:19:31 +000058 pj_bzero(cp, sizeof(*cp));
Benny Prijono9033e312005-11-21 02:08:39 +000059
60 cp->max_capacity = max_capacity;
61 pj_list_init(&cp->used_list);
62 for (i=0; i<PJ_CACHING_POOL_ARRAY_SIZE; ++i)
63 pj_list_init(&cp->free_list[i]);
64
65 pj_memcpy(&cp->factory.policy, policy, sizeof(pj_pool_factory_policy));
66 cp->factory.create_pool = &cpool_create_pool;
67 cp->factory.release_pool = &cpool_release_pool;
68 cp->factory.dump_status = &cpool_dump_status;
Benny Prijonoc6e165f2006-07-09 10:05:46 +000069 cp->factory.on_block_alloc = &cpool_on_block_alloc;
70 cp->factory.on_block_free = &cpool_on_block_free;
Benny Prijonoc8322f32006-02-26 21:18:42 +000071
Benny Prijonoe67d99a2006-03-20 12:39:24 +000072 cp->pool = pj_pool_create_int(&cp->factory, "cachingpool", 256,
Benny Prijonoc8322f32006-02-26 21:18:42 +000073 0, NULL);
74 i = pj_mutex_create_simple(cp->pool, "cachingpool", &cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +000075}
76
77PJ_DEF(void) pj_caching_pool_destroy( pj_caching_pool *cp )
78{
79 int i;
80 pj_pool_t *pool;
81
82 PJ_CHECK_STACK();
83
84 /* Delete all pool in free list */
85 for (i=0; i < PJ_CACHING_POOL_ARRAY_SIZE; ++i) {
86 pj_pool_t *pool = cp->free_list[i].next;
87 pj_pool_t *next;
88 for (; pool != (void*)&cp->free_list[i]; pool = next) {
89 next = pool->next;
90 pj_list_erase(pool);
91 pj_pool_destroy_int(pool);
92 }
93 }
94
95 /* Delete all pools in used list */
96 pool = cp->used_list.next;
97 while (pool != (pj_pool_t*) &cp->used_list) {
98 pj_pool_t *next = pool->next;
99 pj_list_erase(pool);
100 pj_pool_destroy_int(pool);
101 pool = next;
102 }
Benny Prijonoc8322f32006-02-26 21:18:42 +0000103
104 pj_mutex_destroy(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000105}
106
107static pj_pool_t* cpool_create_pool(pj_pool_factory *pf,
108 const char *name,
109 pj_size_t initial_size,
110 pj_size_t increment_sz,
111 pj_pool_callback *callback)
112{
113 pj_caching_pool *cp = (pj_caching_pool*)pf;
114 pj_pool_t *pool;
115 int idx;
116
117 PJ_CHECK_STACK();
118
Benny Prijonoc8322f32006-02-26 21:18:42 +0000119 pj_mutex_lock(cp->mutex);
120
Benny Prijono9033e312005-11-21 02:08:39 +0000121 /* Use pool factory's policy when callback is NULL */
122 if (callback == NULL) {
123 callback = pf->policy.callback;
124 }
125
126 /* Search the suitable size for the pool.
127 * We'll just do linear search to the size array, as the array size itself
128 * is only a few elements. Binary search I suspect will be less efficient
129 * for this purpose.
130 */
Benny Prijono53e3ffd2006-07-06 14:27:31 +0000131 if (initial_size <= pool_sizes[START_SIZE]) {
132 for (idx=START_SIZE-1;
133 idx >= 0 && pool_sizes[idx] >= initial_size;
134 --idx)
135 ;
136 ++idx;
137 } else {
138 for (idx=START_SIZE+1;
139 idx < PJ_CACHING_POOL_ARRAY_SIZE &&
140 pool_sizes[idx] < initial_size;
141 ++idx)
142 ;
143 }
Benny Prijono9033e312005-11-21 02:08:39 +0000144
145 /* Check whether there's a pool in the list. */
146 if (idx==PJ_CACHING_POOL_ARRAY_SIZE || pj_list_empty(&cp->free_list[idx])) {
147 /* No pool is available. */
148 /* Set minimum size. */
149 if (idx < PJ_CACHING_POOL_ARRAY_SIZE)
150 initial_size = pool_sizes[idx];
151
152 /* Create new pool */
153 pool = pj_pool_create_int(&cp->factory, name, initial_size,
154 increment_sz, callback);
Benny Prijonoc8322f32006-02-26 21:18:42 +0000155 if (!pool) {
156 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000157 return NULL;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000158 }
Benny Prijono9033e312005-11-21 02:08:39 +0000159
160 } else {
161 /* Get one pool from the list. */
162 pool = cp->free_list[idx].next;
163 pj_list_erase(pool);
164
165 /* Initialize the pool. */
166 pj_pool_init_int(pool, name, increment_sz, callback);
167
168 /* Update pool manager's free capacity. */
169 cp->capacity -= pj_pool_get_capacity(pool);
170
Benny Prijonoc81dfef2006-01-07 18:41:22 +0000171 PJ_LOG(6, (pool->obj_name, "pool reused, size=%u", pool->capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000172 }
173
174 /* Put in used list. */
175 pj_list_insert_before( &cp->used_list, pool );
176
Benny Prijono53e3ffd2006-07-06 14:27:31 +0000177 /* Mark factory data */
178 pool->factory_data = (void*) idx;
179
Benny Prijono9033e312005-11-21 02:08:39 +0000180 /* Increment used count. */
181 ++cp->used_count;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000182
183 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000184 return pool;
185}
186
187static void cpool_release_pool( pj_pool_factory *pf, pj_pool_t *pool)
188{
189 pj_caching_pool *cp = (pj_caching_pool*)pf;
Benny Prijono8508aa02006-03-30 15:56:01 +0000190 unsigned pool_capacity;
Benny Prijono53e3ffd2006-07-06 14:27:31 +0000191 unsigned i;
Benny Prijono9033e312005-11-21 02:08:39 +0000192
193 PJ_CHECK_STACK();
194
Benny Prijonoc8322f32006-02-26 21:18:42 +0000195 pj_mutex_lock(cp->mutex);
196
Benny Prijono9033e312005-11-21 02:08:39 +0000197 /* Erase from the used list. */
198 pj_list_erase(pool);
199
200 /* Decrement used count. */
201 --cp->used_count;
202
Benny Prijono8508aa02006-03-30 15:56:01 +0000203 pool_capacity = pj_pool_get_capacity(pool);
204
Benny Prijono9033e312005-11-21 02:08:39 +0000205 /* Destroy the pool if the size is greater than our size or if the total
206 * capacity in our recycle list (plus the size of the pool) exceeds
207 * maximum capacity.
208 . */
Benny Prijono8508aa02006-03-30 15:56:01 +0000209 if (pool_capacity > pool_sizes[PJ_CACHING_POOL_ARRAY_SIZE-1] ||
210 cp->capacity + pool_capacity > cp->max_capacity)
Benny Prijono9033e312005-11-21 02:08:39 +0000211 {
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 /* Reset pool. */
Benny Prijonoc81dfef2006-01-07 18:41:22 +0000218 PJ_LOG(6, (pool->obj_name, "recycle(): cap=%d, used=%d(%d%%)",
Benny Prijono8508aa02006-03-30 15:56:01 +0000219 pool_capacity, pj_pool_get_used_size(pool),
220 pj_pool_get_used_size(pool)*100/pool_capacity));
Benny Prijono9033e312005-11-21 02:08:39 +0000221 pj_pool_reset(pool);
222
Benny Prijono1479b652006-07-03 14:18:17 +0000223 pool_capacity = pj_pool_get_capacity(pool);
224
Benny Prijono9033e312005-11-21 02:08:39 +0000225 /*
226 * Otherwise put the pool in our recycle list.
227 */
Benny Prijono53e3ffd2006-07-06 14:27:31 +0000228 i = (unsigned)pool->factory_data;
Benny Prijono9033e312005-11-21 02:08:39 +0000229
Benny Prijono53e3ffd2006-07-06 14:27:31 +0000230 pj_assert(i<PJ_CACHING_POOL_ARRAY_SIZE);
231 if (i >= PJ_CACHING_POOL_ARRAY_SIZE ) {
Benny Prijono9033e312005-11-21 02:08:39 +0000232 /* Something has gone wrong with the pool. */
233 pj_pool_destroy_int(pool);
Benny Prijonoc8322f32006-02-26 21:18:42 +0000234 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000235 return;
236 }
237
238 pj_list_insert_after(&cp->free_list[i], pool);
Benny Prijono8508aa02006-03-30 15:56:01 +0000239 cp->capacity += pool_capacity;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000240
241 pj_mutex_unlock(cp->mutex);
Benny Prijono9033e312005-11-21 02:08:39 +0000242}
243
244static void cpool_dump_status(pj_pool_factory *factory, pj_bool_t detail )
245{
246#if PJ_LOG_MAX_LEVEL >= 3
247 pj_caching_pool *cp = (pj_caching_pool*)factory;
Benny Prijonoc8322f32006-02-26 21:18:42 +0000248
249 pj_mutex_lock(cp->mutex);
250
Benny Prijono9033e312005-11-21 02:08:39 +0000251 PJ_LOG(3,("cachpool", " Dumping caching pool:"));
252 PJ_LOG(3,("cachpool", " Capacity=%u, max_capacity=%u, used_cnt=%u", \
253 cp->capacity, cp->max_capacity, cp->used_count));
254 if (detail) {
255 pj_pool_t *pool = cp->used_list.next;
256 pj_uint32_t total_used = 0, total_capacity = 0;
257 PJ_LOG(3,("cachpool", " Dumping all active pools:"));
258 while (pool != (void*)&cp->used_list) {
Benny Prijono8508aa02006-03-30 15:56:01 +0000259 unsigned pool_capacity = pj_pool_get_capacity(pool);
260 PJ_LOG(3,("cachpool", " %12s: %8d of %8d (%d%%) used",
261 pj_pool_getobjname(pool),
262 pj_pool_get_used_size(pool),
263 pool_capacity,
264 pj_pool_get_used_size(pool)*100/pool_capacity));
Benny Prijonod4934802005-11-21 16:58:03 +0000265 total_used += pj_pool_get_used_size(pool);
Benny Prijono8508aa02006-03-30 15:56:01 +0000266 total_capacity += pool_capacity;
Benny Prijono9033e312005-11-21 02:08:39 +0000267 pool = pool->next;
268 }
269 PJ_LOG(3,("cachpool", " Total %9d of %9d (%d %%) used!",
270 total_used, total_capacity,
271 total_used * 100 / total_capacity));
272 }
Benny Prijonoc8322f32006-02-26 21:18:42 +0000273
274 pj_mutex_unlock(cp->mutex);
Benny Prijonoaf12bfc2005-11-23 11:23:12 +0000275#else
276 PJ_UNUSED_ARG(factory);
277 PJ_UNUSED_ARG(detail);
Benny Prijono9033e312005-11-21 02:08:39 +0000278#endif
279}
Benny Prijono8508aa02006-03-30 15:56:01 +0000280
Benny Prijonoc6e165f2006-07-09 10:05:46 +0000281
282static pj_bool_t cpool_on_block_alloc(pj_pool_factory *f, pj_size_t sz)
283{
284 pj_caching_pool *cp = (pj_caching_pool*)f;
285
286 //Can't lock because mutex is not recursive
287 //if (cp->mutex) pj_mutex_lock(cp->mutex);
288
289 cp->used_size += sz;
290 if (cp->used_size > cp->peak_used_size)
291 cp->peak_used_size = cp->used_size;
292
293 //if (cp->mutex) pj_mutex_unlock(cp->mutex);
294
295 return PJ_TRUE;
296}
297
298
299static void cpool_on_block_free(pj_pool_factory *f, pj_size_t sz)
300{
301 pj_caching_pool *cp = (pj_caching_pool*)f;
302
303 //pj_mutex_lock(cp->mutex);
304 cp->used_size -= sz;
305 //pj_mutex_unlock(cp->mutex);
306}
307
308
Benny Prijono8508aa02006-03-30 15:56:01 +0000309#endif /* PJ_HAS_POOL_ALT_API */
310