2008-08-06 11:15:24 -07:00
|
|
|
/* EINA - EFL data type library
|
2010-07-26 08:52:43 -07:00
|
|
|
* Copyright (C) 2008-2010 Cedric BAIL, Vincent Torri
|
2008-08-06 11:15:24 -07:00
|
|
|
*
|
|
|
|
* 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/>.
|
|
|
|
*/
|
2008-07-31 08:11:05 -07:00
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2010-07-13 06:51:00 -07:00
|
|
|
#ifdef EFL_HAVE_POSIX_THREADS
|
2009-02-17 06:18:14 -08:00
|
|
|
#include <pthread.h>
|
2010-10-13 09:30:22 -07:00
|
|
|
|
|
|
|
# ifdef EFL_DEBUG_THREADS
|
|
|
|
# include <assert.h>
|
|
|
|
# endif
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
|
|
|
|
2012-01-18 09:47:05 -08:00
|
|
|
#ifdef EINA_DEBUG_MALLOC
|
|
|
|
# include <malloc.h>
|
|
|
|
#endif
|
|
|
|
|
2010-07-13 06:51:00 -07:00
|
|
|
#ifdef EFL_HAVE_WIN32_THREADS
|
|
|
|
# define WIN32_LEAN_AND_MEAN
|
|
|
|
# include <windows.h>
|
|
|
|
# undef WIN32_LEAN_AND_MEAN
|
|
|
|
#endif
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
#include "eina_inlist.h"
|
|
|
|
#include "eina_error.h"
|
2008-08-18 01:18:16 -07:00
|
|
|
#include "eina_module.h"
|
2008-09-18 07:22:48 -07:00
|
|
|
#include "eina_mempool.h"
|
2009-07-15 06:13:52 -07:00
|
|
|
#include "eina_trash.h"
|
2011-02-04 06:03:18 -08:00
|
|
|
#include "eina_rbtree.h"
|
2011-04-24 08:54:09 -07:00
|
|
|
#include "eina_lock.h"
|
2008-07-31 08:11:05 -07:00
|
|
|
|
|
|
|
#include "eina_private.h"
|
|
|
|
|
Make valgrind know about eina mempools.
Because mempools generally allocate a big memory area and distribute chunks of
that area to the users, valgrind can not know about logical invalid access. By
using some valgrind macros we can tell valgrind about mempools and which area
can be accessed or not.
To start with I have just done valgrind integration on chained mempool but soon
it will be done for one_big too.
The code below is an example on which valgrind wouldn't complain without this
patch:
@code
#include <Eina.h>
int
main(int argc, char *argv[])
{
int i, *pool[4];
Eina_Mempool *mp;
eina_init();
mp = eina_mempool_add("chained_mempool", "test", NULL, sizeof(int), 4);
for (i = 0; i < 4; i++) {
pool[i] = eina_mempool_malloc(mp, sizeof(int));
*pool[i] = i;
}
printf("Valid mp pointer: pool[0] = %d\n", *pool[0]);
eina_mempool_free(mp, pool[0]);
printf("Freed mp pointer: pool[0] = %d\n", *pool[0]);
for (i = 1; i < 4; i++)
eina_mempool_free(mp, pool[i]);
eina_mempool_del(mp);
eina_shutdown();
return 0;
}
@endcode
SVN revision: 53405
2010-10-14 08:18:15 -07:00
|
|
|
#ifndef NVALGRIND
|
|
|
|
# include <valgrind/memcheck.h>
|
|
|
|
#endif
|
|
|
|
|
2012-01-18 09:47:05 -08:00
|
|
|
#if defined DEBUG || defined EINA_DEBUG_MALLOC
|
2011-02-04 06:03:18 -08:00
|
|
|
#include <assert.h>
|
2010-02-11 13:20:52 -08:00
|
|
|
#include "eina_log.h"
|
|
|
|
|
2010-10-23 13:57:08 -07:00
|
|
|
static int _eina_chained_mp_log_dom = -1;
|
2010-02-11 13:20:52 -08:00
|
|
|
|
|
|
|
#ifdef INF
|
|
|
|
#undef INF
|
|
|
|
#endif
|
2010-10-23 13:57:08 -07:00
|
|
|
#define INF(...) EINA_LOG_DOM_INFO(_eina_chained_mp_log_dom, __VA_ARGS__)
|
2010-02-11 13:20:52 -08:00
|
|
|
#endif
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
typedef struct _Chained_Mempool Chained_Mempool;
|
|
|
|
struct _Chained_Mempool
|
|
|
|
{
|
2010-07-27 19:37:05 -07:00
|
|
|
Eina_Inlist *first;
|
2011-02-04 06:03:18 -08:00
|
|
|
Eina_Rbtree *root;
|
2008-07-31 08:11:05 -07:00
|
|
|
const char *name;
|
2010-07-26 08:52:43 -07:00
|
|
|
int item_alloc;
|
2008-07-31 08:11:05 -07:00
|
|
|
int pool_size;
|
2010-07-30 01:26:34 -07:00
|
|
|
int alloc_size;
|
|
|
|
int group_size;
|
2008-07-31 08:11:05 -07:00
|
|
|
int usage;
|
2012-01-18 09:47:05 -08:00
|
|
|
#ifdef EINA_DEBUG_MALLOC
|
|
|
|
int minimal_size;
|
|
|
|
#endif
|
2011-04-24 08:54:09 -07:00
|
|
|
#ifdef EFL_DEBUG_THREADS
|
2010-10-13 09:30:22 -07:00
|
|
|
pthread_t self;
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
2011-04-24 08:54:09 -07:00
|
|
|
Eina_Lock mutex;
|
2008-07-31 08:11:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef struct _Chained_Pool Chained_Pool;
|
|
|
|
struct _Chained_Pool
|
|
|
|
{
|
2008-09-18 07:22:48 -07:00
|
|
|
EINA_INLIST;
|
2011-02-04 06:03:18 -08:00
|
|
|
EINA_RBTREE;
|
2009-07-15 06:13:52 -07:00
|
|
|
Eina_Trash *base;
|
2008-07-31 08:11:05 -07:00
|
|
|
int usage;
|
2010-10-12 09:53:30 -07:00
|
|
|
|
|
|
|
unsigned char *last;
|
|
|
|
unsigned char *limit;
|
2008-07-31 08:11:05 -07:00
|
|
|
};
|
|
|
|
|
2011-02-04 06:03:18 -08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-10-01 09:30:30 -07:00
|
|
|
static inline Chained_Pool *
|
2008-07-31 08:11:05 -07:00
|
|
|
_eina_chained_mp_pool_new(Chained_Mempool *pool)
|
|
|
|
{
|
|
|
|
Chained_Pool *p;
|
2009-07-15 06:13:52 -07:00
|
|
|
unsigned char *ptr;
|
Make valgrind know about eina mempools.
Because mempools generally allocate a big memory area and distribute chunks of
that area to the users, valgrind can not know about logical invalid access. By
using some valgrind macros we can tell valgrind about mempools and which area
can be accessed or not.
To start with I have just done valgrind integration on chained mempool but soon
it will be done for one_big too.
The code below is an example on which valgrind wouldn't complain without this
patch:
@code
#include <Eina.h>
int
main(int argc, char *argv[])
{
int i, *pool[4];
Eina_Mempool *mp;
eina_init();
mp = eina_mempool_add("chained_mempool", "test", NULL, sizeof(int), 4);
for (i = 0; i < 4; i++) {
pool[i] = eina_mempool_malloc(mp, sizeof(int));
*pool[i] = i;
}
printf("Valid mp pointer: pool[0] = %d\n", *pool[0]);
eina_mempool_free(mp, pool[0]);
printf("Freed mp pointer: pool[0] = %d\n", *pool[0]);
for (i = 1; i < 4; i++)
eina_mempool_free(mp, pool[i]);
eina_mempool_del(mp);
eina_shutdown();
return 0;
}
@endcode
SVN revision: 53405
2010-10-14 08:18:15 -07:00
|
|
|
unsigned int alignof;
|
2010-07-26 08:52:43 -07:00
|
|
|
|
2010-07-30 01:26:34 -07:00
|
|
|
eina_error_set(0);
|
|
|
|
p = malloc(pool->alloc_size);
|
2010-07-26 08:52:43 -07:00
|
|
|
if (!p)
|
|
|
|
{
|
2010-07-27 19:37:05 -07:00
|
|
|
eina_error_set(EINA_ERROR_OUT_OF_MEMORY);
|
|
|
|
return NULL;
|
2010-07-26 08:52:43 -07:00
|
|
|
}
|
2008-07-31 08:11:05 -07:00
|
|
|
|
2012-01-18 09:47:05 -08:00
|
|
|
#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
|
|
|
|
|
Make valgrind know about eina mempools.
Because mempools generally allocate a big memory area and distribute chunks of
that area to the users, valgrind can not know about logical invalid access. By
using some valgrind macros we can tell valgrind about mempools and which area
can be accessed or not.
To start with I have just done valgrind integration on chained mempool but soon
it will be done for one_big too.
The code below is an example on which valgrind wouldn't complain without this
patch:
@code
#include <Eina.h>
int
main(int argc, char *argv[])
{
int i, *pool[4];
Eina_Mempool *mp;
eina_init();
mp = eina_mempool_add("chained_mempool", "test", NULL, sizeof(int), 4);
for (i = 0; i < 4; i++) {
pool[i] = eina_mempool_malloc(mp, sizeof(int));
*pool[i] = i;
}
printf("Valid mp pointer: pool[0] = %d\n", *pool[0]);
eina_mempool_free(mp, pool[0]);
printf("Freed mp pointer: pool[0] = %d\n", *pool[0]);
for (i = 1; i < 4; i++)
eina_mempool_free(mp, pool[i]);
eina_mempool_del(mp);
eina_shutdown();
return 0;
}
@endcode
SVN revision: 53405
2010-10-14 08:18:15 -07:00
|
|
|
alignof = eina_mempool_alignof(sizeof(Chained_Pool));
|
|
|
|
ptr = (unsigned char *)p + alignof;
|
2008-07-31 08:11:05 -07:00
|
|
|
p->usage = 0;
|
2009-07-15 06:13:52 -07:00
|
|
|
p->base = NULL;
|
2010-10-12 09:53:30 -07:00
|
|
|
|
|
|
|
p->last = ptr;
|
|
|
|
p->limit = ptr + pool->item_alloc * pool->pool_size;
|
Make valgrind know about eina mempools.
Because mempools generally allocate a big memory area and distribute chunks of
that area to the users, valgrind can not know about logical invalid access. By
using some valgrind macros we can tell valgrind about mempools and which area
can be accessed or not.
To start with I have just done valgrind integration on chained mempool but soon
it will be done for one_big too.
The code below is an example on which valgrind wouldn't complain without this
patch:
@code
#include <Eina.h>
int
main(int argc, char *argv[])
{
int i, *pool[4];
Eina_Mempool *mp;
eina_init();
mp = eina_mempool_add("chained_mempool", "test", NULL, sizeof(int), 4);
for (i = 0; i < 4; i++) {
pool[i] = eina_mempool_malloc(mp, sizeof(int));
*pool[i] = i;
}
printf("Valid mp pointer: pool[0] = %d\n", *pool[0]);
eina_mempool_free(mp, pool[0]);
printf("Freed mp pointer: pool[0] = %d\n", *pool[0]);
for (i = 1; i < 4; i++)
eina_mempool_free(mp, pool[i]);
eina_mempool_del(mp);
eina_shutdown();
return 0;
}
@endcode
SVN revision: 53405
2010-10-14 08:18:15 -07:00
|
|
|
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ptr, pool->alloc_size - alignof);
|
|
|
|
#endif
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2008-10-01 09:30:30 -07:00
|
|
|
static inline void
|
2008-07-31 08:11:05 -07:00
|
|
|
_eina_chained_mp_pool_free(Chained_Pool *p)
|
|
|
|
{
|
|
|
|
free(p);
|
|
|
|
}
|
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
static void *
|
|
|
|
eina_chained_mempool_malloc(void *data, __UNUSED__ unsigned int size)
|
|
|
|
{
|
|
|
|
Chained_Mempool *pool = data;
|
2008-09-17 08:18:35 -07:00
|
|
|
Chained_Pool *p = NULL;
|
2008-07-31 08:11:05 -07:00
|
|
|
void *mem;
|
|
|
|
|
2011-04-24 09:49:48 -07:00
|
|
|
if (!eina_lock_take(&pool->mutex))
|
2010-10-12 09:53:30 -07:00
|
|
|
{
|
2010-10-13 08:35:56 -07:00
|
|
|
#ifdef EFL_DEBUG_THREADS
|
2011-04-24 08:54:09 -07:00
|
|
|
assert(pthread_equal(pool->self, pthread_self()));
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
2011-04-24 08:54:09 -07:00
|
|
|
}
|
2009-02-17 06:18:14 -08:00
|
|
|
|
2011-02-04 06:03:18 -08:00
|
|
|
// Either we have some free space in the first one, or there is no free space.
|
2011-04-11 10:28:16 -07:00
|
|
|
if (pool->first) p = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool);
|
2011-02-04 06:03:18 -08:00
|
|
|
|
|
|
|
// 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
|
2009-02-17 06:18:14 -08:00
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
// we have reached the end of the list - no free pools
|
|
|
|
if (!p)
|
|
|
|
{
|
2010-07-27 19:37:05 -07:00
|
|
|
p = _eina_chained_mp_pool_new(pool);
|
|
|
|
if (!p)
|
|
|
|
{
|
2011-04-24 09:49:48 -07:00
|
|
|
eina_lock_release(&pool->mutex);
|
2010-07-27 19:37:05 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(p));
|
2011-02-04 06:03:18 -08:00
|
|
|
pool->root = eina_rbtree_inline_insert(pool->root, EINA_RBTREE_GET(p),
|
|
|
|
_eina_chained_mp_pool_cmp, NULL);
|
2008-07-31 08:11:05 -07:00
|
|
|
}
|
2010-07-27 19:37:05 -07:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
mem = _eina_chained_mempool_alloc_in(pool, p);
|
2009-02-17 06:18:14 -08:00
|
|
|
|
2011-04-24 09:49:48 -07:00
|
|
|
eina_lock_release(&pool->mutex);
|
2010-07-13 06:51:00 -07:00
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
eina_chained_mempool_free(void *data, void *ptr)
|
|
|
|
{
|
|
|
|
Chained_Mempool *pool = data;
|
2011-02-04 06:03:18 -08:00
|
|
|
Eina_Rbtree *r;
|
2008-07-31 08:11:05 -07:00
|
|
|
Chained_Pool *p;
|
|
|
|
|
|
|
|
// look 4 pool
|
2011-04-24 09:49:48 -07:00
|
|
|
if (!eina_lock_take(&pool->mutex))
|
2010-10-12 09:53:30 -07:00
|
|
|
{
|
2010-10-13 08:35:56 -07:00
|
|
|
#ifdef EFL_DEBUG_THREADS
|
2011-04-24 08:54:09 -07:00
|
|
|
assert(pthread_equal(pool->self, pthread_self()));
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
2011-04-24 08:54:09 -07:00
|
|
|
}
|
2009-02-17 06:18:14 -08:00
|
|
|
|
2011-02-04 06:03:18 -08:00
|
|
|
// 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);
|
2009-02-17 06:18:14 -08:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
_eina_chained_mempool_free_in(pool, p, ptr);
|
2011-02-04 06:03:18 -08:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
on_error:
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
if (ptr)
|
2011-02-04 06:03:18 -08:00
|
|
|
{
|
2011-04-11 07:07:42 -07:00
|
|
|
VALGRIND_MEMPOOL_FREE(pool, ptr);
|
2011-02-04 06:03:18 -08:00
|
|
|
}
|
2011-04-11 07:07:42 -07:00
|
|
|
#endif
|
2011-02-04 06:03:18 -08:00
|
|
|
|
2011-04-24 09:49:48 -07:00
|
|
|
eina_lock_release(&pool->mutex);
|
2011-04-11 07:07:42 -07:00
|
|
|
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 */
|
2011-04-24 09:49:48 -07:00
|
|
|
if (!eina_lock_take(&pool->mutex))
|
2011-02-04 06:03:18 -08:00
|
|
|
{
|
2011-04-11 07:07:42 -07:00
|
|
|
#ifdef EFL_DEBUG_THREADS
|
2011-04-24 08:54:09 -07:00
|
|
|
assert(pthread_equal(pool->self, pthread_self()));
|
2011-04-11 07:07:42 -07:00
|
|
|
#endif
|
2011-04-24 08:54:09 -07:00
|
|
|
}
|
2011-02-04 06:03:18 -08:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
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)
|
2010-10-27 20:46:52 -07:00
|
|
|
{
|
2011-04-11 07:07:42 -07:00
|
|
|
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;
|
|
|
|
}
|
2010-10-27 20:46:52 -07:00
|
|
|
}
|
2011-04-11 07:07:42 -07:00
|
|
|
|
|
|
|
/* FIXME: improvement - reorder pool so that the most used one get in front */
|
2011-04-24 09:49:48 -07:00
|
|
|
eina_lock_release(&pool->mutex);
|
2008-07-31 08:11:05 -07:00
|
|
|
}
|
|
|
|
|
2010-07-27 19:37:05 -07:00
|
|
|
static void *
|
|
|
|
eina_chained_mempool_realloc(__UNUSED__ void *data,
|
|
|
|
__UNUSED__ void *element,
|
|
|
|
__UNUSED__ unsigned int size)
|
2008-07-31 08:11:05 -07:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-27 19:37:05 -07:00
|
|
|
static void *
|
|
|
|
eina_chained_mempool_init(const char *context,
|
|
|
|
__UNUSED__ const char *option,
|
|
|
|
va_list args)
|
2008-07-31 08:11:05 -07:00
|
|
|
{
|
|
|
|
Chained_Mempool *mp;
|
2010-07-30 01:26:34 -07:00
|
|
|
int item_size;
|
2009-09-16 06:38:21 -07:00
|
|
|
size_t length;
|
2008-07-31 08:11:05 -07:00
|
|
|
|
|
|
|
length = context ? strlen(context) + 1 : 0;
|
|
|
|
|
|
|
|
mp = calloc(1, sizeof(Chained_Mempool) + length);
|
2010-07-27 19:37:05 -07:00
|
|
|
if (!mp)
|
|
|
|
return NULL;
|
2008-07-31 08:11:05 -07:00
|
|
|
|
2010-07-30 01:26:34 -07:00
|
|
|
item_size = va_arg(args, int);
|
2008-07-31 08:11:05 -07:00
|
|
|
mp->pool_size = va_arg(args, int);
|
|
|
|
|
|
|
|
if (length)
|
|
|
|
{
|
2010-07-27 19:37:05 -07:00
|
|
|
mp->name = (const char *)(mp + 1);
|
|
|
|
memcpy((char *)mp->name, context, length);
|
2008-07-31 08:11:05 -07:00
|
|
|
}
|
|
|
|
|
2012-01-18 09:47:05 -08:00
|
|
|
#ifdef EINA_DEBUG_MALLOC
|
|
|
|
mp->minimal_size = item_size * mp->pool_size + sizeof(Chained_Pool);
|
|
|
|
#endif
|
|
|
|
|
2010-07-30 01:26:34 -07:00
|
|
|
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));
|
2010-07-26 08:52:43 -07:00
|
|
|
|
Make valgrind know about eina mempools.
Because mempools generally allocate a big memory area and distribute chunks of
that area to the users, valgrind can not know about logical invalid access. By
using some valgrind macros we can tell valgrind about mempools and which area
can be accessed or not.
To start with I have just done valgrind integration on chained mempool but soon
it will be done for one_big too.
The code below is an example on which valgrind wouldn't complain without this
patch:
@code
#include <Eina.h>
int
main(int argc, char *argv[])
{
int i, *pool[4];
Eina_Mempool *mp;
eina_init();
mp = eina_mempool_add("chained_mempool", "test", NULL, sizeof(int), 4);
for (i = 0; i < 4; i++) {
pool[i] = eina_mempool_malloc(mp, sizeof(int));
*pool[i] = i;
}
printf("Valid mp pointer: pool[0] = %d\n", *pool[0]);
eina_mempool_free(mp, pool[0]);
printf("Freed mp pointer: pool[0] = %d\n", *pool[0]);
for (i = 1; i < 4; i++)
eina_mempool_free(mp, pool[i]);
eina_mempool_del(mp);
eina_shutdown();
return 0;
}
@endcode
SVN revision: 53405
2010-10-14 08:18:15 -07:00
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_CREATE_MEMPOOL(mp, 0, 1);
|
|
|
|
#endif
|
|
|
|
|
2011-04-24 08:54:09 -07:00
|
|
|
#ifdef EFL_DEBUG_THREADS
|
2010-10-13 09:30:22 -07:00
|
|
|
mp->self = pthread_self();
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
|
|
|
|
2011-04-24 08:54:09 -07:00
|
|
|
eina_lock_new(&mp->mutex);
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
return mp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
eina_chained_mempool_shutdown(void *data)
|
|
|
|
{
|
|
|
|
Chained_Mempool *mp;
|
|
|
|
|
2010-07-27 19:37:05 -07:00
|
|
|
mp = (Chained_Mempool *)data;
|
2008-07-31 08:11:05 -07:00
|
|
|
|
|
|
|
while (mp->first)
|
|
|
|
{
|
2010-07-27 19:37:05 -07:00
|
|
|
Chained_Pool *p = (Chained_Pool *)mp->first;
|
2008-07-31 08:11:05 -07:00
|
|
|
|
|
|
|
#ifdef DEBUG
|
2010-07-27 19:37:05 -07:00
|
|
|
if (p->usage > 0)
|
|
|
|
INF("Bad news we are destroying not an empty mempool [%s]\n",
|
|
|
|
mp->name);
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
#endif
|
|
|
|
|
2010-07-27 19:37:05 -07:00
|
|
|
mp->first = eina_inlist_remove(mp->first, mp->first);
|
2011-02-04 06:03:18 -08:00
|
|
|
mp->root = eina_rbtree_inline_remove(mp->root, EINA_RBTREE_GET(p),
|
|
|
|
_eina_chained_mp_pool_cmp, NULL);
|
2010-07-27 19:37:05 -07:00
|
|
|
_eina_chained_mp_pool_free(p);
|
2008-07-31 08:11:05 -07:00
|
|
|
}
|
|
|
|
|
2011-02-04 06:03:18 -08:00
|
|
|
#ifdef DEBUG
|
|
|
|
if (mp->root)
|
|
|
|
INF("Bad news, list of pool and rbtree are out of sync for %p !", mp);
|
|
|
|
#endif
|
|
|
|
|
Make valgrind know about eina mempools.
Because mempools generally allocate a big memory area and distribute chunks of
that area to the users, valgrind can not know about logical invalid access. By
using some valgrind macros we can tell valgrind about mempools and which area
can be accessed or not.
To start with I have just done valgrind integration on chained mempool but soon
it will be done for one_big too.
The code below is an example on which valgrind wouldn't complain without this
patch:
@code
#include <Eina.h>
int
main(int argc, char *argv[])
{
int i, *pool[4];
Eina_Mempool *mp;
eina_init();
mp = eina_mempool_add("chained_mempool", "test", NULL, sizeof(int), 4);
for (i = 0; i < 4; i++) {
pool[i] = eina_mempool_malloc(mp, sizeof(int));
*pool[i] = i;
}
printf("Valid mp pointer: pool[0] = %d\n", *pool[0]);
eina_mempool_free(mp, pool[0]);
printf("Freed mp pointer: pool[0] = %d\n", *pool[0]);
for (i = 1; i < 4; i++)
eina_mempool_free(mp, pool[i]);
eina_mempool_del(mp);
eina_shutdown();
return 0;
}
@endcode
SVN revision: 53405
2010-10-14 08:18:15 -07:00
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_DESTROY_MEMPOOL(mp);
|
|
|
|
#endif
|
|
|
|
|
2011-04-24 09:49:48 -07:00
|
|
|
eina_lock_free(&mp->mutex);
|
2011-04-24 08:54:09 -07:00
|
|
|
|
|
|
|
#ifdef EFL_DEBUG_THREADS
|
2010-10-14 07:17:48 -07:00
|
|
|
assert(pthread_equal(mp->self, pthread_self()));
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
|
|
|
|
2008-07-31 08:11:05 -07:00
|
|
|
free(mp);
|
|
|
|
}
|
|
|
|
|
2009-09-06 22:54:42 -07:00
|
|
|
static Eina_Mempool_Backend _eina_chained_mp_backend = {
|
2009-09-16 06:38:21 -07:00
|
|
|
"chained_mempool",
|
|
|
|
&eina_chained_mempool_init,
|
|
|
|
&eina_chained_mempool_free,
|
|
|
|
&eina_chained_mempool_malloc,
|
|
|
|
&eina_chained_mempool_realloc,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
2011-04-11 07:07:42 -07:00
|
|
|
&eina_chained_mempool_shutdown,
|
|
|
|
&eina_chained_mempool_repack
|
2008-07-31 08:11:05 -07:00
|
|
|
};
|
2008-08-18 01:18:16 -07:00
|
|
|
|
2008-09-24 05:55:31 -07:00
|
|
|
Eina_Bool chained_init(void)
|
|
|
|
{
|
2012-01-18 09:47:05 -08:00
|
|
|
#if defined DEBUG || defined EINA_DEBUG_MALLOC
|
2010-10-23 13:57:08 -07:00
|
|
|
_eina_chained_mp_log_dom = eina_log_domain_register("eina_mempool",
|
|
|
|
EINA_LOG_COLOR_DEFAULT);
|
|
|
|
if (_eina_chained_mp_log_dom < 0)
|
2010-02-11 13:20:52 -08:00
|
|
|
{
|
2010-07-27 19:37:05 -07:00
|
|
|
EINA_LOG_ERR("Could not register log domain: eina_mempool");
|
|
|
|
return EINA_FALSE;
|
2010-02-11 13:20:52 -08:00
|
|
|
}
|
2010-07-27 19:37:05 -07:00
|
|
|
|
2010-02-11 13:56:31 -08:00
|
|
|
#endif
|
2010-02-11 13:20:52 -08:00
|
|
|
return eina_mempool_register(&_eina_chained_mp_backend);
|
2008-09-24 05:55:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void chained_shutdown(void)
|
|
|
|
{
|
2010-02-11 13:20:52 -08:00
|
|
|
eina_mempool_unregister(&_eina_chained_mp_backend);
|
2012-01-18 09:47:05 -08:00
|
|
|
#if defined DEBUG || defined EINA_DEBUG_MALLOC
|
2010-10-23 13:57:08 -07:00
|
|
|
eina_log_domain_unregister(_eina_chained_mp_log_dom);
|
|
|
|
_eina_chained_mp_log_dom = -1;
|
2010-02-11 13:56:31 -08:00
|
|
|
#endif
|
2008-09-24 05:55:31 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
#ifndef EINA_STATIC_BUILD_CHAINED_POOL
|
|
|
|
|
|
|
|
EINA_MODULE_INIT(chained_init);
|
|
|
|
EINA_MODULE_SHUTDOWN(chained_shutdown);
|
2008-09-22 22:17:49 -07:00
|
|
|
|
|
|
|
#endif /* ! EINA_STATIC_BUILD_CHAINED_POOL */
|