eina: add eina_mempool_repack.
authorcedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 11 Apr 2011 14:07:42 +0000 (14:07 +0000)
committercedric <cedric@7cbeb6ba-43b4-40fd-8cce-4c39aea84d33>
Mon, 11 Apr 2011 14:07:42 +0000 (14:07 +0000)
WARNING: HIGHLY UNTESTED PIECE OF CODE ! USE IT AT YOUR OWN RISK !

git-svn-id: svn+ssh://svn.enlightenment.org/var/svn/e/trunk/eina@58554 7cbeb6ba-43b4-40fd-8cce-4c39aea84d33

12 files changed:
ChangeLog
src/include/eina_inline_mempool.x
src/include/eina_mempool.h
src/lib/eina_mempool.c
src/lib/eina_private.h
src/modules/mp/buddy/eina_buddy.c
src/modules/mp/chained_pool/eina_chained_mempool.c
src/modules/mp/ememoa_fixed/eina_ememoa_fixed.c
src/modules/mp/ememoa_unknown/eina_ememoa_unknown.c
src/modules/mp/fixed_bitmap/eina_fixed_bitmap.c
src/modules/mp/one_big/eina_one_big.c
src/modules/mp/pass_through/eina_pass_through.c

index f3c3478..ccfa402 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -45,3 +45,4 @@
 2011-05-11  Cedric Bail
 
        * Add eina_inlist_sort.
+       * Add eina_mempool_repack.
index 3f44b90..72e70fe 100644 (file)
@@ -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
index e30efd2..c6c0aa7 100644 (file)
@@ -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);
 
index 7e30264..ddeabca 100644 (file)
@@ -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);
index 2162b47..7e500f5 100644 (file)
@@ -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)                              \
index 6a1ac50..f402c6f 100644 (file)
@@ -269,7 +269,8 @@ static Eina_Mempool_Backend _backend = {
    NULL, /* realloc */
    NULL, /* garbage collect */
    &_statistics,
-   &_shutdown
+   &_shutdown,
+   NULL /* repack */
 };
 
 Eina_Bool buddy_init(void)
index be95e60..5457b52 100644 (file)
@@ -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,44 +352,121 @@ 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));
+   _eina_chained_mempool_free_in(pool, p, ptr);
 
-   // is it in pool mem?
-   if (ptr < pmem)
+ on_error:
+#ifndef NVALGRIND
+   if (ptr)
      {
-#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;
+        VALGRIND_MEMPOOL_FREE(pool, ptr);
      }
+#endif
 
-   // 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)
+#ifdef EFL_HAVE_THREADS
+   if (_threads_activated)
      {
-        // 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);
+# ifdef EFL_HAVE_POSIX_THREADS
+        pthread_mutex_unlock(&pool->mutex);
+# else
+        ReleaseMutex(pool->mutex);
+# endif
      }
-   else
+#endif
+   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)
      {
-        // move to front
-        pool->first = eina_inlist_promote(pool->first, EINA_INLIST_GET(p));
+# 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
 
- on_error:
-#ifndef NVALGRIND
-   if (ptr)
+   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)
      {
-        VALGRIND_MEMPOOL_FREE(pool, ptr);
+       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;
+        }
      }
-#endif
+
+   /* FIXME: improvement - reorder pool so that the most used one get in front */
 
 #ifdef EFL_HAVE_THREADS
    if (_threads_activated)
@@ -339,7 +478,6 @@ eina_chained_mempool_free(void *data, void *ptr)
 # endif
      }
 #endif
-   return;
 }
 
 static void *
@@ -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)
index 5b635fb..0d02f80 100644 (file)
@@ -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)
index 6d505b4..56b99f6 100644 (file)
@@ -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)
index bbd49b4..e053e15 100644 (file)
@@ -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)
index 66fed4d..d920fe7 100644 (file)
@@ -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)
index 0acd978..196868e 100644 (file)
@@ -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)