diff options
author | Vincent Torri <vincent.torri@gmail.com> | 2012-09-16 10:57:48 +0000 |
---|---|---|
committer | Vincent Torri <vincent.torri@gmail.com> | 2012-09-16 10:57:48 +0000 |
commit | 785f2a6b3a70454ecfe94addc6480ebf20c44c13 (patch) | |
tree | 17a195d2c1f022cd480fd0e0b95be5035ad915e2 /src/modules | |
parent | dfc0331373c3f98df7cb996abc588c7dcf44af0a (diff) | |
download | efl-785f2a6b3a70454ecfe94addc6480ebf20c44c13.tar.gz efl-785f2a6b3a70454ecfe94addc6480ebf20c44c13.tar.xz efl-785f2a6b3a70454ecfe94addc6480ebf20c44c13.zip |
merge : add eina
currently, examples, tests and benchmark are not set. That's the next things i'll do
SVN revision: 76710
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/Makefile.am | 3 | ||||
-rw-r--r-- | src/modules/eina/Makefile.am | 4 | ||||
-rw-r--r-- | src/modules/eina/mp/Makefile.am | 45 | ||||
-rw-r--r-- | src/modules/eina/mp/buddy/Makefile.am | 27 | ||||
-rw-r--r-- | src/modules/eina/mp/buddy/eina_buddy.c | 292 | ||||
-rw-r--r-- | src/modules/eina/mp/chained_pool/Makefile.am | 28 | ||||
-rw-r--r-- | src/modules/eina/mp/chained_pool/eina_chained_mempool.c | 572 | ||||
-rw-r--r-- | src/modules/eina/mp/ememoa_fixed/Makefile.am | 28 | ||||
-rw-r--r-- | src/modules/eina/mp/ememoa_fixed/eina_ememoa_fixed.c | 176 | ||||
-rw-r--r-- | src/modules/eina/mp/ememoa_unknown/Makefile.am | 28 | ||||
-rw-r--r-- | src/modules/eina/mp/ememoa_unknown/eina_ememoa_unknown.c | 182 | ||||
-rw-r--r-- | src/modules/eina/mp/fixed_bitmap/Makefile.am | 27 | ||||
-rw-r--r-- | src/modules/eina/mp/fixed_bitmap/eina_fixed_bitmap.c | 270 | ||||
-rw-r--r-- | src/modules/eina/mp/one_big/Makefile.am | 28 | ||||
-rw-r--r-- | src/modules/eina/mp/one_big/eina_one_big.c | 336 | ||||
-rw-r--r-- | src/modules/eina/mp/pass_through/Makefile.am | 27 | ||||
-rw-r--r-- | src/modules/eina/mp/pass_through/eina_pass_through.c | 90 |
17 files changed, 2163 insertions, 0 deletions
diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am new file mode 100644 index 000000000..b8f642fb7 --- /dev/null +++ b/src/modules/Makefile.am @@ -0,0 +1,3 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = eina diff --git a/src/modules/eina/Makefile.am b/src/modules/eina/Makefile.am new file mode 100644 index 000000000..53e28b7bf --- /dev/null +++ b/src/modules/eina/Makefile.am @@ -0,0 +1,4 @@ +SUBDIRS = mp + +MAINTAINERCLEANFILES = \ +Makefile.in
\ No newline at end of file diff --git a/src/modules/eina/mp/Makefile.am b/src/modules/eina/mp/Makefile.am new file mode 100644 index 000000000..435d57a96 --- /dev/null +++ b/src/modules/eina/mp/Makefile.am @@ -0,0 +1,45 @@ +MAINTAINERCLEANFILES = Makefile.in + +SUBDIRS = + +if EINA_BUILD_BUDDY +if !EINA_STATIC_BUILD_BUDDY +SUBDIRS += buddy +endif +endif + +if EINA_BUILD_CHAINED_POOL +if !EINA_STATIC_BUILD_CHAINED_POOL +SUBDIRS += chained_pool +endif +endif + +if EINA_BUILD_EMEMOA_FIXED +if !EINA_STATIC_BUILD_EMEMOA_FIXED +SUBDIRS += ememoa_fixed +endif +endif + +if EINA_BUILD_EMEMOA_UNKNOWN +if !EINA_STATIC_BUILD_EMEMOA_UNKNOWN +SUBDIRS += ememoa_unknown +endif +endif + +if EINA_BUILD_FIXED_BITMAP +if !EINA_STATIC_BUILD_FIXED_BITMAP +SUBDIRS += fixed_bitmap +endif +endif + +if EINA_BUILD_ONE_BIG +if !EINA_STATIC_BUILD_ONE_BIG +SUBDIRS += one_big +endif +endif + +if EINA_BUILD_PASS_THROUGH +if !EINA_STATIC_BUILD_PASS_THROUGH +SUBDIRS += pass_through +endif +endif diff --git a/src/modules/eina/mp/buddy/Makefile.am b/src/modules/eina/mp/buddy/Makefile.am new file mode 100644 index 000000000..e43db1aa8 --- /dev/null +++ b/src/modules/eina/mp/buddy/Makefile.am @@ -0,0 +1,27 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EFL_EINA_BUILD@ + +controllerdir = $(libdir)/eina/modules/mp/buddy/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_buddy.c + +module_la_CFLAGS = @EINA_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/buddy/eina_buddy.c b/src/modules/eina/mp/buddy/eina_buddy.c new file mode 100644 index 000000000..7d830dbfb --- /dev/null +++ b/src/modules/eina/mp/buddy/eina_buddy.c @@ -0,0 +1,292 @@ +/* EINA - EFL data type library + * Copyright (C) 2009 Jorge Luis Zapata Muga + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +/* + * This is a naive 'buddy' allocator following Knuth's documentation. + * The main difference is that we dont store the block information + * on the block memory itself but on another malloc'd area. + * This is useful for managing memory which isn't as fast as the main + * memory like the video memory + * The algorithm uses an area to store the linked list of blocks. + * Each block size is equal to the minimum allocatable block size for + * the memory pool and the number of blocks is equal to the size of the + * memory pool divided by the block size. + */ +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdio.h> + +#include "eina_types.h" +#include "eina_inlist.h" +#include "eina_module.h" +#include "eina_mempool.h" +#include "eina_private.h" + +typedef struct _Block +{ + EINA_INLIST; + Eina_Bool available : 1; + unsigned short int order : 7; /* final order is order + min_order */ +} Block; + +typedef struct _Buddy +{ + void *heap; /* start address of the heap */ + size_t size; /* total size in bytes of the heap */ + unsigned int min_order; /* minimum size is 1 << min_order */ + unsigned int max_order; /* maximum size is 1 << max_order */ + unsigned int num_order; /* number of orders */ + Eina_Inlist **areas; /* one area per order */ + Block *blocks; /* the allocated block information */ +} Buddy; + +/* get the minimum order greater or equal to size */ +static inline unsigned int _get_order(Buddy *b, size_t size) +{ + unsigned int i; + size_t bytes; + + bytes = 1 << b->min_order; + for (i = 0; bytes < size && i < b->num_order; i++) + { + bytes += bytes; + } + //printf("order for size %d is %d\n", size, i + b->min_order); + return i; +} + +static inline void *_get_offset(Buddy *b, Block *block) +{ + void *ret; + + ret = (char *)b->heap + ((block - &b->blocks[0]) << b->min_order); + return ret; +} + +static void *_init(__UNUSED__ const char *context, + __UNUSED__ const char *options, + va_list args) +{ + Buddy *b; + int i; + size_t bytes; + size_t size; + size_t min_order; + void *heap; + + heap = va_arg(args, void *); + size = va_arg(args, size_t); + min_order = va_arg(args, int); + /* the minimum order we support is 15 (32K) */ + min_order = min_order < 15 ? 15 : min_order; + bytes = 1 << min_order; + for (i = 0; bytes <= size; i++) + { + bytes += bytes; + } + if (!i) + return NULL; + + b = malloc(sizeof(Buddy)); + b->heap = heap; + b->size = size; + b->min_order = min_order; + b->max_order = min_order + i - 1; + b->num_order = i; + b->areas = calloc(b->num_order, sizeof(Eina_Inlist *)); + b->blocks = calloc(1 << (b->num_order - 1), sizeof(Block)); + /* setup the initial free area */ + b->blocks[0].available = EINA_TRUE; + b->areas[b->num_order - 1] = EINA_INLIST_GET(&(b->blocks[0])); + + return b; +} + +static void _shutdown(void *data) +{ + Buddy *b = data; + + free(b->blocks); + free(b->areas); + free(b); +} + +static void _free(void *data, void *element) +{ + Buddy *b = data; + Block *block, *buddy; + size_t offset; + size_t idx; + + offset = (unsigned char *)element - (unsigned char *)b->heap; + if (offset > b->size) + return; + + idx = offset >> b->min_order; + block = &b->blocks[idx]; + + //printf("free %x idx = %d order = %d buddy = %d\n", offset, idx, block->order, idx ^ (1 << block->order)); + /* we should always work with the buddy at right */ + if (idx & (1 << block->order)) + { + Block *left; + + idx = idx ^ (1 << block->order); + left = &b->blocks[idx]; + if (!left->available) + goto end; + else + { + buddy = block; + block = left; + b->areas[block->order] = eina_inlist_remove(b->areas[block->order], + EINA_INLIST_GET(block)); + block->order++; + } + } + +check: + /* already on the last order */ + if (block->order + b->min_order == b->max_order) + { + goto end; /* get the buddy */ + + } + + buddy = &b->blocks[idx ^ (1 << block->order)]; + if (!buddy->available) + { + goto end; /* merge two blocks */ + + } + + b->areas[block->order] = eina_inlist_remove(b->areas[block->order], + EINA_INLIST_GET(buddy)); + block->order++; + goto check; +end: + /* add the block to the free list */ + block->available = EINA_TRUE; + b->areas[block->order] = eina_inlist_append(b->areas[block->order], + EINA_INLIST_GET(block)); +} + +static void *_alloc(void *data, unsigned int size) +{ + Buddy *b = data; + Block *block, *buddy; + unsigned int k, j; + + k = j = _get_order(b, size); + /* get a free list of order k where k <= j <= max_order */ + while ((j < b->num_order) && !b->areas[j]) + j++; + /* check that the order is on our range */ + if (j + b->min_order > b->max_order) + return NULL; + + /* get a free element on this order, if not, go splitting until we find one */ + //printf("getting order %d (%d) for size %d\n", j, k, size); +found: + if (j == k) + { + void *ret; + + block = EINA_INLIST_CONTAINER_GET(b->areas[j], Block); + block->available = EINA_FALSE; + block->order = j; + /* remove the block from the list */ + b->areas[j] = eina_inlist_remove(b->areas[j], EINA_INLIST_GET(block)); + ret = _get_offset(b, block); + + return ret; + } + + block = EINA_INLIST_CONTAINER_GET(b->areas[j], Block); + /* split */ + b->areas[j] = eina_inlist_remove(b->areas[j], EINA_INLIST_GET(block)); + j--; + b->areas[j] = eina_inlist_append(b->areas[j], EINA_INLIST_GET(block)); + buddy = block + (1 << j); + buddy->order = j; + buddy->available = EINA_TRUE; + b->areas[j] = eina_inlist_append(b->areas[j], EINA_INLIST_GET(buddy)); + + goto found; +} + +static void _statistics(void *data) +{ + Buddy *b = data; + unsigned int i; + + printf("Information:\n"); + printf( + "size = %zu, min_order = %d, max_order = %d, num_order = %d, num_blocks = %d (%uKB)\n", + b->size, + b->min_order, + b->max_order, + b->num_order, + 1 << b->num_order, + ((1 << (b->num_order)) * sizeof(Block)) / 1024); + printf("Area dumping:"); + /* iterate over the free lists and dump the maps */ + for (i = 0; i < b->num_order; i++) + { + Block *block; + + printf("\n2^%d:", b->min_order + i); + EINA_INLIST_FOREACH(b->areas[i], block) + { + printf(" %d", (block - &b->blocks[0])); + } + } + printf("\nBlocks dumping:\n"); +} + +static Eina_Mempool_Backend _backend = { + "buddy", + &_init, + &_free, + &_alloc, + NULL, /* realloc */ + NULL, /* garbage collect */ + &_statistics, + &_shutdown, + NULL /* repack */ +}; + +Eina_Bool buddy_init(void) +{ + return eina_mempool_register(&_backend); +} + +void buddy_shutdown(void) +{ + eina_mempool_unregister(&_backend); +} + + +#ifndef EINA_STATIC_BUILD_BUDDY + +EINA_MODULE_INIT(buddy_init); +EINA_MODULE_SHUTDOWN(buddy_shutdown); + +#endif /* ! EINA_STATIC_BUILD_BUDDY */ diff --git a/src/modules/eina/mp/chained_pool/Makefile.am b/src/modules/eina/mp/chained_pool/Makefile.am new file mode 100644 index 000000000..4e9344581 --- /dev/null +++ b/src/modules/eina/mp/chained_pool/Makefile.am @@ -0,0 +1,28 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EFL_EINA_BUILD@ \ +@VALGRIND_CFLAGS@ + +controllerdir = $(libdir)/eina/modules/mp/chained_pool/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_chained_mempool.c + +module_la_CFLAGS = @EINA_CFLAGS@ @EFL_PTHREAD_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version @EFL_PTHREAD_LIBS@ +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/chained_pool/eina_chained_mempool.c b/src/modules/eina/mp/chained_pool/eina_chained_mempool.c new file mode 100644 index 000000000..e56df4cee --- /dev/null +++ b/src/modules/eina/mp/chained_pool/eina_chained_mempool.c @@ -0,0 +1,572 @@ +/* EINA - EFL data type library + * Copyright (C) 2008-2010 Cedric BAIL, Vincent Torri + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#ifdef EFL_HAVE_POSIX_THREADS +#include <pthread.h> + +# ifdef EFL_DEBUG_THREADS +# include <assert.h> +# endif +#endif + +#ifdef EINA_DEBUG_MALLOC +# include <malloc.h> +#endif + +#ifdef EFL_HAVE_WIN32_THREADS +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# undef WIN32_LEAN_AND_MEAN +#endif + +#include "eina_inlist.h" +#include "eina_error.h" +#include "eina_module.h" +#include "eina_mempool.h" +#include "eina_trash.h" +#include "eina_rbtree.h" +#include "eina_lock.h" + +#include "eina_private.h" + +#ifndef NVALGRIND +# include <memcheck.h> +#endif + +#if defined DEBUG || defined EINA_DEBUG_MALLOC +#include <assert.h> +#include "eina_log.h" + +static int _eina_chained_mp_log_dom = -1; + +#ifdef INF +#undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_eina_chained_mp_log_dom, __VA_ARGS__) +#endif + +typedef struct _Chained_Mempool Chained_Mempool; +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; +#ifdef EINA_DEBUG_MALLOC + int minimal_size; +#endif +#ifdef EFL_DEBUG_THREADS + pthread_t self; +#endif + Eina_Lock mutex; +}; + +typedef struct _Chained_Pool Chained_Pool; +struct _Chained_Pool +{ + EINA_INLIST; + EINA_RBTREE; + Eina_Trash *base; + int usage; + + unsigned char *last; + unsigned char *limit; +}; + +static inline Eina_Rbtree_Direction +_eina_chained_mp_pool_cmp(const Eina_Rbtree *left, const Eina_Rbtree *right, __UNUSED__ void *data) +{ + if (left < right) return EINA_RBTREE_LEFT; + return EINA_RBTREE_RIGHT; +} + +static inline int +_eina_chained_mp_pool_key_cmp(const Eina_Rbtree *node, const void *key, + __UNUSED__ int length, __UNUSED__ void *data) +{ + const Chained_Pool *r = EINA_RBTREE_CONTAINER_GET(node, const Chained_Pool); + + if (key > (void *) r->limit) return -1; + if (key < (void *) r) return 1; + return 0; +} + +static inline Chained_Pool * +_eina_chained_mp_pool_new(Chained_Mempool *pool) +{ + Chained_Pool *p; + unsigned char *ptr; + unsigned int alignof; + + eina_error_set(0); + p = malloc(pool->alloc_size); + if (!p) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + +#ifdef EINA_DEBUG_MALLOC + { + size_t sz; + + sz = malloc_usable_size(p); + if (sz - pool->minimal_size > 0) + INF("Just allocated %0.2f%% to much memory in '%s' for one block of size %i that means %i bytes to much.", + ((float)(sz - pool->minimal_size) * 100) / (float) (pool->alloc_size), + pool->name, + pool->alloc_size, + sz - pool->minimal_size); + } +#endif + + alignof = eina_mempool_alignof(sizeof(Chained_Pool)); + ptr = (unsigned char *)p + alignof; + p->usage = 0; + p->base = NULL; + + p->last = ptr; + p->limit = ptr + pool->item_alloc * pool->pool_size; + +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_NOACCESS(ptr, pool->alloc_size - alignof); +#endif + + return p; +} + +static inline void +_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) +{ + Chained_Mempool *pool = data; + Chained_Pool *p = NULL; + void *mem; + + if (!eina_lock_take(&pool->mutex)) + { +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(pool->self, pthread_self())); +#endif + } + + // Either we have some free space in the first one, or there is no free space. + if (pool->first) p = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool); + + // base is not NULL - has a free slot + if (p && !p->base && !p->last) + p = NULL; + +#ifdef DEBUG + if (p == NULL) + EINA_INLIST_FOREACH(pool->first, p) + assert(!p->base && !p->last); +#endif + + // we have reached the end of the list - no free pools + if (!p) + { + p = _eina_chained_mp_pool_new(pool); + if (!p) + { + eina_lock_release(&pool->mutex); + return NULL; + } + + pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(p)); + pool->root = eina_rbtree_inline_insert(pool->root, EINA_RBTREE_GET(p), + _eina_chained_mp_pool_cmp, NULL); + } + + mem = _eina_chained_mempool_alloc_in(pool, p); + + eina_lock_release(&pool->mutex); + + return mem; +} + +static void +eina_chained_mempool_free(void *data, void *ptr) +{ + Chained_Mempool *pool = data; + Eina_Rbtree *r; + Chained_Pool *p; + + // look 4 pool + if (!eina_lock_take(&pool->mutex)) + { +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(pool->self, pthread_self())); +#endif + } + + // searching for the right mempool + r = eina_rbtree_inline_lookup(pool->root, ptr, 0, _eina_chained_mp_pool_key_cmp, NULL); + + // related mempool not found + if (!r) + { +#ifdef DEBUG + INF("%p is not the property of %p Chained_Mempool", ptr, pool); +#endif + goto on_error; + } + + p = EINA_RBTREE_CONTAINER_GET(r, Chained_Pool); + + _eina_chained_mempool_free_in(pool, p, ptr); + + on_error: +#ifndef NVALGRIND + if (ptr) + { + VALGRIND_MEMPOOL_FREE(pool, ptr); + } +#endif + + eina_lock_release(&pool->mutex); + 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 */ + if (!eina_lock_take(&pool->mutex)) + { +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(pool->self, pthread_self())); +#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 */ + eina_lock_release(&pool->mutex); +} + +static void * +eina_chained_mempool_realloc(__UNUSED__ void *data, + __UNUSED__ void *element, + __UNUSED__ unsigned int size) +{ + return NULL; +} + +static void * +eina_chained_mempool_init(const char *context, + __UNUSED__ const char *option, + va_list args) +{ + Chained_Mempool *mp; + int item_size; + size_t length; + + length = context ? strlen(context) + 1 : 0; + + mp = calloc(1, sizeof(Chained_Mempool) + length); + if (!mp) + return NULL; + + item_size = va_arg(args, int); + mp->pool_size = va_arg(args, int); + + if (length) + { + mp->name = (const char *)(mp + 1); + memcpy((char *)mp->name, context, length); + } + +#ifdef EINA_DEBUG_MALLOC + mp->minimal_size = item_size * mp->pool_size + sizeof(Chained_Pool); +#endif + + mp->item_alloc = eina_mempool_alignof(item_size); + mp->group_size = mp->item_alloc * mp->pool_size; + mp->alloc_size = mp->group_size + eina_mempool_alignof(sizeof(Chained_Pool)); + +#ifndef NVALGRIND + VALGRIND_CREATE_MEMPOOL(mp, 0, 1); +#endif + +#ifdef EFL_DEBUG_THREADS + mp->self = pthread_self(); +#endif + + eina_lock_new(&mp->mutex); + + return mp; +} + +static void +eina_chained_mempool_shutdown(void *data) +{ + Chained_Mempool *mp; + + mp = (Chained_Mempool *)data; + + while (mp->first) + { + Chained_Pool *p = (Chained_Pool *)mp->first; + +#ifdef DEBUG + if (p->usage > 0) + INF("Bad news we are destroying not an empty mempool [%s]\n", + mp->name); + +#endif + + mp->first = eina_inlist_remove(mp->first, mp->first); + mp->root = eina_rbtree_inline_remove(mp->root, EINA_RBTREE_GET(p), + _eina_chained_mp_pool_cmp, NULL); + _eina_chained_mp_pool_free(p); + } + +#ifdef DEBUG + if (mp->root) + INF("Bad news, list of pool and rbtree are out of sync for %p !", mp); +#endif + +#ifndef NVALGRIND + VALGRIND_DESTROY_MEMPOOL(mp); +#endif + + eina_lock_free(&mp->mutex); + +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(mp->self, pthread_self())); +#endif + + free(mp); +} + +static Eina_Mempool_Backend _eina_chained_mp_backend = { + "chained_mempool", + &eina_chained_mempool_init, + &eina_chained_mempool_free, + &eina_chained_mempool_malloc, + &eina_chained_mempool_realloc, + NULL, + NULL, + &eina_chained_mempool_shutdown, + &eina_chained_mempool_repack +}; + +Eina_Bool chained_init(void) +{ +#if defined DEBUG || defined EINA_DEBUG_MALLOC + _eina_chained_mp_log_dom = eina_log_domain_register("eina_mempool", + EINA_LOG_COLOR_DEFAULT); + if (_eina_chained_mp_log_dom < 0) + { + EINA_LOG_ERR("Could not register log domain: eina_mempool"); + return EINA_FALSE; + } + +#endif + return eina_mempool_register(&_eina_chained_mp_backend); +} + +void chained_shutdown(void) +{ + eina_mempool_unregister(&_eina_chained_mp_backend); +#if defined DEBUG || defined EINA_DEBUG_MALLOC + eina_log_domain_unregister(_eina_chained_mp_log_dom); + _eina_chained_mp_log_dom = -1; +#endif +} + +#ifndef EINA_STATIC_BUILD_CHAINED_POOL + +EINA_MODULE_INIT(chained_init); +EINA_MODULE_SHUTDOWN(chained_shutdown); + +#endif /* ! EINA_STATIC_BUILD_CHAINED_POOL */ diff --git a/src/modules/eina/mp/ememoa_fixed/Makefile.am b/src/modules/eina/mp/ememoa_fixed/Makefile.am new file mode 100644 index 000000000..50a4115ad --- /dev/null +++ b/src/modules/eina/mp/ememoa_fixed/Makefile.am @@ -0,0 +1,28 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EMEMOA_CFLAGS@ \ +@EFL_EINA_BUILD@ + +controllerdir = $(libdir)/eina/modules/mp/ememoa_fixed/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_ememoa_fixed.c + +module_la_CFLAGS = @EINA_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EMEMOA_LIBS@ @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/ememoa_fixed/eina_ememoa_fixed.c b/src/modules/eina/mp/ememoa_fixed/eina_ememoa_fixed.c new file mode 100644 index 000000000..0d02f80bb --- /dev/null +++ b/src/modules/eina/mp/ememoa_fixed/eina_ememoa_fixed.c @@ -0,0 +1,176 @@ +/* EINA - EFL data type library + * Copyright (C) 2008 Cedric BAIL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <ememoa_mempool_fixed.h> + +#include "eina_inlist.h" +#include "eina_error.h" +#include "eina_module.h" +#include "eina_mempool.h" + +#include "eina_private.h" + +typedef struct _Eina_Ememoa_Fixed_Mempool Eina_Ememoa_Fixed_Mempool; +struct _Eina_Ememoa_Fixed_Mempool +{ + struct ememoa_mempool_desc_s *desc; + int pool; +}; + +static void * +eina_ememoa_fixed_malloc(void *data, __UNUSED__ unsigned int size) +{ + Eina_Ememoa_Fixed_Mempool *efm = data; + + return ememoa_mempool_fixed_pop_object(efm->pool); +} + +static void +eina_ememoa_fixed_free(void *data, void *ptr) +{ + Eina_Ememoa_Fixed_Mempool *efm = data; + + ememoa_mempool_fixed_push_object(efm->pool, ptr); +} + +static void * +eina_ememoa_fixed_realloc(__UNUSED__ void *data, + __UNUSED__ void *element, + __UNUSED__ unsigned int size) +{ + return NULL; +} + +static void +eina_ememoa_fixed_gc(void *data) +{ + Eina_Ememoa_Fixed_Mempool *efm = data; + + ememoa_mempool_fixed_garbage_collect(efm->pool); +} + +static void +eina_ememoa_fixed_statistics(void *data) +{ + Eina_Ememoa_Fixed_Mempool *efm = data; + + ememoa_mempool_fixed_display_statistic(efm->pool); + (void)efm; +} + +static void * +eina_ememoa_fixed_init(const char *context, + __UNUSED__ const char *option, + va_list args) +{ + struct ememoa_mempool_desc_s *desc = NULL; + Eina_Ememoa_Fixed_Mempool *efm = NULL; + Eina_Bool thread_protect; + int context_length; + int item_size; + int pool_size; + + if (context) + { + context_length = strlen(context) + 1; + + desc = calloc(1, sizeof (struct ememoa_mempool_desc_s) + context_length); + if (!desc) + goto on_error; + + desc->name = (char *)(desc + 1); + memcpy((char *)desc->name, context, context_length); + } + + item_size = va_arg(args, int); + pool_size = va_arg(args, int); + thread_protect = va_arg(args, int); + + efm = malloc(sizeof (Eina_Ememoa_Fixed_Mempool)); + if (!efm) + goto on_error; + + efm->desc = desc; + efm->pool = ememoa_mempool_fixed_init( + item_size, + pool_size, + thread_protect ? + EMEMOA_THREAD_PROTECTION : 0, + efm->desc); + if (efm->pool < 0) + goto on_error; + + return efm; + +on_error: + if (desc) + free(desc); + + if (efm) + free(efm); + + return NULL; +} + +static void +eina_ememoa_fixed_shutdown(void *data) +{ + Eina_Ememoa_Fixed_Mempool *efm = data; + + if (efm->desc) + free(efm->desc); + + ememoa_mempool_fixed_clean(efm->pool); + free(efm); +} + +static Eina_Mempool_Backend _eina_ememoa_mp_backend = { + .name = "ememoa_fixed", + .init = &eina_ememoa_fixed_init, + .shutdown = &eina_ememoa_fixed_shutdown, + .realloc = &eina_ememoa_fixed_realloc, + .alloc = &eina_ememoa_fixed_malloc, + .free = &eina_ememoa_fixed_free, + .garbage_collect = &eina_ememoa_fixed_gc, + .statistics = &eina_ememoa_fixed_statistics, + .repack = NULL +}; + +Eina_Bool ememoa_fixed_init(void) +{ + return eina_mempool_register(&_eina_ememoa_mp_backend); +} + +void ememoa_fixed_shutdown(void) +{ + eina_mempool_unregister(&_eina_ememoa_mp_backend); +} + + +#ifndef EINA_STATIC_BUILD_EMEMOA_FIXED + +EINA_MODULE_INIT(ememoa_fixed_init); +EINA_MODULE_SHUTDOWN(ememoa_fixed_shutdown); + +#endif /* ! EINA_STATIC_BUILD_EMEMOA_FIXED */ diff --git a/src/modules/eina/mp/ememoa_unknown/Makefile.am b/src/modules/eina/mp/ememoa_unknown/Makefile.am new file mode 100644 index 000000000..971313711 --- /dev/null +++ b/src/modules/eina/mp/ememoa_unknown/Makefile.am @@ -0,0 +1,28 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EMEMOA_CFLAGS@ \ +@EFL_EINA_BUILD@ + +controllerdir = $(libdir)/eina/modules/mp/ememoa_unknown/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_ememoa_unknown.c + +module_la_CFLAGS = @EINA_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EMEMOA_LIBS@ @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/ememoa_unknown/eina_ememoa_unknown.c b/src/modules/eina/mp/ememoa_unknown/eina_ememoa_unknown.c new file mode 100644 index 000000000..56b99f66c --- /dev/null +++ b/src/modules/eina/mp/ememoa_unknown/eina_ememoa_unknown.c @@ -0,0 +1,182 @@ +/* EINA - EFL data type library + * Copyright (C) 2008 Cedric BAIL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> +#include <ememoa_mempool_fixed.h> +#include <ememoa_mempool_unknown_size.h> + +#include "eina_types.h" +#include "eina_module.h" +#include "eina_private.h" +#include "eina_mempool.h" + +typedef struct _Eina_Ememoa_Unknown_Size_Mempool +Eina_Ememoa_Unknown_Size_Mempool; +struct _Eina_Ememoa_Unknown_Size_Mempool +{ + struct ememoa_mempool_desc_s *desc; + int pool; +}; + +static void * +eina_ememoa_unknown_size_malloc(void *data, unsigned int size) +{ + Eina_Ememoa_Unknown_Size_Mempool *efm = data; + + return ememoa_mempool_unknown_size_pop_object(efm->pool, size); +} + +static void +eina_ememoa_unknown_size_free(void *data, void *ptr) +{ + Eina_Ememoa_Unknown_Size_Mempool *efm = data; + + ememoa_mempool_unknown_size_push_object(efm->pool, ptr); +} + +static void * +eina_ememoa_unknown_size_realloc(void *data, void *element, unsigned int size) +{ + Eina_Ememoa_Unknown_Size_Mempool *efm = data; + + return ememoa_mempool_unknown_size_resize_object(efm->pool, element, size); +} + +static void +eina_ememoa_unknown_size_gc(void *data) +{ + Eina_Ememoa_Unknown_Size_Mempool *efm = data; + + ememoa_mempool_unknown_size_garbage_collect(efm->pool); +} + +static void +eina_ememoa_unknown_size_statistics(void *data) +{ + Eina_Ememoa_Unknown_Size_Mempool *efm = data; + + ememoa_mempool_unknown_size_display_statistic(efm->pool); +} + +static void * +eina_ememoa_unknown_size_init(const char *context, + __UNUSED__ const char *option, + va_list args) +{ + struct ememoa_mempool_desc_s *desc = NULL; + Eina_Ememoa_Unknown_Size_Mempool *efm = NULL; + Eina_Bool thread_protect; + unsigned int *items_map = NULL; + unsigned int items_count; + unsigned int i; + int context_length; + + if (context) + { + context_length = strlen(context) + 1; + + desc = calloc(1, sizeof (struct ememoa_mempool_desc_s) + context_length); + if (!desc) + goto on_error; + + desc->name = (char *)(desc + 1); + memcpy((char *)desc->name, context, context_length); + } + + thread_protect = va_arg(args, int); + items_count = va_arg(args, unsigned int); + + items_map = malloc(sizeof (unsigned int) * 2 * items_count); + + for (i = 0; i < (items_count << 1); ++i) + items_map[i] = va_arg(args, unsigned int); + + efm = malloc(sizeof (Eina_Ememoa_Unknown_Size_Mempool)); + if (!efm) + goto on_error; + + efm->desc = desc; + efm->pool = ememoa_mempool_unknown_size_init( + items_count, + items_map, + thread_protect ? + EMEMOA_THREAD_PROTECTION : 0, + efm->desc); + if (efm->pool < 0) + goto on_error; + + return efm; + +on_error: + if (items_map) + free(items_map); + + if (desc) + free(desc); + + if (efm) + free(efm); + + return NULL; +} + +static void +eina_ememoa_unknown_size_shutdown(void *data) +{ + Eina_Ememoa_Unknown_Size_Mempool *efm = data; + + if (efm->desc) + free(efm->desc); + + ememoa_mempool_unknown_size_clean(efm->pool); + free(efm); +} + +static Eina_Mempool_Backend _eina_ememoa_unknown_mp_backend = { + .name = "ememoa_unknown", + .init = &eina_ememoa_unknown_size_init, + .shutdown = &eina_ememoa_unknown_size_shutdown, + .realloc = &eina_ememoa_unknown_size_realloc, + .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, + .repack = NULL +}; + +Eina_Bool ememoa_unknown_init(void) +{ + return eina_mempool_register(&_eina_ememoa_unknown_mp_backend); +} + +void ememoa_unknown_shutdown(void) +{ + eina_mempool_unregister(&_eina_ememoa_unknown_mp_backend); +} + +#ifndef EINA_STATIC_BUILD_EMEMOA_UNKNOWN + +EINA_MODULE_INIT(ememoa_unknown_init); +EINA_MODULE_SHUTDOWN(ememoa_unknown_shutdown); + +#endif /* ! EINA_STATIC_BUILD_EMEMOA_UNKNOWN */ diff --git a/src/modules/eina/mp/fixed_bitmap/Makefile.am b/src/modules/eina/mp/fixed_bitmap/Makefile.am new file mode 100644 index 000000000..214367600 --- /dev/null +++ b/src/modules/eina/mp/fixed_bitmap/Makefile.am @@ -0,0 +1,27 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EFL_EINA_BUILD@ + +controllerdir = $(libdir)/eina/modules/mp/fixed_bitmap/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_fixed_bitmap.c + +module_la_CFLAGS = @EINA_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/fixed_bitmap/eina_fixed_bitmap.c b/src/modules/eina/mp/fixed_bitmap/eina_fixed_bitmap.c new file mode 100644 index 000000000..e053e1579 --- /dev/null +++ b/src/modules/eina/mp/fixed_bitmap/eina_fixed_bitmap.c @@ -0,0 +1,270 @@ +/* EINA - EFL data type library + * Copyright (C) 2008 Cedric BAIL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifndef _MSC_VER +# include <stdint.h> +#endif +#include <string.h> +#include <assert.h> + +#ifdef HAVE_EVIL +# include <Evil.h> +#endif + +#include "eina_inlist.h" +#include "eina_rbtree.h" +#include "eina_error.h" + +#include "eina_mempool.h" + +#include "eina_private.h" + +typedef struct _Eina_Fixed_Bitmap Eina_Fixed_Bitmap; +typedef struct _Eina_Fixed_Bitmap_Pool Eina_Fixed_Bitmap_Pool; + +struct _Eina_Fixed_Bitmap +{ + Eina_Rbtree *lookup; + Eina_Inlist *head; + + int item_size; +}; + +struct _Eina_Fixed_Bitmap_Pool +{ + EINA_RBTREE; + EINA_INLIST; + + uint32_t bitmask; +}; + +static inline size_t +_eina_rbtree_inlist_delta(void) +{ + Eina_Fixed_Bitmap_Pool tmp; + void *a = &tmp.__rbtree; + void *b = &tmp.__in_list; + + return (char *)a - (char *)b; +} + +static Eina_Rbtree_Direction +_eina_fixed_cmp(const Eina_Rbtree *left, + const Eina_Rbtree *right, + __UNUSED__ void *data) +{ + if (left - right < 0) + return EINA_RBTREE_LEFT; + + return EINA_RBTREE_RIGHT; +} + +static int +_eina_fixed_cmp_key(const Eina_Rbtree *node, + const void *key, + __UNUSED__ int length, + Eina_Fixed_Bitmap *mp) +{ + const void *a = node; + const void *b = key; + ssize_t delta; + ssize_t limit; + + limit = sizeof (Eina_Fixed_Bitmap_Pool) + mp->item_size * 32; + delta = (char *)a - (char *)b; + + if (delta > 0) + return 1; + + if (delta + limit < 0) + return -1; + + return 0; +} + +static void +_eina_fixed_bitmap_pool_free(Eina_Fixed_Bitmap_Pool *pool, + __UNUSED__ void *data) +{ + free(pool); +} + +static void * +eina_fixed_bitmap_malloc(void *data, __UNUSED__ unsigned int size) +{ + Eina_Fixed_Bitmap *mp = data; + Eina_Fixed_Bitmap_Pool *pool = NULL; + void *ptr; + int idx; + + if (mp->head) + { + pool = + (Eina_Fixed_Bitmap_Pool *)((unsigned char *)mp->head + + _eina_rbtree_inlist_delta()); + + if (pool->bitmask == 0) + pool = NULL; + } + + if (!pool) + { + eina_error_set(0); + pool = malloc(sizeof (Eina_Fixed_Bitmap_Pool) + mp->item_size * 32); + if (!pool) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + return NULL; + } + + pool->bitmask = 0xFFFFFFFF; + + mp->head = eina_inlist_prepend(mp->head, EINA_INLIST_GET(pool)); + mp->lookup = eina_rbtree_inline_insert(mp->lookup, EINA_RBTREE_GET( + pool), + EINA_RBTREE_CMP_NODE_CB( + _eina_fixed_cmp), NULL); + } + + idx = ffs(pool->bitmask) - 1; + pool->bitmask &= ~(1 << idx); + ptr = (unsigned char *)(pool + 1) + idx * mp->item_size; + + if (pool->bitmask == 0) + mp->head = eina_inlist_demote(mp->head, EINA_INLIST_GET(pool)); + + return ptr; +} + +static void +eina_fixed_bitmap_free(void *data, void *ptr) +{ + Eina_Fixed_Bitmap *mp = data; + Eina_Fixed_Bitmap_Pool *pool; + void *a; + Eina_Bool push_front = EINA_FALSE; + ssize_t delta; + + pool = (Eina_Fixed_Bitmap_Pool *)eina_rbtree_inline_lookup( + mp->lookup, + ptr, + 0, + EINA_RBTREE_CMP_KEY_CB( + _eina_fixed_cmp_key), + mp); + if (!pool) + return; + + if (pool->bitmask != 0xFFFFFFFF) + push_front = EINA_TRUE; + + a = pool; + delta = + ((char *)ptr - (char *)a - + sizeof (Eina_Fixed_Bitmap_Pool)) / mp->item_size; + + assert(delta >= 0 && delta < 32); + + pool->bitmask |= (1 << (delta & 0x1F)); + + if (pool->bitmask == 0xFFFFFFFF) + { + mp->head = eina_inlist_remove(mp->head, EINA_INLIST_GET(pool)); + mp->lookup = eina_rbtree_inline_remove(mp->lookup, EINA_RBTREE_GET( + pool), + EINA_RBTREE_CMP_NODE_CB( + _eina_fixed_cmp), NULL); + free(pool); + } + else if (push_front) + mp->head = eina_inlist_promote(mp->head, EINA_INLIST_GET(pool)); +} + +static void * +eina_fixed_bitmap_realloc(__UNUSED__ void *data, + __UNUSED__ void *element, + __UNUSED__ unsigned int size) +{ + return NULL; +} + +static void * +eina_fixed_bitmap_init(__UNUSED__ const char *context, + __UNUSED__ const char *option, + va_list args) +{ + Eina_Fixed_Bitmap *mp; + int item_size; + + mp = malloc(sizeof (Eina_Fixed_Bitmap)); + if (!mp) + return NULL; + + item_size = va_arg(args, int); + + mp->item_size = eina_mempool_alignof(item_size); + + mp->lookup = NULL; + mp->head = NULL; + + return mp; +} + +static void +eina_fixed_bitmap_shutdown(void *data) +{ + Eina_Fixed_Bitmap *mp = data; + + eina_rbtree_delete(mp->lookup, + EINA_RBTREE_FREE_CB(_eina_fixed_bitmap_pool_free), NULL); + free(mp); +} + +static Eina_Mempool_Backend _eina_fixed_bitmap_mp_backend = { + "fixed_bitmap", + &eina_fixed_bitmap_init, + &eina_fixed_bitmap_free, + &eina_fixed_bitmap_malloc, + &eina_fixed_bitmap_realloc, + NULL, + NULL, + &eina_fixed_bitmap_shutdown, + NULL +}; + +Eina_Bool fixed_bitmap_init(void) +{ + return eina_mempool_register(&_eina_fixed_bitmap_mp_backend); +} + +void fixed_bitmap_shutdown(void) +{ + eina_mempool_unregister(&_eina_fixed_bitmap_mp_backend); +} + +#ifndef EINA_STATIC_BUILD_FIXED_BITMAP + +EINA_MODULE_INIT(fixed_bitmap_init); +EINA_MODULE_SHUTDOWN(fixed_bitmap_shutdown); + +#endif /* ! EINA_STATIC_BUILD_FIXED_BITMAP */ + diff --git a/src/modules/eina/mp/one_big/Makefile.am b/src/modules/eina/mp/one_big/Makefile.am new file mode 100644 index 000000000..6a5efa531 --- /dev/null +++ b/src/modules/eina/mp/one_big/Makefile.am @@ -0,0 +1,28 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EFL_EINA_BUILD@ \ +@VALGRIND_CFLAGS@ + +controllerdir = $(libdir)/eina/modules/mp/one_big/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_one_big.c + +module_la_CFLAGS = @EINA_CFLAGS@ @EFL_PTHREAD_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version @EFL_PTHREAD_LIBS@ +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/one_big/eina_one_big.c b/src/modules/eina/mp/one_big/eina_one_big.c new file mode 100644 index 000000000..1159378de --- /dev/null +++ b/src/modules/eina/mp/one_big/eina_one_big.c @@ -0,0 +1,336 @@ +/* EINA - EFL data type library + * Copyright (C) 2010 Cedric BAIL, Vincent Torri + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> +#include <string.h> + +#ifdef EFL_HAVE_POSIX_THREADS +# include <pthread.h> +#endif + +#include <assert.h> + +#ifdef EFL_HAVE_WIN32_THREADS +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +# undef WIN32_LEAN_AND_MEAN +#endif + +#include "eina_mempool.h" +#include "eina_trash.h" +#include "eina_inlist.h" +#include "eina_log.h" +#include "eina_lock.h" + +#ifndef NVALGRIND +# include <memcheck.h> +#endif + +#include "eina_private.h" + +#ifdef INF +#undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(_eina_mempool_log_dom, __VA_ARGS__) + +#ifdef WRN +#undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(_eina_one_big_mp_log_dom, __VA_ARGS__) + +static int _eina_one_big_mp_log_dom = -1; + +typedef struct _One_Big One_Big; +struct _One_Big +{ + const char *name; + + int item_size; + + int usage; + int over; + + int served; + int max; + unsigned char *base; + + Eina_Trash *empty; + Eina_Inlist *over_list; + +#ifdef EFL_DEBUG_THREADS + pthread_t self; +#endif + Eina_Lock mutex; +}; + +static void * +eina_one_big_malloc(void *data, __UNUSED__ unsigned int size) +{ + One_Big *pool = data; + unsigned char *mem = NULL; + + if (!eina_lock_take(&pool->mutex)) + { +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(pool->self, pthread_self())); +#endif + } + + if (pool->empty) + { +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_DEFINED(pool->empty, pool->item_size); +#endif + mem = eina_trash_pop(&pool->empty); + pool->usage++; + goto on_exit; + } + + if (!pool->base) + { + pool->base = malloc(pool->item_size * pool->max); + if (!pool->base) + { + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + goto retry_smaller; + } +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_NOACCESS(pool->base, pool->item_size * pool->max); +#endif + } + + if (pool->served < pool->max) + { + mem = pool->base + (pool->served++ *pool->item_size); + pool->usage++; + goto on_exit; + } + + retry_smaller: + eina_error_set(0); + mem = malloc(sizeof(Eina_Inlist) + pool->item_size); + if (!mem) + eina_error_set(EINA_ERROR_OUT_OF_MEMORY); + else + { + pool->over++; + memset(mem, 0, sizeof(Eina_Inlist)); + pool->over_list = eina_inlist_append(pool->over_list, + (Eina_Inlist *)mem); + mem = ((unsigned char *)mem) + sizeof(Eina_Inlist); + } +#ifndef NVALGRIND + VALGRIND_MAKE_MEM_NOACCESS(mem, pool->item_size); +#endif + +on_exit: + eina_lock_release(&pool->mutex); + +#ifndef NVALGRIND + VALGRIND_MEMPOOL_ALLOC(pool, mem, pool->item_size); +#endif + return mem; +} + +static void +eina_one_big_free(void *data, void *ptr) +{ + One_Big *pool = data; + + if (!eina_lock_take(&pool->mutex)) + { +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(pool->self, pthread_self())); +#endif + } + + if ((void *)pool->base <= ptr + && ptr < (void *)(pool->base + (pool->max * pool->item_size))) + { + eina_trash_push(&pool->empty, ptr); + pool->usage--; + } + else + { +#ifndef NDEBUG + Eina_Inlist *it; +#endif + Eina_Inlist *il; + + il = (Eina_Inlist *)(((unsigned char *)ptr) - sizeof(Eina_Inlist)); + +#ifndef NDEBUG + for (it = pool->over_list; it != NULL; it = it->next) + if (it == il) break; + + assert(it != NULL); +#endif + + pool->over_list = eina_inlist_remove(pool->over_list, il); + free(il); + pool->over--; + } + +#ifndef NVALGRIND + VALGRIND_MEMPOOL_FREE(pool, ptr); +#endif + + eina_lock_release(&pool->mutex); +} + +static void * +eina_one_big_realloc(__UNUSED__ void *data, + __UNUSED__ void *element, + __UNUSED__ unsigned int size) +{ + return NULL; +} + +static void * +eina_one_big_init(const char *context, + __UNUSED__ const char *option, + va_list args) +{ + One_Big *pool; + int item_size; + size_t length; + + length = context ? strlen(context) + 1 : 0; + + pool = calloc(1, sizeof (One_Big) + length); + if (!pool) + return NULL; + + item_size = va_arg(args, int); + + pool->item_size = eina_mempool_alignof(item_size); + pool->max = va_arg(args, int); + + if (length) + { + pool->name = (const char *)(pool + 1); + memcpy((char *)pool->name, context, length); + } + +#ifdef EFL_DEBUG_THREADS + pool->self = pthread_self(); +#endif + eina_lock_new(&pool->mutex); + +#ifndef NVALGRIND + VALGRIND_CREATE_MEMPOOL(pool, 0, 1); +#endif + + return pool; +} + +static void +eina_one_big_shutdown(void *data) +{ + One_Big *pool = data; + + if (!pool) return; + if (!eina_lock_take(&pool->mutex)) + { +#ifdef EFL_DEBUG_THREADS + assert(pthread_equal(pool->self, pthread_self())); +#endif + } + + if (pool->over > 0) + { +// FIXME: should we warn here? one_big mempool exceeded its alloc and now +// mempool is cleaning up the mess created. be quiet for now as we were before +// but edje seems to be a big offender at the moment! bad cedric! :) +// WRN( +// "Pool [%s] over by %i. cleaning up for you", +// pool->name, pool->over); + while (pool->over_list) + { + Eina_Inlist *il = pool->over_list; + pool->over_list = eina_inlist_remove(pool->over_list, il); + free(il); + pool->over--; + } + } + if (pool->over > 0) + { + WRN( + "Pool [%s] still over by %i\n", + pool->name, pool->over); + } + +#ifndef NVALGRIND + VALGRIND_DESTROY_MEMPOOL(pool); +#endif + + if (pool->base) free(pool->base); + + eina_lock_release(&pool->mutex); + eina_lock_free(&pool->mutex); + free(pool); +} + + +static Eina_Mempool_Backend _eina_one_big_mp_backend = { + "one_big", + &eina_one_big_init, + &eina_one_big_free, + &eina_one_big_malloc, + &eina_one_big_realloc, + NULL, + NULL, + &eina_one_big_shutdown, + NULL +}; + +Eina_Bool one_big_init(void) +{ +#ifdef DEBUG + _eina_one_big_mp_log_dom = eina_log_domain_register("eina_one_big_mempool", + EINA_LOG_COLOR_DEFAULT); + if (_eina_one_big_mp_log_dom < 0) + { + EINA_LOG_ERR("Could not register log domain: eina_one_big_mempool"); + return EINA_FALSE; + } + +#endif + return eina_mempool_register(&_eina_one_big_mp_backend); +} + +void one_big_shutdown(void) +{ + eina_mempool_unregister(&_eina_one_big_mp_backend); +#ifdef DEBUG + eina_log_domain_unregister(_eina_one_big_mp_log_dom); + _eina_one_big_mp_log_dom = -1; +#endif +} + +#ifndef EINA_STATIC_BUILD_ONE_BIG + +EINA_MODULE_INIT(one_big_init); +EINA_MODULE_SHUTDOWN(one_big_shutdown); + +#endif /* ! EINA_STATIC_BUILD_ONE_BIG */ + diff --git a/src/modules/eina/mp/pass_through/Makefile.am b/src/modules/eina/mp/pass_through/Makefile.am new file mode 100644 index 000000000..6d5f1687e --- /dev/null +++ b/src/modules/eina/mp/pass_through/Makefile.am @@ -0,0 +1,27 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/include/eina \ +-I$(top_builddir)/src/include/eina \ +-I$(top_srcdir)/src/lib/eina \ +-I$(top_builddir)/src/lib/eina \ +@EFL_EINA_BUILD@ + +controllerdir = $(libdir)//eina/modules/mp/pass_through/$(MODULE_ARCH) +controller_LTLIBRARIES = module.la + +module_la_SOURCES = eina_pass_through.c + +module_la_CFLAGS = @EINA_CFLAGS@ +module_la_LIBADD = $(top_builddir)/src/lib/eina/libeina.la @EINA_LIBS@ +module_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -module -avoid-version +module_la_LIBTOOLFLAGS = --tag=disable-static + +install-data-hook: + rm -f $(DESTDIR)$(controllerdir)/$(controller_LTLIBRARIES) +uninstall-hook: + rm -f $(DESTDIR)$(controllerdir)/module.* + +clean-local: + rm -rf *.gcno diff --git a/src/modules/eina/mp/pass_through/eina_pass_through.c b/src/modules/eina/mp/pass_through/eina_pass_through.c new file mode 100644 index 000000000..196868ecb --- /dev/null +++ b/src/modules/eina/mp/pass_through/eina_pass_through.c @@ -0,0 +1,90 @@ +/* EINA - EFL data type library + * Copyright (C) 2008 Cedric BAIL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; + * if not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include <stdlib.h> + +#include "eina_types.h" +#include "eina_module.h" +#include "eina_mempool.h" +#include "eina_private.h" + +static void * +eina_pass_through_malloc(__UNUSED__ void *data, unsigned int size) +{ + return malloc(size); +} + +static void +eina_pass_through_free(__UNUSED__ void *data, void *ptr) +{ + free(ptr); +} + +static void * +eina_pass_through_realloc(__UNUSED__ void *data, void *ptr, unsigned int size) +{ + return realloc(ptr, size); +} + +static void * +eina_pass_through_init(__UNUSED__ const char *context, + __UNUSED__ const char *option, + __UNUSED__ va_list args) +{ + return (void *)0x1; +} + +static void +eina_pass_through_shutdown(__UNUSED__ void *data) +{ +} + + +static Eina_Mempool_Backend _eina_pass_through_mp_backend = { + "pass_through", + &eina_pass_through_init, + &eina_pass_through_free, + &eina_pass_through_malloc, + &eina_pass_through_realloc, + NULL, + NULL, + &eina_pass_through_shutdown, + NULL +}; + +Eina_Bool pass_through_init(void) +{ + return eina_mempool_register(&_eina_pass_through_mp_backend); +} + +void pass_through_shutdown(void) +{ + eina_mempool_unregister(&_eina_pass_through_mp_backend); +} + +#ifndef EINA_STATIC_BUILD_PASS_THROUGH + +EINA_MODULE_INIT(pass_through_init); +EINA_MODULE_SHUTDOWN(pass_through_shutdown); + +#endif /* ! EINA_STATIC_BUILD_PASS_THROUGH */ + |