eina: add eina_mempool_iterator_new to slowly iterate every allocated pointer in a mempool.

Reviewed-by: Mike Blumenkrantz <michael.blumenkrantz@gmail.com>
Differential Revision: https://phab.enlightenment.org/D9941
This commit is contained in:
Cedric Bail 2019-09-14 10:54:05 -07:00
parent bf12fe241e
commit 9382bfc0bc
7 changed files with 209 additions and 13 deletions

View File

@ -56,6 +56,11 @@ struct _Eina_Mempool_Backend
* @see eina_mempool_from
*/
Eina_Bool (*from)(void *data, void *element);
/** Function to get an Eina_Iterator that will walk every allocated element
* in the pool.
* @use eina_mempool_iterator_new
*/
Eina_Iterator *(*iterator)(void *data);
};
struct _Eina_Mempool_Backend_ABI1
@ -74,6 +79,7 @@ struct _Eina_Mempool_Backend_ABI2
{
void (*repack)(void *data, Eina_Mempool_Repack_Cb cb, void *cb_data);
Eina_Bool (*from)(void *data, void *element);
Eina_Iterator *(*iterator)(void *data);
};
struct _Eina_Mempool
@ -116,6 +122,13 @@ eina_mempool_from(Eina_Mempool *mp, void *element)
return mp->backend2->from(mp->backend_data, element);
}
static inline Eina_Iterator *
eina_mempool_iterator_new(Eina_Mempool *mp)
{
if (!mp->backend2->iterator) return NULL;
return mp->backend2->iterator(mp->backend_data);
}
static inline unsigned int
eina_mempool_alignof(unsigned int size)
{

View File

@ -104,6 +104,7 @@ _new_va(const char *name,
if (!mp->backend2) goto on_error;
mp->backend2->repack = be->repack;
mp->backend2->from = be->from;
mp->backend2->iterator = be->iterator;
}
mp->backend_data = mp->backend.init(context, options, args);

View File

@ -197,6 +197,17 @@ static inline Eina_Bool eina_mempool_from(Eina_Mempool *mp, void *element);
*/
EAPI void eina_mempool_statistics(Eina_Mempool *mp) EINA_ARG_NONNULL(1);
/**
* @brief Provide an iterator to walk all allocated elements from a specified mempool.
*
* @param[in] mp The mempool
* @return @c NULL if it is not possible to iterate over the mempool, a valid iterator otherwise.
*
* @note This call is expected to be slow and should not be used in any performance critical area.
* @since 1.23
*/
static inline Eina_Iterator *eina_mempool_iterator_new(Eina_Mempool *mp);
/**
* @brief Registers the given memory pool backend.
*

View File

@ -79,7 +79,7 @@ struct _Chained_Pool
EINA_INLIST;
EINA_RBTREE;
Eina_Trash *base;
int usage;
unsigned int usage;
unsigned char *last;
unsigned char *limit;
@ -91,11 +91,11 @@ struct _Chained_Mempool
Eina_Inlist *first;
Eina_Rbtree *root;
const char *name;
int item_alloc;
int pool_size;
int alloc_size;
int group_size;
int usage;
unsigned int item_alloc;
unsigned int pool_size;
unsigned int alloc_size;
unsigned int group_size;
unsigned int usage;
Chained_Pool* first_fill; //All allocation will happen in this chain,unless it is filled
#ifdef EINA_DEBUG_MALLOC
int minimal_size;
@ -453,6 +453,85 @@ eina_chained_mempool_from(void *data, void *ptr)
return ret;
}
typedef struct _Eina_Iterator_Chained_Mempool Eina_Iterator_Chained_Mempool;
struct _Eina_Iterator_Chained_Mempool
{
Eina_Iterator iterator;
Eina_Iterator *walker;
Chained_Pool *current;
Chained_Mempool *pool;
unsigned int offset;
};
static Eina_Bool
eina_mempool_iterator_next(Eina_Iterator_Chained_Mempool *it, void **data)
{
if (!it->current)
{
if (!eina_iterator_next(it->walker, (void**) &it->current))
return EINA_FALSE;
if (!it->current) return EINA_FALSE;
}
retry:
if (it->offset < it->pool->group_size)
{
unsigned char *ptr = (unsigned char *) (it->current + 1);
ptr += it->offset;
it->offset += it->pool->item_alloc;
if (!eina_chained_mempool_from(it->pool, ptr)) goto retry;
if (data) *data = (void *) ptr;
return EINA_TRUE;
}
if (!eina_iterator_next(it->walker, (void**) &it->current))
return EINA_FALSE;
it->offset = 0;
goto retry;
}
static Chained_Mempool *
eina_mempool_iterator_get_container(Eina_Iterator_Chained_Mempool *it)
{
return it->pool;
}
static void
eina_mempool_iterator_free(Eina_Iterator_Chained_Mempool *it)
{
eina_iterator_free(it->walker);
free(it);
}
static Eina_Iterator *
eina_chained_mempool_iterator_new(void *data)
{
Eina_Iterator_Chained_Mempool *it;
Chained_Mempool *pool = data;
it = calloc(1, sizeof (Eina_Iterator_Chained_Mempool));
if (!it) return NULL;
it->walker = eina_inlist_iterator_new(pool->first);
it->pool = pool;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(eina_mempool_iterator_next);
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
eina_mempool_iterator_get_container);
it->iterator.free = FUNC_ITERATOR_FREE(eina_mempool_iterator_free);
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
return &it->iterator;
}
static void
eina_chained_mempool_repack(void *data,
Eina_Mempool_Repack_Cb cb,
@ -645,7 +724,8 @@ static Eina_Mempool_Backend _eina_chained_mp_backend = {
NULL,
&eina_chained_mempool_shutdown,
&eina_chained_mempool_repack,
&eina_chained_mempool_from
&eina_chained_mempool_from,
&eina_chained_mempool_iterator_new
};
Eina_Bool chained_init(void)

View File

@ -63,14 +63,14 @@ struct _One_Big
{
const char *name;
int item_size;
unsigned int item_size;
int offset_to_item_inlist;
int usage;
int over;
int served;
int max;
unsigned int served;
unsigned int max;
unsigned char *base;
Eina_Trash *empty;
@ -263,6 +263,79 @@ eina_one_big_from(void *data, void *ptr)
return r;
}
typedef struct _Eina_Iterator_One_Big_Mempool Eina_Iterator_One_Big_Mempool;
struct _Eina_Iterator_One_Big_Mempool
{
Eina_Iterator iterator;
Eina_Iterator *walker;
One_Big *pool;
unsigned int offset;
};
static Eina_Bool
eina_mempool_iterator_next(Eina_Iterator_One_Big_Mempool *it, void **data)
{
Eina_Inlist *il = NULL;
retry:
if (it->offset < (it->pool->max * it->pool->item_size))
{
unsigned char *ptr = (unsigned char *) (it->pool->base);
ptr += it->offset;
it->offset += it->pool->item_size;
if (!eina_one_big_from(it->pool, ptr)) goto retry;
if (data) *data = (void *) ptr;
return EINA_TRUE;
}
if (!eina_iterator_next(it->walker, (void **) &il))
return EINA_FALSE;
if (data) *data = OVER_MEM_FROM_LIST(it->pool, il);
return EINA_TRUE;
}
static One_Big *
eina_mempool_iterator_get_container(Eina_Iterator_One_Big_Mempool *it)
{
return it->pool;
}
static void
eina_mempool_iterator_free(Eina_Iterator_One_Big_Mempool *it)
{
eina_iterator_free(it->walker);
free(it);
}
static Eina_Iterator *
eina_one_big_iterator_new(void *data)
{
Eina_Iterator_One_Big_Mempool *it;
One_Big *pool = data;
it = calloc(1, sizeof (Eina_Iterator_One_Big_Mempool));
if (!it) return NULL;
it->walker = eina_inlist_iterator_new(pool->over_list);
it->pool = pool;
it->iterator.version = EINA_ITERATOR_VERSION;
it->iterator.next = FUNC_ITERATOR_NEXT(eina_mempool_iterator_next);
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
eina_mempool_iterator_get_container);
it->iterator.free = FUNC_ITERATOR_FREE(eina_mempool_iterator_free);
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
return &it->iterator;
}
static void *
eina_one_big_realloc(EINA_UNUSED void *data,
EINA_UNUSED void *element,
@ -378,7 +451,8 @@ static Eina_Mempool_Backend _eina_one_big_mp_backend = {
NULL,
&eina_one_big_shutdown,
NULL,
&eina_one_big_from
&eina_one_big_from,
&eina_one_big_iterator_new
};
Eina_Bool one_big_init(void)

View File

@ -76,7 +76,8 @@ static Eina_Mempool_Backend _eina_pass_through_mp_backend = {
NULL,
&eina_pass_through_shutdown,
NULL,
&eina_pass_through_from
&eina_pass_through_from,
NULL
};
Eina_Bool pass_through_init(void)

View File

@ -28,10 +28,12 @@ static void
_eina_mempool_test(Eina_Mempool *mp,
Eina_Bool with_realloc, Eina_Bool with_gc, Eina_Bool accurate_from)
{
Eina_Iterator *it;
int *tbl[512];
int *ptr;
int i;
fail_if(!mp);
fail_if(!mp);
for (i = 0; i < 512; ++i)
{
@ -52,6 +54,20 @@ _eina_mempool_test(Eina_Mempool *mp,
fail_if(eina_mempool_from(mp, tbl[i]) != EINA_FALSE);
}
it = eina_mempool_iterator_new(mp);
EINA_ITERATOR_FOREACH(it, ptr)
{
ck_assert_int_gt(*ptr, 255);
*ptr = 0;
}
eina_iterator_free(it);
if (it) // Only check if the mempool support iterator
{
for (; i < 512; ++i)
ck_assert_int_eq(*tbl[i], 0);
}
if (with_realloc)
fail_if(eina_mempool_realloc(mp, tbl[500], 25) == NULL);
else