1
0
mirror of git://sourceware.org/git/lvm2.git synced 2024-12-21 13:34:40 +03:00
lvm2/lib/mm/pool-debug.c
2002-01-10 16:47:25 +00:00

190 lines
3.0 KiB
C

/*
* Copyright (C) 2001 Sistina Software (UK) Limited.
*
* This file is released under the LGPL.
*/
#include "pool.h"
#include "dbg_malloc.h"
#include "log.h"
#include <assert.h>
struct block {
struct block *next;
size_t size;
char data[0];
};
struct pool {
int begun;
struct block *object;
struct block *blocks;
struct block *tail;
};
/* by default things come out aligned for doubles */
#define DEFAULT_ALIGNMENT __alignof__ (double)
struct pool *pool_create(size_t chunk_hint)
{
struct pool *mem = dbg_malloc(sizeof(*mem));
if (!mem) {
log_error("Couldn't create memory pool (size %u)",
sizeof(*mem));
return NULL;
}
mem->object = 0;
mem->blocks = mem->tail = NULL;
return mem;
}
static void _free_blocks(struct block *b)
{
struct block *n;
while (b) {
n = b->next;
dbg_free(b);
b = n;
}
}
void pool_destroy(struct pool *p)
{
_free_blocks(p->blocks);
dbg_free(p);
}
void *pool_alloc(struct pool *p, size_t s)
{
return pool_alloc_aligned(p, s, DEFAULT_ALIGNMENT);
}
static void _append_block(struct pool *p, struct block *b)
{
if (p->tail) {
p->tail->next = b;
p->tail = b;
} else
p->blocks = p->tail = b;
}
static struct block *_new_block(size_t s, unsigned alignment)
{
/* FIXME: I'm currently ignoring the alignment arg. */
size_t len = sizeof(struct block) + s;
struct block *b = dbg_malloc(len);
if (!b) {
log_err("Out of memory. Requested %u bytes.", len);
return NULL;
}
b->next = NULL;
b->size = s;
return b;
}
void *pool_alloc_aligned(struct pool *p, size_t s, unsigned alignment)
{
struct block *b = _new_block(s, alignment);
if (!b)
return NULL;
_append_block(p, b);
return &b->data[0];
}
void pool_empty(struct pool *p)
{
_free_blocks(p->blocks);
p->blocks = p->tail = NULL;
}
void pool_free(struct pool *p, void *ptr)
{
struct block *b, *prev = NULL;
for (b = p->blocks; b; b = b->next) {
if ((void *) &b->data[0] == ptr)
break;
prev = b;
}
/*
* If this fires then you tried to free a
* pointer that either wasn't from this
* pool, or isn't the start of a block.
*/
assert(b);
_free_blocks(b);
if (prev) {
p->tail = prev;
prev->next = NULL;
} else
p->blocks = p->tail = NULL;
}
int pool_begin_object(struct pool *p, size_t init_size)
{
assert(!p->begun);
p->begun = 1;
return 1;
}
int pool_grow_object(struct pool *p, const void *buffer, size_t delta)
{
struct block *new;
assert(p->begun);
if (!(new = _new_block(p->object->size + delta, DEFAULT_ALIGNMENT))) {
log_err("Couldn't extend object.");
return 0;
}
if (p->object) {
memcpy(&new->data, &p->object->data, p->object->size);
dbg_free(p->object);
}
p->object = new;
return 1;
}
void *pool_end_object(struct pool *p)
{
assert(p->begun);
_append_block(p, p->object);
p->begun = 0;
p->object = NULL;
return &p->tail->data;
}
void pool_abandon_object(struct pool *p)
{
assert(p->begun);
dbg_free(p->object);
p->begun = 0;
p->object = NULL;
}
char *pool_strdup(struct pool *p, const char *str)
{
char *ret = pool_alloc(p, strlen(str) + 1);
if (ret)
strcpy(ret, str);
return ret;
}