[MEDIUM] add new memory management functions

Implement pool_destroy2, pool_flush2, pool_gc2. It is safe to call
pool_gc2 to free whatever memory possible.
This commit is contained in:
Willy Tarreau 2007-05-13 19:38:49 +02:00
parent 50e608d721
commit e6ce59deb7
2 changed files with 82 additions and 13 deletions

View File

@ -134,7 +134,7 @@ struct pool_head {
/* Allocate a new entry for pool <pool>, and return it for immediate use. /* Allocate a new entry for pool <pool>, and return it for immediate use.
* NULL is returned if no memory is available for a new creation. * NULL is returned if no memory is available for a new creation.
*/ */
void *refill_pool_alloc(struct pool_head *pool); void *pool_refill_alloc(struct pool_head *pool);
/* Try to find an existing shared pool with the same characteristics and /* Try to find an existing shared pool with the same characteristics and
* returns it, otherwise creates this one. NULL is returned if no memory * returns it, otherwise creates this one. NULL is returned if no memory
@ -146,6 +146,23 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
*/ */
void dump_pools(void); void dump_pools(void);
/*
* This function frees whatever can be freed in pool <pool>.
*/
void pool_flush2(struct pool_head *pool);
/*
* This function frees whatever can be freed in all pools, but respecting
* the minimum thresholds imposed by owners.
*/
void pool_gc2();
/*
* This function destroys a pull by freeing it completely.
* This should be called only under extreme circumstances.
*/
void pool_destroy2(struct pool_head *pool);
/* /*
* Returns a pointer to type <type> taken from the * Returns a pointer to type <type> taken from the
* pool <pool_type> or dynamically allocated. In the * pool <pool_type> or dynamically allocated. In the
@ -155,11 +172,11 @@ void dump_pools(void);
#define pool_alloc2(pool) \ #define pool_alloc2(pool) \
({ \ ({ \
void *__p; \ void *__p; \
if ((__p = pool.free_list) == NULL) \ if ((__p = pool->free_list) == NULL) \
__p = pool_refill_alloc(&pool); \ __p = pool_refill_alloc(pool); \
else { \ else { \
pool.free_list = *(void **)pool.free_list; \ pool->free_list = *(void **)pool->free_list; \
pool.used++; \ pool->used++; \
} \ } \
__p; \ __p; \
}) })
@ -174,9 +191,9 @@ void dump_pools(void);
*/ */
#define pool_free2(pool, ptr) \ #define pool_free2(pool, ptr) \
({ \ ({ \
*(void **)ptr = (void *)pool.free_list; \ *(void **)ptr = (void *)pool->free_list; \
pool.free_list = (void *)ptr; \ pool->free_list = (void *)ptr; \
pool.used--; \ pool->used--; \
}) })

View File

@ -66,7 +66,7 @@ struct pool_head *create_pool(char *name, unsigned int size, unsigned int flags)
/* Allocate a new entry for pool <pool>, and return it for immediate use. /* Allocate a new entry for pool <pool>, and return it for immediate use.
* NULL is returned if no memory is available for a new creation. * NULL is returned if no memory is available for a new creation.
*/ */
void *refill_pool_alloc(struct pool_head *pool) void *pool_refill_alloc(struct pool_head *pool)
{ {
void *ret; void *ret;
@ -80,6 +80,57 @@ void *refill_pool_alloc(struct pool_head *pool)
return ret; return ret;
} }
/*
* This function frees whatever can be freed in pool <pool>.
*/
void pool_flush2(struct pool_head *pool)
{
void *temp, *next;
next = pool->free_list;
while (next) {
temp = next;
next = *(void **)temp;
pool->allocated--;
FREE(temp);
}
pool->free_list = next;
/* here, we should have pool->allocate == pool->used */
}
/*
* This function frees whatever can be freed in all pools, but respecting
* the minimum thresholds imposed by owners.
*/
void pool_gc2()
{
struct pool_head *entry;
list_for_each_entry(entry, &pools, list) {
void *temp, *next;
//qfprintf(stderr, "Flushing pool %s\n", entry->name);
next = entry->free_list;
while (next &&
entry->allocated > entry->minavail &&
entry->allocated > entry->used) {
temp = next;
next = *(void **)temp;
entry->allocated--;
FREE(temp);
}
entry->free_list = next;
}
}
/*
* This function destroys a pull by freeing it completely.
* This should be called only under extreme circumstances.
*/
void pool_destroy2(struct pool_head *pool)
{
pool_flush2(pool);
FREE(pool);
}
/* Dump statistics on pools usage. /* Dump statistics on pools usage.
*/ */
void dump_pools(void) void dump_pools(void)
@ -91,15 +142,16 @@ void dump_pools(void)
allocated = used = nbpools = 0; allocated = used = nbpools = 0;
qfprintf(stderr, "Dumping pools usage.\n"); qfprintf(stderr, "Dumping pools usage.\n");
list_for_each_entry(entry, &pools, list) { list_for_each_entry(entry, &pools, list) {
qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated, %d used%s\n", qfprintf(stderr, " - Pool %s (%d bytes) : %d allocated (%lu bytes), %d used%s\n",
entry->name, entry->size, entry->allocated, entry->used, entry->name, entry->size, entry->allocated,
(entry->flags & MEM_F_SHARED) ? " (SHARED)" : ""); entry->size * entry->allocated, entry->used,
(entry->flags & MEM_F_SHARED) ? " [SHARED]" : "");
allocated += entry->allocated * entry->size; allocated += entry->allocated * entry->size;
used += entry->used * entry->size; used += entry->used * entry->size;
nbpools++; nbpools++;
} }
qfprintf(stderr, "Total: %d pools, %lu allocated, %lu used.\n", qfprintf(stderr, "Total: %d pools, %lu bytes allocated, %lu used.\n",
nbpools, allocated, used); nbpools, allocated, used);
} }