#include "systhr.h"
#include "pool_pvt.h"
#include "util.h"
#include <stdlib.h>
#include <string.h>
#include <limits.h>
static pool_config_t pool_config =
POOL_CONFIG_INIT;
static pool_global_stats_t pool_global_stats;
static cx_allocator_class pool_allocator_class = {
(
void *(*)(
void *,
size_t )) pool_malloc,
(
void *(*)(
void *,
void *,
size_t )) pool_realloc,
(
void *(*)(
void *,
size_t ,
size_t )) pool_calloc,
(
void (*)(
void *,
void *))pool_free
};
static int
pool_internal_init()
{
if (pool_config.block_size ==
0) {
}
return 0;
}
#define POOL_MIN_BLOCKSIZE 128
NSAPI_PUBLIC int
pool_init(pblock *pb, Session *sn, Request *rq)
{
char *str_block_size =
"16384";
char *str_pool_disable =
"false";
int n;
if (str_block_size !=
NULL) {
int64_t value;
if(!util_strtoint(str_block_size, &value)) {
log_ereport(
LOG_MISCONFIG,
"pool-init: param ''block-size'' is not an integer");
return REQ_ABORTED;
}
if(value >
INT_MAX) {
log_ereport(
LOG_MISCONFIG,
"pool-init: block-size is too big");
return REQ_ABORTED;
}
if(value <
POOL_MIN_BLOCKSIZE) {
log_ereport(
LOG_MISCONFIG,
"pool-init: block-size is too small");
return REQ_ABORTED;
}
pool_config.block_size = value;
}
if (str_pool_disable && util_getboolean(str_pool_disable,
PR_TRUE)) {
pool_config.block_size =
0;
pool_config.retain_size =
0;
pool_config.retain_num =
0;
}
pool_internal_init();
return REQ_PROCEED;
}
CxAllocator* pool_allocator(
pool_handle_t *pool) {
return &((
pool_t *)pool)->allocator;
}
static block_t *
_create_block(
pool_t *pool,
int size)
{
block_t *newblock;
char *newdata;
block_t **blk_ptr;
long blen;
for (blk_ptr = &pool->free_blocks;
(newblock = *blk_ptr) !=
NULL; blk_ptr = &newblock->next) {
blen = newblock->end - newblock->data;
if (blen >= size) {
*blk_ptr = newblock->next;
pool->free_size -= blen;
--pool->free_num;
newblock->start = newblock->data;
goto done;
}
}
newblock = (
block_t *)
PERM_MALLOC(
sizeof(
block_t));
newdata = (
char *)
PERM_MALLOC(size);
if (newblock ==
NULL || (newdata ==
NULL && size !=
0)) {
PERM_FREE(newblock);
PERM_FREE(newdata);
return NULL;
}
newblock->data = newdata;
newblock->start = newblock->data;
newblock->end = newblock->data + size;
newblock->next =
NULL;
blen = size;
#ifdef POOL_GLOBAL_STATISTICS
PR_AtomicIncrement((PRInt32 *)&pool_global_stats.blkAlloc);
#endif
done:
#ifdef PER_POOL_STATISTICS
++pool->stats.blkAlloc;
#endif
return newblock;
}
static void
_free_block(
block_t *block)
{
#ifdef POOL_ZERO_DEBUG
long blen = block->end - block->data;
memset(block->data,
POOL_ZERO_DEBUG, blen);
#endif
PERM_FREE(block->data);
#ifdef POOL_ZERO_DEBUG
memset(block,
POOL_ZERO_DEBUG,
sizeof(block));
#endif
PERM_FREE(block);
#ifdef POOL_GLOBAL_STATISTICS
PR_AtomicIncrement((PRInt32 *)&pool_global_stats.blkFree);
#endif
}
block_t *
_ptr_in_pool(
pool_t *pool,
const void *ptr)
{
block_t *block_ptr =
NULL;
if (
POOL_PTR_IN_BLOCK(pool->curr_block, ptr)) {
block_ptr = pool->curr_block;
}
else {
for (block_ptr = pool->used_blocks; block_ptr; block_ptr = block_ptr->next) {
if (
POOL_PTR_IN_BLOCK(block_ptr, ptr))
break;
}
}
return block_ptr;
}
NSAPI_PUBLIC pool_handle_t *
pool_create()
{
pool_t *newpool;
newpool = (
pool_t *)
PERM_MALLOC(
sizeof(
pool_t));
if (newpool) {
newpool->allocator.cl = &pool_allocator_class;
newpool->allocator.data = newpool;
newpool->used_blocks =
NULL;
newpool->free_blocks =
NULL;
newpool->free_size =
0;
newpool->free_num =
0;
newpool->size =
0;
newpool->next =
NULL;
#ifdef PER_POOL_STATISTICS
memset((
void *)(&newpool->stats),
0,
sizeof(newpool->stats));
newpool->stats.thread = PR_GetCurrentThread();
newpool->stats.created = PR_Now();
#endif
newpool->curr_block =_create_block(newpool, pool_config.block_size);
if (newpool->curr_block ==
NULL) {
pool_destroy((
pool_handle_t *)newpool);
return NULL;
}
#ifdef PER_POOL_STATISTICS
newpool->stats.poolId = pool_global_stats.createCnt;
#endif
}
else {
}
return (
pool_handle_t *)newpool;
}
NSAPI_PUBLIC void *
pool_mark(
pool_handle_t *pool_handle)
{
pool_t *pool = (
pool_t *)pool_handle;
if (pool ==
NULL)
return NULL;
#ifdef PER_POOL_STATISTICS
pool->stats.thread = PR_GetCurrentThread();
#endif
if (pool->curr_block->start == pool->curr_block->end)
return pool->curr_block;
return (
void *)(pool->curr_block->start);
}
NSAPI_PUBLIC void
pool_recycle(
pool_handle_t *pool_handle,
void *mark)
{
pool_t *pool = (
pool_t *)pool_handle;
block_t *tmp_blk;
unsigned long blen;
if (pool ==
NULL)
return;
tmp_blk = pool->curr_block;
for (;;) {
if (tmp_blk == mark) {
pool->curr_block = tmp_blk;
break;
}
if (
POOL_PTR_IN_BLOCK(tmp_blk, mark)) {
if (tmp_blk == pool->curr_block) {
blen = tmp_blk->start - (
char *)mark;
}
else {
blen = tmp_blk->end - (
char *)mark;
}
pool->size -= blen;
tmp_blk->start = (
char *)mark;
pool->curr_block = tmp_blk;
break;
}
if (tmp_blk == pool->curr_block) {
blen = tmp_blk->start - tmp_blk->data;
}
else {
blen = tmp_blk->end - tmp_blk->data;
}
tmp_blk->start = tmp_blk->data;
pool->size -= blen;
if (pool->used_blocks ==
NULL) {
pool->curr_block = tmp_blk;
break;
}
if ((pool->free_size + blen) <= pool_config.retain_size &&
pool->free_num < pool_config.retain_num) {
tmp_blk->next = pool->free_blocks;
pool->free_blocks = tmp_blk;
pool->free_size += blen;
++pool->free_num;
}
else {
_free_block(tmp_blk);
}
#ifdef PER_POOL_STATISTICS
#endif
tmp_blk = pool->used_blocks;
pool->used_blocks = tmp_blk->next;
}
}
NSAPI_PUBLIC void
pool_destroy(
pool_handle_t *pool_handle)
{
pool_t *pool = (
pool_t *)pool_handle;
block_t *tmp_blk;
if (pool ==
NULL)
return;
if (pool->curr_block)
_free_block(pool->curr_block);
while(pool->used_blocks) {
tmp_blk = pool->used_blocks;
pool->used_blocks = tmp_blk->next;
_free_block(tmp_blk);
}
while(pool->free_blocks) {
tmp_blk = pool->free_blocks;
pool->free_blocks = tmp_blk->next;
_free_block(tmp_blk);
}
{
}
#ifdef POOL_ZERO_DEBUG
memset(pool,
POOL_ZERO_DEBUG,
sizeof(pool));
#endif
PERM_FREE(pool);
return;
}
NSAPI_PUBLIC void *
pool_malloc(
pool_handle_t *pool_handle,
size_t size)
{
pool_t *pool = (
pool_t *)pool_handle;
block_t *curr_block;
long reqsize, blocksize;
char *ptr;
if (pool ==
NULL)
return PERM_MALLOC(size);
reqsize =
ALIGN(size);
if (reqsize ==
0) {
reqsize =
WORD_SIZE;
}
curr_block = pool->curr_block;
ptr = curr_block->start;
curr_block->start += reqsize;
if (curr_block->start > curr_block->end) {
curr_block->start -= reqsize;
pool->size += curr_block->end - curr_block->start;
#ifdef PER_POOL_STATISTICS
if (pool->size > pool->stats.maxAlloc) {
pool->stats.maxAlloc = pool->size;
}
#endif
curr_block->next = pool->used_blocks;
pool->used_blocks = curr_block;
blocksize = reqsize;
if (blocksize < pool_config.block_size)
blocksize = pool_config.block_size;
curr_block = _create_block(pool, blocksize);
pool->curr_block = curr_block;
if (curr_block ==
NULL) {
return NULL;
}
ptr = curr_block->start;
curr_block->start += reqsize;
}
pool->size += reqsize;
#ifdef PER_POOL_STATISTICS
if (pool->size > pool->stats.maxAlloc) {
pool->stats.maxAlloc = pool->size;
}
++pool->stats.allocCnt;
pool->stats.thread = PR_GetCurrentThread();
#endif
return ptr;
}
NSAPI_PUBLIC void
pool_free(
pool_handle_t *pool_handle,
void *ptr)
{
pool_t *pool = (
pool_t *)pool_handle;
if (ptr ==
NULL)
return;
if (pool ==
NULL) {
PERM_FREE(ptr);
return;
}
#ifdef PER_POOL_STATISTICS
++pool->stats.freeCnt;
pool->stats.thread = PR_GetCurrentThread();
#endif
return;
}
NSAPI_PUBLIC void *
pool_calloc(
pool_handle_t *pool_handle,
size_t nelem,
size_t elsize)
{
void *ptr;
if (pool_handle ==
NULL)
return calloc(
1, elsize * nelem);
ptr = pool_malloc(pool_handle, elsize * nelem);
if (ptr)
memset(ptr,
0, elsize * nelem);
return ptr;
}
NSAPI_PUBLIC void *
pool_realloc(
pool_handle_t *pool_handle,
void *ptr,
size_t size)
{
pool_t *pool = (
pool_t *)pool_handle;
void *newptr;
block_t *block_ptr;
size_t oldsize;
if (pool ==
NULL)
return PERM_REALLOC(ptr, size);
if ( (newptr = pool_malloc(pool_handle, size)) ==
NULL)
return NULL;
if ( !(block_ptr = _ptr_in_pool(pool, ptr)) ) {
return newptr;
}
oldsize = block_ptr->end - (
char *)ptr ;
if (oldsize > size)
oldsize = size;
memmove((
char *)newptr, (
char *)ptr, oldsize);
return newptr;
}
NSAPI_PUBLIC char *
pool_strdup(
pool_handle_t *pool_handle,
const char *orig_str)
{
char *new_str;
int len = strlen(orig_str);
if (pool_handle ==
NULL)
return PERM_STRDUP(orig_str);
new_str = (
char *)pool_malloc(pool_handle, len+
1);
if (new_str)
memcpy(new_str, orig_str, len+
1);
return new_str;
}
NSAPI_PUBLIC long
pool_space(
pool_handle_t *pool_handle)
{
pool_t *pool = (
pool_t *)pool_handle;
return pool->size;
}
NSAPI_PUBLIC int pool_enabled()
{
if (getThreadMallocKey() == -
1)
return 0;
if (!systhread_getdata(getThreadMallocKey()))
return 0;
return 1;
}
#ifdef DEBUG
NSAPI_PUBLIC void INTpool_assert(
pool_handle_t *pool_handle,
const void *ptr)
{
pool_t *pool = (
pool_t *)pool_handle;
if (pool ==
NULL)
return;
}
#endif
NSAPI_PUBLIC pool_config_t *pool_getConfig(
void)
{
return &pool_config;
}
#ifdef POOL_GLOBAL_STATISTICS
NSAPI_PUBLIC pool_global_stats_t *pool_getGlobalStats(
void)
{
return &pool_global_stats;
}
#endif
#ifdef PER_POOL_STATISTICS
NSAPI_PUBLIC pool_stats_t *pool_getPoolStats(
pool_handle_t *pool_handle)
{
pool_t *pool = (
pool_t *)pool_handle;
if (pool ==
NULL)
return NULL;
return &pool->stats;
}
#endif
cxmutstr cx_strdup_pool(
pool_handle_t *pool, cxmutstr s) {
cxmutstr newstring;
newstring.ptr = (
char*)pool_malloc(pool, s.length +
1);
if (newstring.ptr !=
NULL) {
newstring.length = s.length;
newstring.ptr[newstring.length] =
0;
memcpy(newstring.ptr, s.ptr, s.length);
}
return newstring;
}