2013-01-13 19:34:19 -08:00
|
|
|
/* Eina - EFL data type library
|
2013-01-08 01:17:56 -08:00
|
|
|
* Copyright (C) 2013 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
|
|
|
|
|
2013-03-19 05:15:44 -07:00
|
|
|
#ifdef HAVE_BACKTRACE
|
|
|
|
# include <execinfo.h>
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
# include <memcheck.h>
|
|
|
|
#endif
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
#include "eina_config.h"
|
2013-01-13 19:34:19 -08:00
|
|
|
#include "eina_private.h"
|
|
|
|
#include "eina_log.h"
|
2013-01-08 01:17:56 -08:00
|
|
|
#include "eina_mempool.h"
|
|
|
|
#include "eina_types.h"
|
|
|
|
#include "eina_safety_checks.h"
|
|
|
|
#include "eina_list.h"
|
|
|
|
#include "eina_hash.h"
|
|
|
|
|
|
|
|
#include "eina_cow.h"
|
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
#define EINA_COW_MAGIC 0xDEADBEEF
|
|
|
|
|
2013-01-23 17:42:20 -08:00
|
|
|
# define EINA_COW_PTR_MAGIC 0xBEEFE00
|
|
|
|
#endif
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
typedef struct _Eina_Cow_Ptr Eina_Cow_Ptr;
|
|
|
|
typedef struct _Eina_Cow_GC Eina_Cow_GC;
|
|
|
|
|
2013-03-03 18:08:21 -08:00
|
|
|
#ifdef HAVE_BACKTRACE
|
|
|
|
#define EINA_DEBUG_BT_NUM 64
|
|
|
|
typedef void (*Eina_Bt_Func) ();
|
|
|
|
#endif
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
struct _Eina_Cow_Ptr
|
|
|
|
{
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-23 17:42:20 -08:00
|
|
|
EINA_MAGIC;
|
2013-03-03 18:08:21 -08:00
|
|
|
# ifdef HAVE_BACKTRACE
|
|
|
|
Eina_Bt_Func writer_bt[EINA_DEBUG_BT_NUM];
|
|
|
|
int writer_bt_num;
|
|
|
|
# endif
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
int refcount;
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
Eina_Bool hashed : 1;
|
|
|
|
Eina_Bool togc : 1;
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-13 19:34:19 -08:00
|
|
|
Eina_Bool writing : 1;
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _Eina_Cow_GC
|
|
|
|
{
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-23 17:42:20 -08:00
|
|
|
EINA_MAGIC;
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-23 17:42:20 -08:00
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
Eina_Cow_Ptr *ref;
|
|
|
|
const void * const *dst;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _Eina_Cow
|
|
|
|
{
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
EINA_MAGIC;
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
Eina_Hash *togc;
|
2013-01-08 01:17:56 -08:00
|
|
|
Eina_Hash *match;
|
|
|
|
|
|
|
|
Eina_Mempool *pool;
|
|
|
|
const void *default_value;
|
|
|
|
|
|
|
|
unsigned int struct_size;
|
2013-01-23 17:42:20 -08:00
|
|
|
unsigned int total_size;
|
2013-01-08 01:17:56 -08:00
|
|
|
};
|
|
|
|
|
|
|
|
typedef int (*Eina_Cow_Hash)(const void *, int);
|
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
|
|
|
# define EINA_COW_MAGIC_CHECK(d) \
|
2013-01-08 01:17:56 -08:00
|
|
|
do { \
|
|
|
|
if (!EINA_MAGIC_CHECK((d), EINA_COW_MAGIC)) \
|
|
|
|
EINA_MAGIC_FAIL((d), EINA_COW_MAGIC); \
|
|
|
|
} while (0);
|
|
|
|
|
2013-01-23 17:42:20 -08:00
|
|
|
# define EINA_COW_PTR_MAGIC_CHECK(d) \
|
|
|
|
do { \
|
|
|
|
if (!EINA_MAGIC_CHECK((d), EINA_COW_PTR_MAGIC)) \
|
|
|
|
EINA_MAGIC_FAIL((d), EINA_COW_PTR_MAGIC); \
|
|
|
|
} while (0);
|
|
|
|
#else
|
2013-03-18 23:11:50 -07:00
|
|
|
# define EINA_COW_MAGIC_CHECK(d)
|
2013-01-23 17:42:20 -08:00
|
|
|
# define EINA_COW_PTR_MAGIC_CHECK(d)
|
|
|
|
#endif
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
#define EINA_COW_PTR_SIZE \
|
2013-01-21 19:52:55 -08:00
|
|
|
eina_mempool_alignof(sizeof (Eina_Cow_Ptr))
|
2013-01-13 19:34:19 -08:00
|
|
|
|
|
|
|
#define EINA_COW_PTR_GET(d) \
|
2013-01-21 19:52:55 -08:00
|
|
|
(((Eina_Cow_Ptr *)d) - 1)
|
2013-01-13 19:34:19 -08:00
|
|
|
|
|
|
|
#define EINA_COW_DATA_GET(d) \
|
2013-01-21 19:52:55 -08:00
|
|
|
((unsigned char *)(d + 1))
|
2013-01-13 19:34:19 -08:00
|
|
|
|
|
|
|
static int _eina_cow_log_dom = -1;
|
|
|
|
|
|
|
|
#ifdef ERR
|
|
|
|
#undef ERR
|
|
|
|
#endif
|
|
|
|
#define ERR(...) EINA_LOG_DOM_ERR(_eina_cow_log_dom, __VA_ARGS__)
|
|
|
|
|
2013-04-04 07:43:23 -07:00
|
|
|
#ifdef INF
|
|
|
|
#undef INF
|
|
|
|
#endif
|
|
|
|
#define INF(...) EINA_LOG_DOM_INFO(_eina_cow_log_dom, __VA_ARGS__)
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
#ifdef DBG
|
|
|
|
#undef DBG
|
|
|
|
#endif
|
|
|
|
#define DBG(...) EINA_LOG_DOM_DBG(_eina_cow_log_dom, __VA_ARGS__)
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
static Eina_Mempool *gc_pool = NULL;
|
|
|
|
|
|
|
|
static inline int
|
|
|
|
_eina_cow_hash_gen(const void *key, int key_length,
|
|
|
|
Eina_Cow_Hash hash,
|
|
|
|
int size)
|
|
|
|
{
|
|
|
|
const unsigned char *walk = key;
|
|
|
|
int r = 0xDEADBEEF;
|
|
|
|
|
|
|
|
while (key_length > 0)
|
|
|
|
{
|
|
|
|
r ^= hash(walk, size);
|
|
|
|
|
|
|
|
walk += size;
|
|
|
|
key_length -= size;
|
|
|
|
}
|
|
|
|
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __LP64__
|
|
|
|
static int
|
|
|
|
_eina_cow_hash64(const void *key, int key_length)
|
|
|
|
{
|
|
|
|
return _eina_cow_hash_gen(key, key_length,
|
|
|
|
(Eina_Cow_Hash) eina_hash_int64, sizeof (unsigned long int));
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
static int
|
|
|
|
_eina_cow_hash32(const void *key, int key_length)
|
|
|
|
{
|
|
|
|
return _eina_cow_hash_gen(key, key_length,
|
|
|
|
(Eina_Cow_Hash) eina_hash_int32, sizeof (int));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int current_cow_size = 0;
|
|
|
|
|
|
|
|
static unsigned int
|
|
|
|
_eina_cow_length(const void *key EINA_UNUSED)
|
|
|
|
{
|
|
|
|
/* nasty hack, has only gc need to access the hash, he will be in charge
|
2013-01-13 19:34:19 -08:00
|
|
|
of that global. access to the hash should be considered global.
|
2013-01-08 01:17:56 -08:00
|
|
|
*/
|
|
|
|
return current_cow_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
_eina_cow_cmp(const void *key1, int key1_length,
|
|
|
|
const void *key2, int key2_length EINA_UNUSED)
|
|
|
|
{
|
|
|
|
return memcmp(key1, key2, key1_length);
|
|
|
|
}
|
|
|
|
|
2013-04-10 19:57:57 -07:00
|
|
|
static inline void
|
2013-01-08 01:17:56 -08:00
|
|
|
_eina_cow_hash_del(Eina_Cow *cow,
|
|
|
|
const void *data,
|
|
|
|
Eina_Cow_Ptr *ref)
|
|
|
|
{
|
2013-01-13 19:34:19 -08:00
|
|
|
/* eina_cow_gc is not supposed to be thread safe */
|
|
|
|
if (!ref->hashed) return ;
|
|
|
|
|
|
|
|
current_cow_size = cow->struct_size;
|
2013-04-01 02:38:24 -07:00
|
|
|
eina_hash_del(cow->match, data, data);
|
2013-01-13 19:34:19 -08:00
|
|
|
ref->hashed = EINA_FALSE;
|
2013-01-08 01:17:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2013-03-18 23:11:50 -07:00
|
|
|
_eina_cow_gc_free(void *data)
|
2013-01-08 01:17:56 -08:00
|
|
|
{
|
2013-03-18 23:11:50 -07:00
|
|
|
eina_mempool_free(gc_pool, data);
|
|
|
|
}
|
2013-01-13 19:34:19 -08:00
|
|
|
|
2013-04-10 19:57:57 -07:00
|
|
|
static inline void
|
2013-03-18 23:11:50 -07:00
|
|
|
_eina_cow_togc_del(Eina_Cow *cow, Eina_Cow_Ptr *ref)
|
|
|
|
{
|
2013-01-13 19:34:19 -08:00
|
|
|
/* eina_cow_gc is not supposed to be thread safe */
|
|
|
|
if (!ref->togc) return ;
|
2013-03-18 23:11:50 -07:00
|
|
|
eina_hash_del(cow->togc, &ref, NULL);
|
2013-01-13 19:34:19 -08:00
|
|
|
ref->togc = EINA_FALSE;
|
2013-01-08 01:17:56 -08:00
|
|
|
}
|
|
|
|
|
2013-04-01 21:41:47 -07:00
|
|
|
static void
|
|
|
|
_eina_cow_togc_add(Eina_Cow *cow,
|
|
|
|
Eina_Cow_Ptr *ref,
|
|
|
|
const Eina_Cow_Data * const * dst)
|
|
|
|
{
|
|
|
|
Eina_Cow_GC *gc;
|
|
|
|
|
|
|
|
/* needed if we want to make cow gc safe */
|
|
|
|
if (ref->togc) return ;
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
gc = eina_mempool_malloc(gc_pool, sizeof (Eina_Cow_GC));
|
|
|
|
if (!gc) return ; /* That one will not get gced this time */
|
|
|
|
|
|
|
|
gc->ref = ref;
|
|
|
|
gc->dst = dst;
|
|
|
|
eina_hash_direct_add(cow->togc, &gc->ref, gc);
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
|
|
|
#endif
|
|
|
|
ref->togc = EINA_TRUE;
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
_eina_cow_gc(Eina_Cow *cow, Eina_Cow_Ptr *ref,
|
|
|
|
const Eina_Cow_Data * const *dst,
|
|
|
|
void *data)
|
|
|
|
{
|
|
|
|
void *match;
|
|
|
|
|
|
|
|
ref->togc = EINA_FALSE;
|
|
|
|
|
|
|
|
current_cow_size = cow->struct_size;
|
|
|
|
match = eina_hash_find(cow->match, data);
|
|
|
|
if (match)
|
|
|
|
{
|
|
|
|
ref = EINA_COW_PTR_GET(match);
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
|
|
|
#endif
|
|
|
|
*((void**)dst) = match;
|
|
|
|
ref->refcount++;
|
|
|
|
|
|
|
|
eina_cow_free(cow, data);
|
|
|
|
|
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
eina_hash_direct_add(cow->match, data, data);
|
|
|
|
ref->hashed = EINA_TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
Eina_Bool
|
|
|
|
eina_cow_init(void)
|
|
|
|
{
|
|
|
|
const char *choice, *tmp;
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
_eina_cow_log_dom = eina_log_domain_register("eina_cow", EINA_LOG_COLOR_DEFAULT);
|
|
|
|
if (_eina_cow_log_dom < 0)
|
|
|
|
{
|
|
|
|
EINA_LOG_ERR("Could not register log domain: eina_cow");
|
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
#ifdef EINA_DEFAULT_MEMPOOL
|
|
|
|
choice = "pass_through";
|
|
|
|
#else
|
|
|
|
choice = "chained_mempool";
|
|
|
|
#endif
|
|
|
|
tmp = getenv("EINA_MEMPOOL");
|
|
|
|
if (tmp && tmp[0])
|
|
|
|
choice = tmp;
|
|
|
|
|
|
|
|
gc_pool = eina_mempool_add(choice, "gc", NULL, sizeof (Eina_Cow_GC), 32);
|
|
|
|
if (!gc_pool)
|
|
|
|
{
|
2013-01-13 19:34:19 -08:00
|
|
|
ERR("Mempool for cow gc cannot be allocated.");
|
2013-01-08 01:17:56 -08:00
|
|
|
return EINA_FALSE;
|
|
|
|
}
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
Eina_Bool
|
|
|
|
eina_cow_shutdown(void)
|
|
|
|
{
|
|
|
|
eina_mempool_del(gc_pool);
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Cow *
|
2013-04-02 01:10:35 -07:00
|
|
|
eina_cow_add(const char *name, unsigned int struct_size, unsigned int step, const void *default_value, Eina_Bool gc)
|
2013-01-08 01:17:56 -08:00
|
|
|
{
|
|
|
|
const char *choice, *tmp;
|
|
|
|
Eina_Cow *cow;
|
2013-01-23 17:42:20 -08:00
|
|
|
unsigned int total_size;
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
EINA_SAFETY_ON_NULL_RETURN_VAL(default_value, NULL);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(struct_size, NULL);
|
|
|
|
EINA_SAFETY_ON_FALSE_RETURN_VAL(step, NULL);
|
|
|
|
|
|
|
|
cow = malloc(sizeof (Eina_Cow));
|
|
|
|
if (!cow) return NULL;
|
|
|
|
|
|
|
|
#ifdef EINA_DEFAULT_MEMPOOL
|
|
|
|
choice = "pass_through";
|
|
|
|
#else
|
|
|
|
choice = "chained_mempool";
|
|
|
|
#endif
|
|
|
|
tmp = getenv("EINA_MEMPOOL");
|
|
|
|
if (tmp && tmp[0])
|
|
|
|
choice = tmp;
|
|
|
|
|
2013-04-04 07:43:23 -07:00
|
|
|
INF("Creating Cow '%s' with mempool of type '%s'", name, choice);
|
2013-01-23 17:42:20 -08:00
|
|
|
total_size = eina_mempool_alignof(struct_size + EINA_COW_PTR_SIZE);
|
|
|
|
cow->pool = eina_mempool_add(choice, name, NULL, total_size, step);
|
2013-01-08 01:17:56 -08:00
|
|
|
if (!cow->pool)
|
|
|
|
{
|
2013-01-13 19:34:19 -08:00
|
|
|
ERR("Mempool for cow '%s' cannot be allocated.", name);
|
2013-01-08 01:17:56 -08:00
|
|
|
goto on_error;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef __LP64__
|
|
|
|
cow->match = eina_hash_new(_eina_cow_length,
|
|
|
|
_eina_cow_cmp,
|
|
|
|
_eina_cow_hash64,
|
|
|
|
NULL,
|
|
|
|
6);
|
|
|
|
#else
|
|
|
|
cow->match = eina_hash_new(_eina_cow_length,
|
|
|
|
_eina_cow_cmp,
|
|
|
|
_eina_cow_hash32,
|
|
|
|
NULL,
|
|
|
|
6);
|
|
|
|
#endif
|
2013-04-02 01:10:35 -07:00
|
|
|
if (gc)
|
|
|
|
cow->togc = eina_hash_pointer_new(_eina_cow_gc_free);
|
|
|
|
else
|
|
|
|
cow->togc = NULL;
|
2013-01-08 01:17:56 -08:00
|
|
|
cow->default_value = default_value;
|
|
|
|
cow->struct_size = struct_size;
|
2013-01-23 17:42:20 -08:00
|
|
|
cow->total_size = total_size;
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
EINA_MAGIC_SET(cow, EINA_COW_MAGIC);
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
return cow;
|
|
|
|
|
|
|
|
on_error:
|
|
|
|
free(cow);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
|
|
|
eina_cow_del(Eina_Cow *cow)
|
|
|
|
{
|
2013-01-17 02:29:31 -08:00
|
|
|
if (!cow) return ;
|
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
eina_mempool_del(cow->pool);
|
2013-01-20 03:02:48 -08:00
|
|
|
eina_hash_free(cow->match);
|
2013-04-02 01:10:35 -07:00
|
|
|
if (cow->togc) eina_hash_free(cow->togc);
|
2013-01-08 01:17:56 -08:00
|
|
|
free(cow);
|
|
|
|
}
|
|
|
|
|
2013-01-16 22:51:35 -08:00
|
|
|
EAPI const Eina_Cow_Data *
|
2013-01-08 01:17:56 -08:00
|
|
|
eina_cow_alloc(Eina_Cow *cow)
|
|
|
|
{
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
return cow->default_value;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2013-01-16 22:51:35 -08:00
|
|
|
eina_cow_free(Eina_Cow *cow, const Eina_Cow_Data *data)
|
2013-01-08 01:17:56 -08:00
|
|
|
{
|
|
|
|
Eina_Cow_Ptr *ref;
|
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
if (!data) return ;
|
|
|
|
if (cow->default_value == data) return ;
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
ref = EINA_COW_PTR_GET(data);
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-22 04:11:43 -07:00
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
ref->refcount--;
|
2013-01-24 13:42:18 -08:00
|
|
|
|
2013-03-22 04:11:43 -07:00
|
|
|
if (ref->refcount > 0)
|
|
|
|
{
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-22 04:11:43 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-03-22 04:11:43 -07:00
|
|
|
return ;
|
|
|
|
}
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-23 17:42:20 -08:00
|
|
|
EINA_MAGIC_SET(ref, EINA_MAGIC_NONE);
|
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
_eina_cow_hash_del(cow, data, ref);
|
|
|
|
_eina_cow_togc_del(cow, ref);
|
2013-01-23 17:42:20 -08:00
|
|
|
eina_mempool_free(cow->pool, (void*) ref);
|
2013-01-08 01:17:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void *
|
2013-01-16 22:51:35 -08:00
|
|
|
eina_cow_write(Eina_Cow *cow,
|
|
|
|
const Eina_Cow_Data * const *data)
|
2013-01-08 01:17:56 -08:00
|
|
|
{
|
|
|
|
Eina_Cow_Ptr *ref;
|
|
|
|
void *r;
|
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-08 01:17:56 -08:00
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
if (!*data) return NULL; /* cow pointer is always != NULL */
|
|
|
|
if (*data == cow->default_value)
|
2013-01-13 19:34:19 -08:00
|
|
|
goto allocate;
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
ref = EINA_COW_PTR_GET(*data);
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-01-24 13:06:41 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
2013-01-24 13:06:41 -08:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
if (ref->refcount == 1)
|
|
|
|
{
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-23 17:42:20 -08:00
|
|
|
EINA_COW_PTR_MAGIC_CHECK(ref);
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
if (ref->writing)
|
|
|
|
{
|
|
|
|
ERR("Request writing on an pointer that is already in a writing process %p\n", data);
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef HAVE_BACKTRACE
|
2013-03-03 18:08:21 -08:00
|
|
|
backtrace_symbols_fd((void **) ref->writer_bt,
|
|
|
|
ref->writer_bt_num, 1);
|
|
|
|
#endif
|
2013-01-13 19:34:19 -08:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-13 19:34:19 -08:00
|
|
|
|
2013-04-10 19:57:57 -07:00
|
|
|
if (cow->togc)
|
|
|
|
_eina_cow_hash_del(cow, *data, ref);
|
|
|
|
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-01-13 19:34:19 -08:00
|
|
|
goto end;
|
2013-01-08 01:17:56 -08:00
|
|
|
}
|
2013-01-27 16:22:21 -08:00
|
|
|
ref->refcount--;
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
allocate:
|
2013-01-23 17:42:20 -08:00
|
|
|
ref = eina_mempool_malloc(cow->pool, cow->total_size);
|
2013-01-08 01:17:56 -08:00
|
|
|
ref->refcount = 1;
|
|
|
|
ref->hashed = EINA_FALSE;
|
|
|
|
ref->togc = EINA_FALSE;
|
2013-03-19 18:59:22 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
|
|
|
EINA_MAGIC_SET(ref, EINA_COW_PTR_MAGIC);
|
|
|
|
#endif
|
|
|
|
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
r = EINA_COW_DATA_GET(ref);
|
|
|
|
memcpy(r, *data, cow->struct_size);
|
2013-01-08 01:17:56 -08:00
|
|
|
*((void**) data) = r;
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
end:
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
2013-03-03 18:08:21 -08:00
|
|
|
#endif
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
|
|
|
# ifdef HAVE_BACKTRACE
|
2013-03-03 18:08:21 -08:00
|
|
|
ref->writer_bt_num = backtrace((void **)(ref->writer_bt),
|
|
|
|
EINA_DEBUG_BT_NUM);
|
2013-03-18 23:11:50 -07:00
|
|
|
# endif
|
2013-01-13 19:34:19 -08:00
|
|
|
ref->writing = EINA_TRUE;
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
return (void *) *data;
|
2013-01-08 01:17:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2013-01-16 22:51:35 -08:00
|
|
|
eina_cow_done(Eina_Cow *cow,
|
|
|
|
const Eina_Cow_Data * const * dst,
|
2013-03-19 05:15:44 -07:00
|
|
|
const void *data,
|
|
|
|
Eina_Bool needed_gc)
|
2013-01-08 01:17:56 -08:00
|
|
|
{
|
|
|
|
Eina_Cow_Ptr *ref;
|
|
|
|
|
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
ref = EINA_COW_PTR_GET(data);
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-03-19 18:59:22 -07:00
|
|
|
EINA_COW_PTR_MAGIC_CHECK(ref);
|
2013-03-18 23:11:50 -07:00
|
|
|
#ifdef EINA_COW_MAGIC_ON
|
2013-01-24 13:06:41 -08:00
|
|
|
if (!ref->writing)
|
|
|
|
ERR("Pointer %p is not in a writable state !", dst);
|
|
|
|
|
2013-01-13 19:34:19 -08:00
|
|
|
ref->writing = EINA_FALSE;
|
2013-03-18 23:11:50 -07:00
|
|
|
#endif
|
2013-03-19 18:59:22 -07:00
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-04-02 01:10:35 -07:00
|
|
|
if (!cow->togc || !needed_gc) return ;
|
2013-03-19 05:15:44 -07:00
|
|
|
|
2013-03-20 13:18:49 -07:00
|
|
|
#ifndef NVALGRIND
|
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-04-01 21:41:47 -07:00
|
|
|
_eina_cow_togc_add(cow, ref, dst);
|
2013-01-08 01:17:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
EAPI void
|
2013-01-16 22:51:35 -08:00
|
|
|
eina_cow_memcpy(Eina_Cow *cow,
|
|
|
|
const Eina_Cow_Data * const *dst,
|
|
|
|
const Eina_Cow_Data *src)
|
2013-01-08 01:17:56 -08:00
|
|
|
{
|
|
|
|
Eina_Cow_Ptr *ref;
|
|
|
|
|
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
|
|
|
|
2013-01-27 16:22:21 -08:00
|
|
|
if (*dst == src) return ;
|
|
|
|
|
|
|
|
if (src != cow->default_value)
|
|
|
|
{
|
|
|
|
ref = EINA_COW_PTR_GET(src);
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_DEFINED(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-04-01 21:41:47 -07:00
|
|
|
|
|
|
|
EINA_COW_PTR_MAGIC_CHECK(ref);
|
2013-01-27 16:22:21 -08:00
|
|
|
ref->refcount++;
|
2013-04-01 21:41:47 -07:00
|
|
|
|
2013-04-02 01:10:35 -07:00
|
|
|
if (cow->togc)
|
|
|
|
_eina_cow_togc_del(cow, ref);
|
2013-04-01 21:41:47 -07:00
|
|
|
|
2013-01-23 17:42:20 -08:00
|
|
|
#ifndef NVALGRIND
|
2013-03-19 18:59:22 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(ref, sizeof (*ref));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-01-27 16:22:21 -08:00
|
|
|
}
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-04-01 21:41:47 -07:00
|
|
|
eina_cow_free(cow, *dst);
|
|
|
|
|
2013-01-08 01:17:56 -08:00
|
|
|
*((const void**)dst) = src;
|
|
|
|
}
|
|
|
|
|
|
|
|
EAPI Eina_Bool
|
|
|
|
eina_cow_gc(Eina_Cow *cow)
|
|
|
|
{
|
|
|
|
Eina_Cow_GC *gc;
|
2013-03-18 23:11:50 -07:00
|
|
|
Eina_Iterator *it;
|
2013-01-08 01:17:56 -08:00
|
|
|
void *data;
|
2013-03-18 23:11:50 -07:00
|
|
|
Eina_Bool r;
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
EINA_COW_MAGIC_CHECK(cow);
|
|
|
|
|
2013-04-02 01:10:35 -07:00
|
|
|
if (!cow->togc || !eina_hash_population(cow->togc))
|
|
|
|
return EINA_FALSE;
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
it = eina_hash_iterator_data_new(cow->togc);
|
|
|
|
r = eina_iterator_next(it, (void**) &gc);
|
|
|
|
eina_iterator_free(it);
|
|
|
|
|
|
|
|
if (!r) return EINA_FALSE; /* Something did go wrong here */
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
/* Do handle hash and all funky merge think here */
|
2013-01-13 19:34:19 -08:00
|
|
|
data = EINA_COW_DATA_GET(gc->ref);
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-04-01 02:38:24 -07:00
|
|
|
#ifndef NVALGRIND
|
2013-05-08 02:08:17 -07:00
|
|
|
VALGRIND_MAKE_MEM_DEFINED(gc->ref, sizeof (Eina_Cow_Ptr));
|
2013-01-23 17:42:20 -08:00
|
|
|
#endif
|
2013-04-01 21:41:47 -07:00
|
|
|
_eina_cow_gc(cow, gc->ref, gc->dst, data);
|
2013-04-01 02:38:24 -07:00
|
|
|
#ifndef NVALGRIND
|
2013-05-08 02:08:17 -07:00
|
|
|
VALGRIND_MAKE_MEM_NOACCESS(gc->ref, sizeof (Eina_Cow_Ptr));
|
2013-04-01 02:38:24 -07:00
|
|
|
#endif
|
2013-01-08 01:17:56 -08:00
|
|
|
|
2013-03-18 23:11:50 -07:00
|
|
|
eina_hash_del(cow->togc, &gc->ref, gc);
|
2013-01-08 01:17:56 -08:00
|
|
|
|
|
|
|
return EINA_TRUE;
|
|
|
|
}
|
|
|
|
|