#define POOL_DEF_EXTENT (32 * 1024)
+#define POOL_QALIGN_P2 (1<<16) /* power-of-2 qalign */
+
struct alloc_pool
{
size_t size; /* extent size */
/* statistical data */
unsigned long e_created; /* extents created */
- unsigned long e_freed; /* extents detroyed */
+ unsigned long e_freed; /* extents destroyed */
int64 n_allocated; /* calls to alloc */
int64 n_freed; /* calls to free */
int64 b_allocated; /* cum. bytes allocated */
{
void *start; /* starting address */
size_t free; /* free bytecount */
- size_t bound; /* bytes bound by padding,
- * overhead and freed */
+ size_t bound; /* trapped free bytes */
struct pool_extent *next;
};
struct align_test {
- void *foo;
- int64 bar;
+ uchar foo;
+ union {
+ int64 i;
+ void *p;
+ } bar;
};
#define MINALIGN offsetof(struct align_test, bar)
alloc_pool_t
pool_create(size_t size, size_t quantum, void (*bomb)(const char *), int flags)
{
- struct alloc_pool *pool;
-
- if (!(pool = new(struct alloc_pool)))
- return pool;
- memset(pool, 0, sizeof (struct alloc_pool));
-
- pool->size = size /* round extent size to min alignment reqs */
- ? (size + MINALIGN - 1) & ~(MINALIGN - 1)
- : POOL_DEF_EXTENT;
- if (pool->flags & POOL_INTERN) {
- pool->size -= sizeof (struct pool_extent);
- flags |= POOL_APPEND;
+ struct alloc_pool *pool;
+
+ if (!(pool = new0(struct alloc_pool)))
+ return NULL;
+
+ if ((MINALIGN & (MINALIGN - 1)) != 0) {
+ if (bomb)
+ (*bomb)("Compiler error: MINALIGN is not a power of 2\n");
+ return NULL;
+ }
+
+ if (!size)
+ size = POOL_DEF_EXTENT;
+ if (!quantum)
+ quantum = MINALIGN;
+
+ if (flags & POOL_INTERN) {
+ if (size <= sizeof (struct pool_extent))
+ size = quantum;
+ else
+ size -= sizeof (struct pool_extent);
+ flags |= POOL_PREPEND;
+ }
+
+ if (quantum <= 1)
+ flags = (flags | POOL_NO_QALIGN) & ~POOL_QALIGN_P2;
+ else if (!(flags & POOL_NO_QALIGN)) {
+ if (size % quantum)
+ size += quantum - size % quantum;
+ /* If quantum is a power of 2, we'll avoid using modulus. */
+ if (!(quantum & (quantum - 1)))
+ flags |= POOL_QALIGN_P2;
}
- pool->quantum = quantum ? quantum : MINALIGN;
+
+ pool->size = size;
+ pool->quantum = quantum;
pool->bomb = bomb;
pool->flags = flags;
pool_destroy(alloc_pool_t p)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
- struct pool_extent *cur, *next;
+ struct pool_extent *cur, *next;
if (!pool)
return;
for (cur = pool->extents; cur; cur = next) {
next = cur->next;
- free(cur->start);
- if (!(pool->flags & POOL_APPEND))
+ if (pool->flags & POOL_PREPEND)
+ free(cur->start - sizeof (struct pool_extent));
+ else {
+ free(cur->start);
free(cur);
+ }
}
+
free(pool);
}
if (!len)
len = pool->quantum;
- else if (pool->quantum > 1 && len % pool->quantum)
- len += pool->quantum - len % pool->quantum;
+ else if (pool->flags & POOL_QALIGN_P2) {
+ if (len & (pool->quantum - 1))
+ len += pool->quantum - (len & (pool->quantum - 1));
+ } else if (!(pool->flags & POOL_NO_QALIGN)) {
+ if (len % pool->quantum)
+ len += pool->quantum - len % pool->quantum;
+ }
if (len > pool->size)
goto bomb_out;
if (!pool->extents || len > pool->extents->free) {
- void *start;
- size_t free;
- size_t bound;
- size_t skew;
- size_t asize;
+ void *start;
+ size_t asize;
struct pool_extent *ext;
- free = pool->size;
- bound = 0;
-
asize = pool->size;
- if (pool->flags & POOL_APPEND)
+ if (pool->flags & POOL_PREPEND)
asize += sizeof (struct pool_extent);
if (!(start = new_array(char, asize)))
goto bomb_out;
if (pool->flags & POOL_CLEAR)
- memset(start, 0, free);
+ memset(start, 0, asize);
- if (pool->flags & POOL_APPEND)
- ext = PTR_ADD(start, free);
- else if (!(ext = new(struct pool_extent)))
+ if (pool->flags & POOL_PREPEND) {
+ ext = start;
+ start += sizeof (struct pool_extent);
+ } else if (!(ext = new(struct pool_extent)))
goto bomb_out;
- if (pool->flags & POOL_QALIGN && pool->quantum > 1
- && (skew = (size_t)PTR_ADD(start, free) % pool->quantum)) {
- bound += skew;
- free -= skew;
- }
ext->start = start;
- ext->free = free;
- ext->bound = bound;
+ ext->free = pool->size;
+ ext->bound = 0;
ext->next = pool->extents;
pool->extents = ext;
if (!pool)
return;
+ if (!addr) {
+ /* A NULL addr starts a fresh extent for new allocations. */
+ if ((cur = pool->extents) != NULL && cur->free != pool->size) {
+ cur->bound += cur->free;
+ cur->free = 0;
+ }
+ return;
+ }
+
if (!len)
len = pool->quantum;
- else if (pool->quantum > 1 && len % pool->quantum)
- len += pool->quantum - len % pool->quantum;
+ else if (pool->flags & POOL_QALIGN_P2) {
+ if (len & (pool->quantum - 1))
+ len += pool->quantum - (len & (pool->quantum - 1));
+ } else if (!(pool->flags & POOL_NO_QALIGN)) {
+ if (len % pool->quantum)
+ len += pool->quantum - len % pool->quantum;
+ }
pool->n_freed++;
pool->b_freed += len;
if (!prev) {
/* The "live" extent is kept ready for more allocations. */
if (cur->free + cur->bound + len >= pool->size) {
- size_t skew;
-
if (pool->flags & POOL_CLEAR) {
memset(PTR_ADD(cur->start, cur->free), 0,
pool->size - cur->free);
}
cur->free = pool->size;
cur->bound = 0;
- if (pool->flags & POOL_QALIGN && pool->quantum > 1
- && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
- cur->bound += skew;
- cur->free -= skew;
- }
} else if (addr == PTR_ADD(cur->start, cur->free)) {
if (pool->flags & POOL_CLEAR)
memset(addr, 0, len);
if (cur->free + cur->bound >= pool->size) {
prev->next = cur->next;
- free(cur->start);
- if (!(pool->flags & POOL_APPEND))
+ if (pool->flags & POOL_PREPEND)
+ free(cur->start - sizeof (struct pool_extent));
+ else {
+ free(cur->start);
free(cur);
+ }
pool->e_freed++;
} else if (prev != pool->extents) {
/* Move the extent to be the first non-live extent. */
struct alloc_pool *pool = (struct alloc_pool *)p;
struct pool_extent *cur, *prev, *next;
- if (!pool)
+ if (!pool || !addr)
return;
- if (!addr) {
- if (!pool->extents)
- return;
- addr = PTR_ADD(pool->extents->start, pool->extents->free);
- }
-
for (prev = NULL, cur = pool->extents; cur; prev = cur, cur = cur->next) {
if (addr >= cur->start
&& addr < PTR_ADD(cur->start, pool->size))
prev->next = NULL;
next = cur;
} else {
- size_t skew;
-
/* The most recent live extent can just be reset. */
if (pool->flags & POOL_CLEAR)
memset(addr, 0, pool->size - cur->free);
cur->free = pool->size;
cur->bound = 0;
- if (pool->flags & POOL_QALIGN && pool->quantum > 1
- && (skew = (size_t)PTR_ADD(cur->start, cur->free) % pool->quantum)) {
- cur->bound += skew;
- cur->free -= skew;
- }
next = cur->next;
+ cur->next = NULL;
}
} else {
next = cur->next;
while ((cur = next) != NULL) {
next = cur->next;
- free(cur->start);
- if (!(pool->flags & POOL_APPEND))
+ if (pool->flags & POOL_PREPEND)
+ free(cur->start - sizeof (struct pool_extent));
+ else {
+ free(cur->start);
free(cur);
+ }
pool->e_freed++;
}
}
pool_stats(alloc_pool_t p, int fd, int summarize)
{
struct alloc_pool *pool = (struct alloc_pool *) p;
- struct pool_extent *cur;
+ struct pool_extent *cur;
char buf[BUFSIZ];
if (!pool)