diff --git a/legacy/eina/ChangeLog b/legacy/eina/ChangeLog index f3c3478f9a..ccfa402ba2 100644 --- a/legacy/eina/ChangeLog +++ b/legacy/eina/ChangeLog @@ -45,3 +45,4 @@ 2011-05-11 Cedric Bail * Add eina_inlist_sort. + * Add eina_mempool_repack. diff --git a/legacy/eina/src/include/eina_inline_mempool.x b/legacy/eina/src/include/eina_inline_mempool.x index 3f44b901d5..72e70fe131 100644 --- a/legacy/eina/src/include/eina_inline_mempool.x +++ b/legacy/eina/src/include/eina_inline_mempool.x @@ -36,6 +36,7 @@ struct _Eina_Mempool_Backend void (*garbage_collect)(void *data); void (*statistics)(void *data); void (*shutdown)(void *data); + void (*repack)(void *data, Eina_Mempool_Repack_Cb cb, void *cb_data); }; struct _Eina_Mempool diff --git a/legacy/eina/src/include/eina_mempool.h b/legacy/eina/src/include/eina_mempool.h index e30efd2aba..c6c0aa7526 100644 --- a/legacy/eina/src/include/eina_mempool.h +++ b/legacy/eina/src/include/eina_mempool.h @@ -84,6 +84,14 @@ typedef struct _Eina_Mempool Eina_Mempool; */ typedef struct _Eina_Mempool_Backend Eina_Mempool_Backend; + +/** + * @typedef Eina_Mempool_Repack_Cb + * Type for a callback who need to unreference an old object from a mempool + * and reference the new one instead. Memcpy is taken care by the mempool. + */ +typedef void (*Eina_Mempool_Repack_Cb)(void *dst, void *src, void *data); + EAPI extern Eina_Error EINA_ERROR_NOT_MEMPOOL_MODULE; EAPI Eina_Mempool *eina_mempool_add(const char *module, const char *context, const char *options, ...) EINA_MALLOC EINA_WARN_UNUSED_RESULT EINA_ARG_NONNULL(1); @@ -93,6 +101,9 @@ static inline void *eina_mempool_realloc(Eina_Mempool *mp, void *element, unsign static inline void *eina_mempool_malloc(Eina_Mempool *mp, unsigned int size) EINA_MALLOC EINA_ARG_NONNULL(1) EINA_WARN_UNUSED_RESULT; static inline void eina_mempool_free(Eina_Mempool *mp, void *element) EINA_ARG_NONNULL(1); +EAPI void eina_mempool_repack(Eina_Mempool *mp, + Eina_Mempool_Repack_Cb cb, + void *data) EINA_ARG_NONNULL(1, 2); EAPI void eina_mempool_gc(Eina_Mempool *mp) EINA_ARG_NONNULL(1); EAPI void eina_mempool_statistics(Eina_Mempool *mp) EINA_ARG_NONNULL(1); diff --git a/legacy/eina/src/lib/eina_mempool.c b/legacy/eina/src/lib/eina_mempool.c index 7e30264c7b..ddeabca6b4 100644 --- a/legacy/eina/src/lib/eina_mempool.c +++ b/legacy/eina/src/lib/eina_mempool.c @@ -319,6 +319,14 @@ EAPI void eina_mempool_del(Eina_Mempool *mp) free(mp); } +EAPI void eina_mempool_repack(Eina_Mempool *mp, Eina_Mempool_Repack_Cb cb, void *data) +{ + EINA_SAFETY_ON_NULL_RETURN(mp); + EINA_SAFETY_ON_NULL_RETURN(mp->backend.shutdown); + DBG("mp=%p", mp); + mp->backend.repack(mp->backend_data, cb, data); +} + EAPI void eina_mempool_gc(Eina_Mempool *mp) { EINA_SAFETY_ON_NULL_RETURN(mp); diff --git a/legacy/eina/src/lib/eina_private.h b/legacy/eina/src/lib/eina_private.h index 2162b47cb3..7e500f5bdf 100644 --- a/legacy/eina/src/lib/eina_private.h +++ b/legacy/eina/src/lib/eina_private.h @@ -94,6 +94,8 @@ #define EINA_MAGIC_SIMPLE_XML_DATA 0x98761261 #define EINA_MAGIC_SIMPLE_XML_ATTRIBUTE 0x98761262 +#define EINA_MAGIC_CLASS 0x9877CB30 + /* undef the following, we want out version */ #undef FREE #define FREE(ptr) \ diff --git a/legacy/eina/src/modules/mp/buddy/eina_buddy.c b/legacy/eina/src/modules/mp/buddy/eina_buddy.c index 6a1ac505be..f402c6fdae 100644 --- a/legacy/eina/src/modules/mp/buddy/eina_buddy.c +++ b/legacy/eina/src/modules/mp/buddy/eina_buddy.c @@ -269,7 +269,8 @@ static Eina_Mempool_Backend _backend = { NULL, /* realloc */ NULL, /* garbage collect */ &_statistics, - &_shutdown + &_shutdown, + NULL /* repack */ }; Eina_Bool buddy_init(void) diff --git a/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c b/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c index be95e600f7..5457b528ca 100644 --- a/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c +++ b/legacy/eina/src/modules/mp/chained_pool/eina_chained_mempool.c @@ -151,6 +151,94 @@ _eina_chained_mp_pool_free(Chained_Pool *p) free(p); } +static int +_eina_chained_mempool_usage_cmp(const Eina_Inlist *l1, const Eina_Inlist *l2) +{ + const Chained_Pool *p1; + const Chained_Pool *p2; + + p1 = EINA_INLIST_CONTAINER_GET(l1, const Chained_Pool); + p2 = EINA_INLIST_CONTAINER_GET(l2, const Chained_Pool); + + return p2->usage - p1->usage; +} + +static void * +_eina_chained_mempool_alloc_in(Chained_Mempool *pool, Chained_Pool *p) +{ + void *mem; + + if (p->last) + { + mem = p->last; + p->last += pool->item_alloc; + if (p->last >= p->limit) + p->last = NULL; + } + else + { +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_DEFINED(p->base, pool->item_alloc); +#endif + // Request a free pointer + mem = eina_trash_pop(&p->base); + } + + // move to end - it just filled up + if (!p->base && !p->last) + pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p)); + + p->usage++; + pool->usage++; + +#ifndef NVALGRIND + VALGRIND_MEMPOOL_ALLOC(pool, mem, pool->item_alloc); +#endif + + return mem; +} + +static Eina_Bool +_eina_chained_mempool_free_in(Chained_Mempool *pool, Chained_Pool *p, void *ptr) +{ + void *pmem; + + // pool mem base + pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool)); + + // is it in pool mem? + if (ptr < pmem) + { +#ifdef DEBUG + INF("%p is inside the private part of %p pool from %p Chained_Mempool (could be the sign of a buffer underrun).", ptr, p, pool); +#endif + return EINA_FALSE; + } + + // freed node points to prev free node + eina_trash_push(&p->base, ptr); + // next free node is now the one we freed + p->usage--; + pool->usage--; + if (p->usage == 0) + { + // free bucket + pool->first = eina_inlist_remove(pool->first, EINA_INLIST_GET(p)); + pool->root = eina_rbtree_inline_remove(pool->root, EINA_RBTREE_GET(p), + _eina_chained_mp_pool_cmp, NULL); + _eina_chained_mp_pool_free(p); + + return EINA_TRUE; + } + else + { + // move to front + pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p)); + } + + return EINA_FALSE; +} + static void * eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size) { @@ -210,28 +298,7 @@ eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size) _eina_chained_mp_pool_cmp, NULL); } - if (p->last) - { - mem = p->last; - p->last += pool->item_alloc; - if (p->last >= p->limit) - p->last = NULL; - } - else - { -#ifndef NVALGRIND - VALGRIND_MAKE_MEM_DEFINED(p->base, pool->item_alloc); -#endif - // Request a free pointer - mem = eina_trash_pop(&p->base); - } - - // move to end - it just filled up - if (!p->base && !p->last) - pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p)); - - p->usage++; - pool->usage++; + mem = _eina_chained_mempool_alloc_in(pool, p); #ifdef EFL_HAVE_THREADS if (_threads_activated) @@ -244,10 +311,6 @@ eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size) } #endif -#ifndef NVALGRIND - VALGRIND_MEMPOOL_ALLOC(pool, mem, pool->item_alloc); -#endif - return mem; } @@ -257,7 +320,6 @@ eina_chained_mempool_free(void *data, void *ptr) Chained_Mempool *pool = data; Eina_Rbtree *r; Chained_Pool *p; - void *pmem; // look 4 pool @@ -290,36 +352,7 @@ eina_chained_mempool_free(void *data, void *ptr) p = EINA_RBTREE_CONTAINER_GET(r, Chained_Pool); - // pool mem base - pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool)); - - // is it in pool mem? - if (ptr < pmem) - { -#ifdef DEBUG - INF("%p is inside the private part of %p pool from %p Chained_Mempool (could be the sign of a buffer underrun).", ptr, p, pool); -#endif - goto on_error; - } - - // freed node points to prev free node - eina_trash_push(&p->base, ptr); - // next free node is now the one we freed - p->usage--; - pool->usage--; - if (p->usage == 0) - { - // free bucket - pool->first = eina_inlist_remove(pool->first, EINA_INLIST_GET(p)); - pool->root = eina_rbtree_inline_remove(pool->root, EINA_RBTREE_GET(p), - _eina_chained_mp_pool_cmp, NULL); - _eina_chained_mp_pool_free(p); - } - else - { - // move to front - pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p)); - } + _eina_chained_mempool_free_in(pool, p, ptr); on_error: #ifndef NVALGRIND @@ -342,6 +375,111 @@ eina_chained_mempool_free(void *data, void *ptr) return; } +static void +eina_chained_mempool_repack(void *data, + Eina_Mempool_Repack_Cb cb, + void *cb_data) +{ + Chained_Mempool *pool = data; + Chained_Pool *start; + Chained_Pool *tail; + + /* FIXME: Improvement - per Chained_Pool lock */ + +#ifdef EFL_HAVE_THREADS + if (_threads_activated) + { +# ifdef EFL_HAVE_POSIX_THREADS + pthread_mutex_lock(&pool->mutex); +# else + WaitForSingleObject(pool->mutex, INFINITE); +# endif + } +#ifdef EFL_DEBUG_THREADS + else + assert(pthread_equal(pool->self, pthread_self())); +#endif +#endif + + pool->first = eina_inlist_sort(pool->first, + (Eina_Compare_Cb) _eina_chained_mempool_usage_cmp); + + /* + idea : remove the almost empty pool at the beginning of the list by + moving data in the last pool with empty slot + */ + tail = EINA_INLIST_CONTAINER_GET(pool->first->last, Chained_Pool); + while (tail && tail->usage == pool->pool_size) + tail = EINA_INLIST_CONTAINER_GET((EINA_INLIST_GET(tail)->prev), Chained_Pool); + + while (tail) + { + unsigned char *src; + unsigned char *dst; + + start = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool); + + if (start == tail || start->usage == pool->pool_size) + break; + + for (src = start->limit - pool->group_size; + src != start->limit; + src += pool->item_alloc) + { + Eina_Bool is_free = EINA_FALSE; + Eina_Bool is_dead; + + /* Do we have something inside that piece of memory */ + if (start->last != NULL && src >= start->last) + { + is_free = EINA_TRUE; + } + else + { + Eina_Trash *over = start->base; + + while (over != NULL && (unsigned char*) over != src) + over = over->next; + + if (over == NULL) + is_free = EINA_TRUE; + } + + if (is_free) continue ; + + /* get a new memory pointer from the latest most occuped pool */ + dst = _eina_chained_mempool_alloc_in(pool, tail); + /* move data from one to another */ + memcpy(dst, src, pool->item_alloc); + /* notify caller */ + cb(dst, src, cb_data); + /* destroy old pointer */ + is_dead = _eina_chained_mempool_free_in(pool, start, src); + + /* search last tail with empty slot */ + while (tail && tail->usage == pool->pool_size) + tail = EINA_INLIST_CONTAINER_GET((EINA_INLIST_GET(tail)->prev), + Chained_Pool); + /* no more free space */ + if (!tail || tail == start) break; + if (is_dead) break; + } + } + + /* FIXME: improvement - reorder pool so that the most used one get in front */ + +#ifdef EFL_HAVE_THREADS + if (_threads_activated) + { +# ifdef EFL_HAVE_POSIX_THREADS + pthread_mutex_unlock(&pool->mutex); +# else + ReleaseMutex(pool->mutex); +# endif + } +#endif +} + static void * eina_chained_mempool_realloc(__UNUSED__ void *data, __UNUSED__ void *element, @@ -451,7 +589,8 @@ static Eina_Mempool_Backend _eina_chained_mp_backend = { &eina_chained_mempool_realloc, NULL, NULL, - &eina_chained_mempool_shutdown + &eina_chained_mempool_shutdown, + &eina_chained_mempool_repack }; Eina_Bool chained_init(void) diff --git a/legacy/eina/src/modules/mp/ememoa_fixed/eina_ememoa_fixed.c b/legacy/eina/src/modules/mp/ememoa_fixed/eina_ememoa_fixed.c index 5b635fb65d..0d02f80bbb 100644 --- a/legacy/eina/src/modules/mp/ememoa_fixed/eina_ememoa_fixed.c +++ b/legacy/eina/src/modules/mp/ememoa_fixed/eina_ememoa_fixed.c @@ -153,7 +153,8 @@ static Eina_Mempool_Backend _eina_ememoa_mp_backend = { .alloc = &eina_ememoa_fixed_malloc, .free = &eina_ememoa_fixed_free, .garbage_collect = &eina_ememoa_fixed_gc, - .statistics = &eina_ememoa_fixed_statistics + .statistics = &eina_ememoa_fixed_statistics, + .repack = NULL }; Eina_Bool ememoa_fixed_init(void) diff --git a/legacy/eina/src/modules/mp/ememoa_unknown/eina_ememoa_unknown.c b/legacy/eina/src/modules/mp/ememoa_unknown/eina_ememoa_unknown.c index 6d505b40b9..56b99f66c9 100644 --- a/legacy/eina/src/modules/mp/ememoa_unknown/eina_ememoa_unknown.c +++ b/legacy/eina/src/modules/mp/ememoa_unknown/eina_ememoa_unknown.c @@ -160,7 +160,8 @@ static Eina_Mempool_Backend _eina_ememoa_unknown_mp_backend = { .alloc = &eina_ememoa_unknown_size_malloc, .free = &eina_ememoa_unknown_size_free, .garbage_collect = &eina_ememoa_unknown_size_gc, - .statistics = &eina_ememoa_unknown_size_statistics + .statistics = &eina_ememoa_unknown_size_statistics, + .repack = NULL }; Eina_Bool ememoa_unknown_init(void) diff --git a/legacy/eina/src/modules/mp/fixed_bitmap/eina_fixed_bitmap.c b/legacy/eina/src/modules/mp/fixed_bitmap/eina_fixed_bitmap.c index bbd49b41d9..e053e15790 100644 --- a/legacy/eina/src/modules/mp/fixed_bitmap/eina_fixed_bitmap.c +++ b/legacy/eina/src/modules/mp/fixed_bitmap/eina_fixed_bitmap.c @@ -247,7 +247,8 @@ static Eina_Mempool_Backend _eina_fixed_bitmap_mp_backend = { &eina_fixed_bitmap_realloc, NULL, NULL, - &eina_fixed_bitmap_shutdown + &eina_fixed_bitmap_shutdown, + NULL }; Eina_Bool fixed_bitmap_init(void) diff --git a/legacy/eina/src/modules/mp/one_big/eina_one_big.c b/legacy/eina/src/modules/mp/one_big/eina_one_big.c index 66fed4daf0..d920fe720a 100644 --- a/legacy/eina/src/modules/mp/one_big/eina_one_big.c +++ b/legacy/eina/src/modules/mp/one_big/eina_one_big.c @@ -368,7 +368,8 @@ static Eina_Mempool_Backend _eina_one_big_mp_backend = { &eina_one_big_realloc, NULL, NULL, - &eina_one_big_shutdown + &eina_one_big_shutdown, + NULL }; Eina_Bool one_big_init(void) diff --git a/legacy/eina/src/modules/mp/pass_through/eina_pass_through.c b/legacy/eina/src/modules/mp/pass_through/eina_pass_through.c index 0acd9787d6..196868ecba 100644 --- a/legacy/eina/src/modules/mp/pass_through/eina_pass_through.c +++ b/legacy/eina/src/modules/mp/pass_through/eina_pass_through.c @@ -67,7 +67,8 @@ static Eina_Mempool_Backend _eina_pass_through_mp_backend = { &eina_pass_through_realloc, NULL, NULL, - &eina_pass_through_shutdown + &eina_pass_through_shutdown, + NULL }; Eina_Bool pass_through_init(void)