Minor refactor: make the framework responsible for allocating and freeing the

actual wmem_allocator_t structure. This simplifies the internal API and
deduplicates a few alloc/free calls in the individual allocator implementations.

I'd originally made the allocators responsible for this on purpose with the
idea that they'd be able to optimize something clever based on the type of
allocator, but that's clearly more work and complexity than it's worth given
the small number of allocators we create/destroy.

svn path=/trunk/; revision=49512
This commit is contained in:
Evan Huus 2013-05-22 15:42:12 +00:00
parent a2f6822fea
commit 5426ba4e02
10 changed files with 64 additions and 79 deletions

View File

@ -284,23 +284,24 @@ and realloc) are non-0.
- free_all()
- gc()
- destroy()
- cleanup()
The free_all() function takes the private_data pointer and should free all the
memory currently allocated in the pool. Note that this is not necessarilly
exactly the same as calling free() on all the allocated blocks - free_all() is
allowed to do additional cleanup or to make use of optimizations not available
when freeing one block at a time.
All of these functions take only one parameter, which is the allocator's
private_data pointer.
The gc() function takes the private_data pointer and should do whatever it can
to reduce excess memory usage in the dissector by returning unused blocks to
the OS, optimizing internal data structures, etc.
The free_all() function should free all the memory currently allocated in the
pool. Note that this is not necessarily exactly the same as calling free()
on all the allocated blocks - free_all() is allowed to do additional cleanup
or to make use of optimizations not available when freeing one block at a time.
The destroy() function does NOT take the private_data pointer - it instead takes
a pointer to the allocator structure as a whole, since that structure may also
need freeing. This function can assume that free_all() has been called
immediately before it (though it can make no assumptions about whether or not
gc() has ever been called).
The gc() function should do whatever it can to reduce excess memory usage in
the dissector by returning unused blocks to the OS, optimizing internal data
structures, etc.
The cleanup() function should do any final cleanup and free any and all memory.
It is basically the equivalent of a destructor function. For simplicity, wmem
is guaranteed to call free_all() immediately before this function. There is no
such guarantee that gc() has (ever) been called.
4.2 Pool-Agnostic API

View File

@ -47,7 +47,7 @@ struct _wmem_allocator_t {
/* Producer/Manager functions */
void (*free_all)(void *private_data);
void (*gc)(void *private_data);
void (*destroy)(struct _wmem_allocator_t *allocator);
void (*cleanup)(void *private_data);
/* Callback List */
struct _wmem_user_cb_container_t *callbacks;

View File

@ -853,45 +853,36 @@ wmem_block_gc(void *private_data)
}
static void
wmem_block_allocator_destroy(wmem_allocator_t *allocator)
wmem_block_allocator_cleanup(void *private_data)
{
wmem_block_allocator_t *real_allocator;
real_allocator = (wmem_block_allocator_t*) allocator->private_data;
/* wmem guarantees that free_all() is called directly before this, so
* calling gc will return all our blocks to the OS automatically */
wmem_block_gc(real_allocator);
wmem_block_gc(private_data);
/* then just free the allocator structs */
g_slice_free(wmem_block_allocator_t, real_allocator);
g_slice_free(wmem_allocator_t, allocator);
g_slice_free(wmem_block_allocator_t, private_data);
}
wmem_allocator_t *
wmem_block_allocator_new(void)
void
wmem_block_allocator_init(wmem_allocator_t *allocator)
{
wmem_allocator_t *allocator;
wmem_block_allocator_t *block_allocator;
allocator = g_slice_new(wmem_allocator_t);
block_allocator = g_slice_new(wmem_block_allocator_t);
allocator->private_data = (void*) block_allocator;
allocator->alloc = &wmem_block_alloc;
allocator->realloc = &wmem_block_realloc;
allocator->free = &wmem_block_free;
allocator->free_all = &wmem_block_free_all;
allocator->gc = &wmem_block_gc;
allocator->destroy = &wmem_block_allocator_destroy;
allocator->cleanup = &wmem_block_allocator_cleanup;
allocator->private_data = (void*) block_allocator;
block_allocator->block_list = NULL;
block_allocator->free_list_head = NULL;
block_allocator->free_insert_point = NULL;
return allocator;
}
/*

View File

@ -32,8 +32,8 @@
extern "C" {
#endif /* __cplusplus */
wmem_allocator_t *
wmem_block_allocator_new(void);
void
wmem_block_allocator_init(wmem_allocator_t *allocator);
/* Exposed only for testing purposes */
void

View File

@ -111,40 +111,35 @@ wmem_simple_gc(void *private_data _U_)
}
static void
wmem_simple_allocator_destroy(wmem_allocator_t *allocator)
wmem_simple_allocator_cleanup(void *private_data)
{
wmem_simple_allocator_t *private_allocator;
wmem_simple_allocator_t *allocator;
private_allocator = (wmem_simple_allocator_t*) allocator->private_data;
allocator = (wmem_simple_allocator_t*) private_data;
g_hash_table_destroy(private_allocator->block_table);
g_slice_free(wmem_simple_allocator_t, private_allocator);
g_slice_free(wmem_allocator_t, allocator);
g_hash_table_destroy(allocator->block_table);
g_slice_free(wmem_simple_allocator_t, allocator);
}
wmem_allocator_t *
wmem_simple_allocator_new(void)
void
wmem_simple_allocator_init(wmem_allocator_t *allocator)
{
wmem_allocator_t *allocator;
wmem_simple_allocator_t *simple_allocator;
allocator = g_slice_new(wmem_allocator_t);
simple_allocator = g_slice_new(wmem_simple_allocator_t);
allocator->private_data = (void*) simple_allocator;
allocator->alloc = &wmem_simple_alloc;
allocator->realloc = &wmem_simple_realloc;
allocator->free = &wmem_simple_free;
allocator->free_all = &wmem_simple_free_all;
allocator->gc = &wmem_simple_gc;
allocator->destroy = &wmem_simple_allocator_destroy;
allocator->cleanup = &wmem_simple_allocator_cleanup;
allocator->private_data = (void*) simple_allocator;
simple_allocator->block_table = g_hash_table_new_full(
&g_direct_hash, &g_direct_equal, NULL, &g_free);
return allocator;
}
/*

View File

@ -32,8 +32,8 @@
extern "C" {
#endif /* __cplusplus */
wmem_allocator_t *
wmem_simple_allocator_new(void);
void
wmem_simple_allocator_init(wmem_allocator_t *allocator);
#ifdef __cplusplus
}

View File

@ -222,24 +222,21 @@ wmem_strict_gc(void *private_data _U_)
}
static void
wmem_strict_allocator_destroy(wmem_allocator_t *allocator)
wmem_strict_allocator_cleanup(void *private_data)
{
wmem_strict_allocator_t *private_allocator;
wmem_strict_allocator_t *allocator;
private_allocator = (wmem_strict_allocator_t*) allocator->private_data;
allocator = (wmem_strict_allocator_t*) private_data;
g_hash_table_destroy(private_allocator->block_table);
g_slice_free(wmem_strict_allocator_t, private_allocator);
g_slice_free(wmem_allocator_t, allocator);
g_hash_table_destroy(allocator->block_table);
g_slice_free(wmem_strict_allocator_t, allocator);
}
wmem_allocator_t *
wmem_strict_allocator_new(void)
void
wmem_strict_allocator_init(wmem_allocator_t *allocator)
{
wmem_allocator_t *allocator;
wmem_strict_allocator_t *strict_allocator;
allocator = g_slice_new(wmem_allocator_t);
strict_allocator = g_slice_new(wmem_strict_allocator_t);
allocator->alloc = &wmem_strict_alloc;
@ -248,15 +245,13 @@ wmem_strict_allocator_new(void)
allocator->free_all = &wmem_strict_free_all;
allocator->gc = &wmem_strict_gc;
allocator->destroy = &wmem_strict_allocator_destroy;
allocator->cleanup = &wmem_strict_allocator_cleanup;
allocator->private_data = (void*) strict_allocator;
strict_allocator->block_table = g_hash_table_new_full(
&g_direct_hash, &g_direct_equal,
NULL, &wmem_strict_ghash_block_free);
return allocator;
}
/*

View File

@ -32,8 +32,8 @@
extern "C" {
#endif /* __cplusplus */
wmem_allocator_t *
wmem_strict_allocator_new(void);
void
wmem_strict_allocator_init(wmem_allocator_t *allocator);
void
wmem_strict_check_canaries(wmem_allocator_t *allocator);

View File

@ -123,7 +123,8 @@ wmem_destroy_allocator(wmem_allocator_t *allocator)
{
wmem_free_all_real(allocator, TRUE);
allocator->destroy(allocator);
allocator->cleanup(allocator->private_data);
g_slice_free(wmem_allocator_t, allocator);
}
wmem_allocator_t *
@ -156,15 +157,19 @@ wmem_allocator_new(const wmem_allocator_type_t type)
real_type = type;
}
allocator = g_slice_new(wmem_allocator_t);
allocator->type = real_type;
allocator->callbacks = NULL;
switch (real_type) {
case WMEM_ALLOCATOR_SIMPLE:
allocator = wmem_simple_allocator_new();
wmem_simple_allocator_init(allocator);
break;
case WMEM_ALLOCATOR_BLOCK:
allocator = wmem_block_allocator_new();
wmem_block_allocator_init(allocator);
break;
case WMEM_ALLOCATOR_STRICT:
allocator = wmem_strict_allocator_new();
wmem_strict_allocator_init(allocator);
break;
default:
g_assert_not_reached();
@ -174,9 +179,6 @@ wmem_allocator_new(const wmem_allocator_type_t type)
return NULL;
};
allocator->type = real_type;
allocator->callbacks = NULL;
return allocator;
}

View File

@ -46,15 +46,19 @@ wmem_allocator_force_new(const wmem_allocator_type_t type)
{
wmem_allocator_t *allocator;
allocator = g_slice_new(wmem_allocator_t);
allocator->type = type;
allocator->callbacks = NULL;
switch (type) {
case WMEM_ALLOCATOR_SIMPLE:
allocator = wmem_simple_allocator_new();
wmem_simple_allocator_init(allocator);
break;
case WMEM_ALLOCATOR_BLOCK:
allocator = wmem_block_allocator_new();
wmem_block_allocator_init(allocator);
break;
case WMEM_ALLOCATOR_STRICT:
allocator = wmem_strict_allocator_new();
wmem_strict_allocator_init(allocator);
break;
default:
g_assert_not_reached();
@ -64,9 +68,6 @@ wmem_allocator_force_new(const wmem_allocator_type_t type)
return NULL;
};
allocator->type = type;
allocator->callbacks = NULL;
return allocator;
}