#include <sm/gen.h>
SM_RCSID("@(#)$Id: rpool.c,v 1.28 2004/08/03 20:44:04 ca Exp $")
#include <sm/exc.h>
#include <sm/heap.h>
#include <sm/rpool.h>
#include <sm/varargs.h>
#include <sm/conf.h>
#if _FFR_PERF_RPOOL
# include <syslog.h>
#endif
const char SmRpoolMagic[] = "sm_rpool";
typedef union
{
SM_POOLLINK_T link;
char align[SM_ALIGN_SIZE];
} SM_POOLHDR_T;
static char *sm_rpool_allocblock_x __P((SM_RPOOL_T *, size_t));
static char *sm_rpool_allocblock __P((SM_RPOOL_T *, size_t));
#define POOLSIZE 4096
#define BIG_OBJECT_RATIO 10
static char *
sm_rpool_allocblock_x(rpool, size)
SM_RPOOL_T *rpool;
size_t size;
{
SM_POOLLINK_T *p;
p = sm_malloc_x(sizeof(SM_POOLHDR_T) + size);
p->sm_pnext = rpool->sm_pools;
rpool->sm_pools = p;
return (char*) p + sizeof(SM_POOLHDR_T);
}
static char *
sm_rpool_allocblock(rpool, size)
SM_RPOOL_T *rpool;
size_t size;
{
SM_POOLLINK_T *p;
p = sm_malloc(sizeof(SM_POOLHDR_T) + size);
if (p == NULL)
return NULL;
p->sm_pnext = rpool->sm_pools;
rpool->sm_pools = p;
return (char*) p + sizeof(SM_POOLHDR_T);
}
void *
#if SM_HEAP_CHECK
sm_rpool_malloc_tagged_x(rpool, size, file, line, group)
SM_RPOOL_T *rpool;
size_t size;
char *file;
int line;
int group;
#else
sm_rpool_malloc_x(rpool, size)
SM_RPOOL_T *rpool;
size_t size;
#endif
{
char *ptr;
if (rpool == NULL)
return sm_malloc_tagged_x(size, file, line, group);
if (size & SM_ALIGN_BITS)
size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
if (size <= rpool->sm_poolavail)
{
ptr = rpool->sm_poolptr;
rpool->sm_poolptr += size;
rpool->sm_poolavail -= size;
return ptr;
}
SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
if (size > rpool->sm_bigobjectsize)
{
#if _FFR_PERF_RPOOL
++rpool->sm_nbigblocks;
#endif
return sm_rpool_allocblock_x(rpool, size);
}
SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
ptr = sm_rpool_allocblock_x(rpool, rpool->sm_poolsize);
rpool->sm_poolptr = ptr + size;
rpool->sm_poolavail = rpool->sm_poolsize - size;
#if _FFR_PERF_RPOOL
++rpool->sm_npools;
#endif
return ptr;
}
void *
#if SM_HEAP_CHECK
sm_rpool_malloc_tagged(rpool, size, file, line, group)
SM_RPOOL_T *rpool;
size_t size;
char *file;
int line;
int group;
#else
sm_rpool_malloc(rpool, size)
SM_RPOOL_T *rpool;
size_t size;
#endif
{
char *ptr;
if (rpool == NULL)
return sm_malloc_tagged(size, file, line, group);
if (size & SM_ALIGN_BITS)
size = (size & ~SM_ALIGN_BITS) + SM_ALIGN_SIZE;
if (size <= rpool->sm_poolavail)
{
ptr = rpool->sm_poolptr;
rpool->sm_poolptr += size;
rpool->sm_poolavail -= size;
return ptr;
}
SM_REQUIRE(rpool->sm_magic == SmRpoolMagic);
if (size > rpool->sm_bigobjectsize)
{
#if _FFR_PERF_RPOOL
++rpool->sm_nbigblocks;
#endif
return sm_rpool_allocblock(rpool, size);
}
SM_ASSERT(rpool->sm_bigobjectsize <= rpool->sm_poolsize);
ptr = sm_rpool_allocblock(rpool, rpool->sm_poolsize);
if (ptr == NULL)
return NULL;
rpool->sm_poolptr = ptr + size;
rpool->sm_poolavail = rpool->sm_poolsize - size;
#if _FFR_PERF_RPOOL
++rpool->sm_npools;
#endif
return ptr;
}
SM_RPOOL_T *
sm_rpool_new_x(parent)
SM_RPOOL_T *parent;
{
SM_RPOOL_T *rpool;
rpool = sm_malloc_x(sizeof(SM_RPOOL_T));
if (parent == NULL)
rpool->sm_parentlink = NULL;
else
{
SM_TRY
rpool->sm_parentlink = sm_rpool_attach_x(parent,
(SM_RPOOL_RFREE_T) sm_rpool_free,
(void *) rpool);
SM_EXCEPT(exc, "*")
sm_free(rpool);
sm_exc_raise_x(exc);
SM_END_TRY
}
rpool->sm_magic = SmRpoolMagic;
rpool->sm_poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
rpool->sm_bigobjectsize = rpool->sm_poolsize / BIG_OBJECT_RATIO;
rpool->sm_poolptr = NULL;
rpool->sm_poolavail = 0;
rpool->sm_pools = NULL;
rpool->sm_rptr = NULL;
rpool->sm_ravail = 0;
rpool->sm_rlists = NULL;
#if _FFR_PERF_RPOOL
rpool->sm_nbigblocks = 0;
rpool->sm_npools = 0;
#endif
return rpool;
}
void
sm_rpool_setsizes(rpool, poolsize, bigobjectsize)
SM_RPOOL_T *rpool;
size_t poolsize;
size_t bigobjectsize;
{
SM_REQUIRE(poolsize >= bigobjectsize);
if (poolsize == 0)
poolsize = POOLSIZE - sizeof(SM_POOLHDR_T);
if (bigobjectsize == 0)
bigobjectsize = poolsize / BIG_OBJECT_RATIO;
rpool->sm_poolsize = poolsize;
rpool->sm_bigobjectsize = bigobjectsize;
}
void
sm_rpool_free(rpool)
SM_RPOOL_T *rpool;
{
SM_RLIST_T *rl, *rnext;
SM_RESOURCE_T *r, *rmax;
SM_POOLLINK_T *pp, *pnext;
if (rpool == NULL)
return;
rl = rpool->sm_rlists;
if (rl != NULL)
{
rmax = rpool->sm_rptr;
for (;;)
{
for (r = rl->sm_rvec; r < rmax; ++r)
{
if (r->sm_rfree != NULL)
r->sm_rfree(r->sm_rcontext);
}
rnext = rl->sm_rnext;
sm_free(rl);
if (rnext == NULL)
break;
rl = rnext;
rmax = &rl->sm_rvec[SM_RLIST_MAX];
}
}
for (pp = rpool->sm_pools; pp != NULL; pp = pnext)
{
pnext = pp->sm_pnext;
sm_free(pp);
}
if (rpool->sm_parentlink != NULL)
*rpool->sm_parentlink = NULL;
rpool->sm_magic = NULL;
rpool->sm_poolavail = 0;
rpool->sm_ravail = 0;
#if _FFR_PERF_RPOOL
if (rpool->sm_nbigblocks > 0 || rpool->sm_npools > 1)
syslog(LOG_NOTICE,
"perf: rpool=%lx, sm_nbigblocks=%d, sm_npools=%d",
(long) rpool, rpool->sm_nbigblocks, rpool->sm_npools);
rpool->sm_nbigblocks = 0;
rpool->sm_npools = 0;
#endif
sm_free(rpool);
}
SM_RPOOL_ATTACH_T
sm_rpool_attach_x(rpool, rfree, rcontext)
SM_RPOOL_T *rpool;
SM_RPOOL_RFREE_T rfree;
void *rcontext;
{
SM_RLIST_T *rl;
SM_RPOOL_ATTACH_T a;
SM_REQUIRE_ISA(rpool, SmRpoolMagic);
if (rpool->sm_ravail == 0)
{
rl = sm_malloc_x(sizeof(SM_RLIST_T));
rl->sm_rnext = rpool->sm_rlists;
rpool->sm_rlists = rl;
rpool->sm_rptr = rl->sm_rvec;
rpool->sm_ravail = SM_RLIST_MAX;
}
a = &rpool->sm_rptr->sm_rfree;
rpool->sm_rptr->sm_rfree = rfree;
rpool->sm_rptr->sm_rcontext = rcontext;
++rpool->sm_rptr;
--rpool->sm_ravail;
return a;
}
#if DO_NOT_USE_STRCPY
char *
sm_rpool_strdup_x(rpool, s)
SM_RPOOL_T *rpool;
const char *s;
{
size_t l;
char *n;
l = strlen(s);
SM_ASSERT(l + 1 > l);
n = sm_rpool_malloc_x(rpool, l + 1);
sm_strlcpy(n, s, l + 1);
return n;
}
#endif