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>
|
|
|
|
|
2012-12-31 08:14:40 -08:00
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
|
|
|
# include <assert.h>
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
|
|
|
|
2016-01-07 07:43:26 -08:00
|
|
|
#ifdef EINA_DEBUG_MALLOC
|
|
|
|
# ifdef __linux__
|
|
|
|
# include <malloc.h>
|
|
|
|
# endif
|
|
|
|
# ifdef __FreeBSD__
|
|
|
|
# include <malloc_np.h>
|
|
|
|
# endif
|
2012-01-18 09:47:05 -08:00
|
|
|
#endif
|
|
|
|
|
2012-10-10 14:48:34 -07:00
|
|
|
#include "eina_config.h"
|
2008-07-31 08:11:05 -07:00
|
|
|
#include "eina_inlist.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"
|
2013-03-03 20:51:26 -08:00
|
|
|
#include "eina_thread.h"
|
2013-11-10 03:07:59 -08:00
|
|
|
#include "eina_cpu.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
|
2012-03-16 04:25:14 -07:00
|
|
|
# include <memcheck.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
|
|
|
#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__)
|
2013-01-23 19:54:47 -08:00
|
|
|
|
|
|
|
#ifdef ERR
|
|
|
|
#undef ERR
|
|
|
|
#endif
|
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_eina_chained_mp_log_dom, __VA_ARGS__)
|
|
|
|
|
2010-02-11 13:20:52 -08:00
|
|
|
#endif
|
|
|
|
|
2013-04-04 06:54:12 -07:00
|
|
|
static int aligned_chained_pool = 0;
|
2013-11-10 00:26:12 -08:00
|
|
|
static int page_size = 0;
|
2013-04-04 06:54:12 -07:00
|
|
|
|
2015-03-06 06:48:38 -08:00
|
|
|
typedef struct _Chained_Pool Chained_Pool;
|
|
|
|
struct _Chained_Pool
|
|
|
|
{
|
|
|
|
EINA_INLIST;
|
|
|
|
EINA_RBTREE;
|
|
|
|
Eina_Trash *base;
|
2019-09-14 10:54:05 -07:00
|
|
|
unsigned int usage;
|
2015-03-06 06:48:38 -08:00
|
|
|
|
|
|
|
unsigned char *last;
|
|
|
|
unsigned char *limit;
|
|
|
|
};
|
|
|
|
|
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;
|
2019-09-14 10:54:05 -07:00
|
|
|
unsigned int item_alloc;
|
|
|
|
unsigned int pool_size;
|
|
|
|
unsigned int alloc_size;
|
|
|
|
unsigned int group_size;
|
|
|
|
unsigned int usage;
|
2015-03-06 06:48:38 -08:00
|
|
|
Chained_Pool* first_fill; //All allocation will happen in this chain,unless it is filled
|
2012-01-18 09:47:05 -08:00
|
|
|
#ifdef EINA_DEBUG_MALLOC
|
|
|
|
int minimal_size;
|
|
|
|
#endif
|
2012-10-10 14:48:34 -07:00
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
2013-01-24 17:20:58 -08:00
|
|
|
Eina_Thread self;
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
2013-10-11 01:42:49 -07:00
|
|
|
Eina_Spinlock mutex;
|
2008-07-31 08:11:05 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
2011-02-04 06:03:18 -08:00
|
|
|
static inline Eina_Rbtree_Direction
|
2012-10-05 13:09:47 -07:00
|
|
|
_eina_chained_mp_pool_cmp(const Eina_Rbtree *left, const Eina_Rbtree *right, EINA_UNUSED void *data)
|
2011-02-04 06:03:18 -08:00
|
|
|
{
|
|
|
|
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,
|
2012-10-05 13:09:47 -07:00
|
|
|
EINA_UNUSED int length, EINA_UNUSED void *data)
|
2011-02-04 06:03:18 -08:00
|
|
|
{
|
|
|
|
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;
|
2010-07-26 08:52:43 -07:00
|
|
|
|
2010-07-30 01:26:34 -07:00
|
|
|
p = malloc(pool->alloc_size);
|
2013-10-11 00:49:13 -07:00
|
|
|
if (!p) return NULL;
|
2008-07-31 08:11:05 -07:00
|
|
|
|
2017-12-20 09:50:17 -08:00
|
|
|
#if defined(EINA_DEBUG_MALLOC) && defined (HAVE_MALLOC_USABLE_SIZE)
|
2012-01-18 09:47:05 -08:00
|
|
|
{
|
|
|
|
size_t sz;
|
|
|
|
sz = malloc_usable_size(p);
|
|
|
|
if (sz - pool->minimal_size > 0)
|
2013-03-08 03:46:25 -08:00
|
|
|
INF("Just allocated %0.2f%% to much memory in '%s' for one block of size %i that means %lu bytes to much.",
|
2012-01-18 09:47:05 -08:00
|
|
|
((float)(sz - pool->minimal_size) * 100) / (float) (pool->alloc_size),
|
|
|
|
pool->name,
|
|
|
|
pool->alloc_size,
|
2013-03-08 03:46:25 -08:00
|
|
|
(unsigned long) sz - pool->minimal_size);
|
2012-01-18 09:47:05 -08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-23 18:23:59 -08:00
|
|
|
ptr = (unsigned char *)(p + 1);
|
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
|
2013-04-04 06:54:12 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ptr, pool->alloc_size - aligned_chained_pool);
|
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
|
|
|
#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)
|
|
|
|
{
|
2019-10-25 07:58:31 -07:00
|
|
|
void *mem = NULL;
|
2011-04-11 07:07:42 -07:00
|
|
|
|
2019-10-25 07:58:31 -07:00
|
|
|
// Let's try to first recycle memory
|
|
|
|
if (p->base)
|
2011-04-11 07:07:42 -07:00
|
|
|
{
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_DEFINED(p->base, pool->item_alloc);
|
|
|
|
#endif
|
|
|
|
// Request a free pointer
|
|
|
|
mem = eina_trash_pop(&p->base);
|
|
|
|
}
|
2019-10-25 07:58:31 -07:00
|
|
|
else if (p->last)
|
|
|
|
{
|
|
|
|
mem = p->last;
|
|
|
|
p->last += pool->item_alloc;
|
|
|
|
if (p->last >= p->limit)
|
|
|
|
p->last = NULL;
|
|
|
|
}
|
2019-09-14 10:16:56 -07:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
// move to end - it just filled up
|
|
|
|
if (!p->base && !p->last)
|
|
|
|
pool->first = eina_inlist_demote(pool->first, EINA_INLIST_GET(p));
|
2019-09-14 10:16:56 -07:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
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)
|
|
|
|
{
|
2013-01-23 18:58:00 -08:00
|
|
|
#ifdef DEBUG
|
2011-04-11 07:07:42 -07:00
|
|
|
void *pmem;
|
2020-06-20 02:54:26 -07:00
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
// pool mem base
|
|
|
|
pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
|
|
|
|
|
|
|
|
// is it in pool mem?
|
|
|
|
if (ptr < pmem)
|
|
|
|
{
|
2013-01-23 19:54:47 -08:00
|
|
|
ERR("%p is inside the private part of %p pool from %p '%s' Chained_Mempool (could be the sign of a buffer underrun).", ptr, p, pool, pool->name);
|
2013-01-23 18:44:14 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// is it really a pointer returned by malloc
|
|
|
|
if ((((unsigned char *)ptr) - (unsigned char *)(p + 1)) % pool->item_alloc)
|
|
|
|
{
|
2013-06-12 06:44:25 -07:00
|
|
|
ERR("%p is %lu bytes inside a pointer served by %p '%s' Chained_Mempool (You are freeing the wrong pointer man !).",
|
2013-01-23 18:44:14 -08:00
|
|
|
ptr, ((((unsigned char *)ptr) - (unsigned char *)(p + 1)) % pool->item_alloc), pool, pool->name);
|
2011-04-11 07:07:42 -07:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
2013-01-23 18:44:14 -08:00
|
|
|
#endif
|
2011-04-11 07:07:42 -07:00
|
|
|
|
|
|
|
// 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);
|
2015-03-06 06:48:38 -08:00
|
|
|
if (pool->first_fill == p)
|
|
|
|
{
|
|
|
|
pool->first_fill = NULL;
|
|
|
|
pool->first_fill = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool);
|
|
|
|
}
|
2011-04-11 07:07:42 -07:00
|
|
|
_eina_chained_mp_pool_free(p);
|
|
|
|
|
2015-03-06 06:48:38 -08:00
|
|
|
return EINA_TRUE;
|
2011-04-11 07:07:42 -07:00
|
|
|
}
|
|
|
|
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 *
|
2012-10-05 13:09:47 -07:00
|
|
|
eina_chained_mempool_malloc(void *data, EINA_UNUSED unsigned int size)
|
2008-07-31 08:11:05 -07:00
|
|
|
{
|
|
|
|
Chained_Mempool *pool = data;
|
2008-09-17 08:18:35 -07:00
|
|
|
Chained_Pool *p = NULL;
|
2020-06-16 02:03:26 -07:00
|
|
|
void *mem = NULL;
|
2008-07-31 08:11:05 -07:00
|
|
|
|
2013-10-11 01:42:49 -07:00
|
|
|
if (!eina_spinlock_take(&pool->mutex))
|
2010-10-12 09:53:30 -07:00
|
|
|
{
|
2012-10-10 14:48:34 -07:00
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
2012-12-31 08:14:40 -08:00
|
|
|
assert(eina_thread_equal(pool->self, eina_thread_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
|
|
|
|
2015-03-06 06:48:38 -08:00
|
|
|
//we have some free space in first fill chain
|
|
|
|
if (pool->first_fill) p = pool->first_fill;
|
2011-02-04 06:03:18 -08:00
|
|
|
|
|
|
|
// base is not NULL - has a free slot
|
|
|
|
if (p && !p->base && !p->last)
|
2015-03-06 06:48:38 -08:00
|
|
|
{
|
|
|
|
//Current pointed chain is filled , so point it to first one
|
|
|
|
pool->first_fill = EINA_INLIST_CONTAINER_GET(pool->first, Chained_Pool);
|
|
|
|
//Either first one has some free space or every chain is filled
|
|
|
|
if (pool->first_fill && !pool->first_fill->base && !pool->first_fill->last)
|
|
|
|
{
|
|
|
|
p = NULL;
|
|
|
|
pool->first_fill = NULL;
|
|
|
|
}
|
|
|
|
}
|
2011-02-04 06:03:18 -08:00
|
|
|
|
|
|
|
#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)
|
2019-10-25 07:58:31 -07:00
|
|
|
{
|
2015-03-06 06:48:38 -08:00
|
|
|
//new chain created ,point it to be the first_fill chain
|
|
|
|
pool->first_fill = _eina_chained_mp_pool_new(pool);
|
|
|
|
if (!pool->first_fill)
|
2010-07-27 19:37:05 -07:00
|
|
|
{
|
2013-10-11 01:42:49 -07:00
|
|
|
eina_spinlock_release(&pool->mutex);
|
2010-07-27 19:37:05 -07:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2015-03-06 06:48:38 -08:00
|
|
|
pool->first = eina_inlist_prepend(pool->first, EINA_INLIST_GET(pool->first_fill));
|
|
|
|
pool->root = eina_rbtree_inline_insert(pool->root, EINA_RBTREE_GET(pool->first_fill),
|
2011-02-04 06:03:18 -08:00
|
|
|
_eina_chained_mp_pool_cmp, NULL);
|
2008-07-31 08:11:05 -07:00
|
|
|
}
|
2010-07-27 19:37:05 -07:00
|
|
|
|
2020-06-16 02:03:26 -07:00
|
|
|
if (pool->first_fill)
|
|
|
|
mem = _eina_chained_mempool_alloc_in(pool, pool->first_fill);
|
2009-02-17 06:18:14 -08:00
|
|
|
|
2013-10-11 01:42:49 -07:00
|
|
|
eina_spinlock_release(&pool->mutex);
|
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
|
2013-10-11 01:42:49 -07:00
|
|
|
if (!eina_spinlock_take(&pool->mutex))
|
2010-10-12 09:53:30 -07:00
|
|
|
{
|
2012-10-10 14:48:34 -07:00
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
2012-12-31 08:14:40 -08:00
|
|
|
assert(eina_thread_equal(pool->self, eina_thread_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
|
2013-01-23 19:54:47 -08:00
|
|
|
ERR("%p is not the property of %p Chained_Mempool", ptr, pool);
|
2011-02-04 06:03:18 -08:00
|
|
|
#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
|
|
|
|
2013-10-11 01:42:49 -07:00
|
|
|
eina_spinlock_release(&pool->mutex);
|
2011-04-11 07:07:42 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-10-25 09:11:06 -07:00
|
|
|
static void *
|
|
|
|
eina_chained_mempool_malloc_near(void *data,
|
|
|
|
void *after, void *before,
|
|
|
|
unsigned int size EINA_UNUSED)
|
|
|
|
{
|
|
|
|
Chained_Mempool *pool = data;
|
|
|
|
Chained_Pool *p = NULL;
|
|
|
|
void *mem = NULL;
|
|
|
|
|
|
|
|
if (!eina_spinlock_take(&pool->mutex))
|
|
|
|
{
|
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
|
|
|
assert(eina_thread_equal(pool->self, eina_thread_self()));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
if (after)
|
|
|
|
{
|
|
|
|
Eina_Rbtree *r = eina_rbtree_inline_lookup(pool->root, after,
|
|
|
|
0, _eina_chained_mp_pool_key_cmp, NULL);
|
|
|
|
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
p = EINA_RBTREE_CONTAINER_GET(r, Chained_Pool);
|
|
|
|
|
|
|
|
if (!p->base && !p->last)
|
|
|
|
p = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (before && p == NULL)
|
|
|
|
{
|
|
|
|
Eina_Rbtree *r = eina_rbtree_inline_lookup(pool->root, before,
|
|
|
|
0, _eina_chained_mp_pool_key_cmp, NULL);
|
|
|
|
if (r)
|
|
|
|
{
|
|
|
|
p = EINA_RBTREE_CONTAINER_GET(r, Chained_Pool);
|
|
|
|
if (!p->base && !p->last)
|
|
|
|
p = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p) mem = _eina_chained_mempool_alloc_in(pool, p);
|
|
|
|
|
|
|
|
eina_spinlock_release(&pool->mutex);
|
|
|
|
|
|
|
|
if (!mem) return eina_chained_mempool_malloc(pool, size);
|
|
|
|
return mem;
|
|
|
|
}
|
|
|
|
|
2017-08-15 13:46:36 -07:00
|
|
|
static Eina_Bool
|
|
|
|
eina_chained_mempool_from(void *data, void *ptr)
|
|
|
|
{
|
|
|
|
Chained_Mempool *pool = data;
|
|
|
|
Eina_Rbtree *r;
|
|
|
|
Chained_Pool *p;
|
|
|
|
Eina_Trash *t;
|
2017-09-04 03:08:33 -07:00
|
|
|
#ifndef NVALGRIND
|
2017-09-05 00:20:43 -07:00
|
|
|
Eina_Trash *last = NULL;
|
2017-09-04 03:08:33 -07:00
|
|
|
#endif
|
2017-08-15 13:46:36 -07:00
|
|
|
void *pmem;
|
|
|
|
Eina_Bool ret = EINA_FALSE;
|
|
|
|
|
|
|
|
// look 4 pool
|
|
|
|
if (!eina_spinlock_take(&pool->mutex))
|
|
|
|
{
|
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
|
|
|
assert(eina_thread_equal(pool->self, eina_thread_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) goto end;
|
|
|
|
|
|
|
|
p = EINA_RBTREE_CONTAINER_GET(r, Chained_Pool);
|
|
|
|
|
|
|
|
// pool mem base
|
|
|
|
pmem = (void *)(((unsigned char *)p) + sizeof(Chained_Pool));
|
|
|
|
|
|
|
|
// is it in pool mem?
|
|
|
|
if (ptr < pmem)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
ERR("%p is inside the private part of %p pool from %p '%s' Chained_Mempool (could be the sign of a buffer underrun).", ptr, p, pool, pool->name);
|
|
|
|
#endif
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2019-09-14 10:16:56 -07:00
|
|
|
// is the pointer in the allocated zone of the mempool
|
|
|
|
if (p->last != NULL && ((unsigned char *)ptr >= p->last))
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
ERR("%p has not been allocated yet from %p pool of %p '%s' Chained_Mempool.", ptr, p, pool, pool->name);
|
|
|
|
#endif
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
2017-08-15 13:46:36 -07:00
|
|
|
// is it really a pointer returned by malloc
|
|
|
|
if ((((unsigned char *)ptr) - (unsigned char *)(p + 1)) % pool->item_alloc)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
ERR("%p is %lu bytes inside a pointer served by %p '%s' Chained_Mempool (You are freeing the wrong pointer man !).",
|
|
|
|
ptr, ((((unsigned char *)ptr) - (unsigned char *)(p + 1)) % pool->item_alloc), pool, pool->name);
|
|
|
|
#endif
|
|
|
|
goto end;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check if the pointer was freed
|
2017-09-05 00:20:43 -07:00
|
|
|
for (t = p->base; t != NULL; t = t->next)
|
2017-09-04 03:08:33 -07:00
|
|
|
{
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_DEFINED(t, pool->item_alloc);
|
|
|
|
if (last) VALGRIND_MAKE_MEM_NOACCESS(last, pool->item_alloc);
|
|
|
|
last = t;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
if (t == ptr) goto end;
|
|
|
|
}
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
if (last) VALGRIND_MAKE_MEM_NOACCESS(last, pool->item_alloc);
|
|
|
|
#endif
|
2017-08-15 13:46:36 -07:00
|
|
|
|
|
|
|
// Seems like we have a valid pointer actually
|
|
|
|
ret = EINA_TRUE;
|
|
|
|
|
|
|
|
end:
|
|
|
|
eina_spinlock_release(&pool->mutex);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2019-09-14 10:54:05 -07:00
|
|
|
typedef struct _Eina_Iterator_Chained_Mempool Eina_Iterator_Chained_Mempool;
|
|
|
|
struct _Eina_Iterator_Chained_Mempool
|
|
|
|
{
|
|
|
|
Eina_Iterator iterator;
|
|
|
|
|
|
|
|
Eina_Iterator *walker;
|
|
|
|
Chained_Pool *current;
|
|
|
|
Chained_Mempool *pool;
|
|
|
|
|
|
|
|
unsigned int offset;
|
|
|
|
};
|
|
|
|
|
|
|
|
static Eina_Bool
|
|
|
|
eina_mempool_iterator_next(Eina_Iterator_Chained_Mempool *it, void **data)
|
|
|
|
{
|
|
|
|
if (!it->current)
|
|
|
|
{
|
|
|
|
if (!eina_iterator_next(it->walker, (void**) &it->current))
|
|
|
|
return EINA_FALSE;
|
|
|
|
if (!it->current) return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
retry:
|
|
|
|
if (it->offset < it->pool->group_size)
|
|
|
|
{
|
|
|
|
unsigned char *ptr = (unsigned char *) (it->current + 1);
|
|
|
|
|
|
|
|
ptr += it->offset;
|
|
|
|
it->offset += it->pool->item_alloc;
|
|
|
|
|
|
|
|
if (!eina_chained_mempool_from(it->pool, ptr)) goto retry;
|
|
|
|
|
|
|
|
if (data) *data = (void *) ptr;
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!eina_iterator_next(it->walker, (void**) &it->current))
|
|
|
|
return EINA_FALSE;
|
|
|
|
|
|
|
|
it->offset = 0;
|
|
|
|
goto retry;
|
|
|
|
}
|
|
|
|
|
|
|
|
static Chained_Mempool *
|
|
|
|
eina_mempool_iterator_get_container(Eina_Iterator_Chained_Mempool *it)
|
|
|
|
{
|
|
|
|
return it->pool;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
eina_mempool_iterator_free(Eina_Iterator_Chained_Mempool *it)
|
|
|
|
{
|
|
|
|
eina_iterator_free(it->walker);
|
|
|
|
free(it);
|
|
|
|
}
|
|
|
|
|
|
|
|
static Eina_Iterator *
|
|
|
|
eina_chained_mempool_iterator_new(void *data)
|
|
|
|
{
|
|
|
|
Eina_Iterator_Chained_Mempool *it;
|
|
|
|
Chained_Mempool *pool = data;
|
|
|
|
|
|
|
|
it = calloc(1, sizeof (Eina_Iterator_Chained_Mempool));
|
|
|
|
if (!it) return NULL;
|
|
|
|
|
|
|
|
it->walker = eina_inlist_iterator_new(pool->first);
|
|
|
|
it->pool = pool;
|
|
|
|
|
|
|
|
it->iterator.version = EINA_ITERATOR_VERSION;
|
|
|
|
it->iterator.next = FUNC_ITERATOR_NEXT(eina_mempool_iterator_next);
|
|
|
|
it->iterator.get_container = FUNC_ITERATOR_GET_CONTAINER(
|
|
|
|
eina_mempool_iterator_get_container);
|
|
|
|
it->iterator.free = FUNC_ITERATOR_FREE(eina_mempool_iterator_free);
|
|
|
|
|
|
|
|
EINA_MAGIC_SET(&it->iterator, EINA_MAGIC_ITERATOR);
|
|
|
|
|
|
|
|
return &it->iterator;
|
|
|
|
}
|
|
|
|
|
2011-04-11 07:07:42 -07:00
|
|
|
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 */
|
2013-10-11 01:42:49 -07:00
|
|
|
if (!eina_spinlock_take(&pool->mutex))
|
2011-02-04 06:03:18 -08:00
|
|
|
{
|
2012-10-10 14:48:34 -07:00
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
2013-01-24 17:20:58 -08:00
|
|
|
assert(eina_thread_equal(pool->self, eina_thread_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 */
|
2013-10-11 01:42:49 -07:00
|
|
|
eina_spinlock_release(&pool->mutex);
|
2008-07-31 08:11:05 -07:00
|
|
|
}
|
|
|
|
|
2010-07-27 19:37:05 -07:00
|
|
|
static void *
|
2012-10-05 13:09:47 -07:00
|
|
|
eina_chained_mempool_realloc(EINA_UNUSED void *data,
|
|
|
|
EINA_UNUSED void *element,
|
|
|
|
EINA_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,
|
2012-10-05 13:09:47 -07:00
|
|
|
EINA_UNUSED const char *option,
|
2010-07-27 19:37:05 -07:00
|
|
|
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
|
|
|
}
|
|
|
|
|
2017-09-16 05:20:11 -07:00
|
|
|
mp->item_alloc = MAX(eina_mempool_alignof(item_size), sizeof(void *));
|
2013-04-04 06:54:12 -07:00
|
|
|
|
2013-11-10 00:26:12 -08:00
|
|
|
mp->pool_size = (((((mp->item_alloc * mp->pool_size + aligned_chained_pool) / page_size)
|
|
|
|
+ 1) * page_size)
|
2013-04-04 06:54:12 -07:00
|
|
|
- aligned_chained_pool) / mp->item_alloc;
|
|
|
|
|
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->group_size = mp->item_alloc * mp->pool_size;
|
2013-04-04 06:54:12 -07:00
|
|
|
mp->alloc_size = mp->group_size + aligned_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
|
|
|
|
|
2012-10-10 14:48:34 -07:00
|
|
|
#ifdef EINA_HAVE_DEBUG_THREADS
|
2013-01-24 17:20:58 -08:00
|
|
|
mp->self = eina_thread_self();
|
2009-02-17 06:18:14 -08:00
|
|
|
#endif
|
2015-03-06 06:48:38 -08:00
|
|
|
mp->first_fill = NULL;
|
2013-10-11 01:42:49 -07:00
|
|
|
eina_spinlock_new(&mp->mutex);
|
2011-04-24 08:54:09 -07:00
|
|
|
|
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)
|
2013-06-12 06:44:40 -07:00
|
|
|
INF("Bad news we are destroying a non-empty mempool [%s]\n",
|
2010-07-27 19:37:05 -07:00
|
|
|
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)
|
2013-01-23 19:54:47 -08:00
|
|
|
ERR("Bad news, list of pool and rbtree are out of sync for %p !", mp);
|
2011-02-04 06:03:18 -08:00
|
|
|
#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
|
|
|
|
|
2013-10-11 01:42:49 -07:00
|
|
|
eina_spinlock_free(&mp->mutex);
|
2011-04-24 08:54:09 -07:00
|
|
|
|
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,
|
2017-08-15 13:46:36 -07:00
|
|
|
&eina_chained_mempool_repack,
|
2019-09-14 10:54:05 -07:00
|
|
|
&eina_chained_mempool_from,
|
2019-10-25 08:01:35 -07:00
|
|
|
&eina_chained_mempool_iterator_new,
|
2019-10-25 09:11:06 -07:00
|
|
|
&eina_chained_mempool_malloc_near
|
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
|
2013-04-04 06:54:12 -07:00
|
|
|
aligned_chained_pool = eina_mempool_alignof(sizeof(Chained_Pool));
|
2013-11-10 00:26:12 -08:00
|
|
|
page_size = eina_cpu_page_size();
|
2013-04-04 06:54:12 -07:00
|
|
|
|
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 */
|