summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCedric BAIL <cedric@osg.samsung.com>2016-06-10 13:42:19 -0700
committerCedric BAIL <cedric@osg.samsung.com>2016-06-10 13:57:01 -0700
commit692b2c9fc9b347fc0be80b674d4580648e2f6541 (patch)
treee2ec543175774f189846416ea50bbd6bb6f74f33
parent5964008946abad2b8c4fac019b3f2ea090a7498d (diff)
downloadefl-692b2c9fc9b347fc0be80b674d4580648e2f6541.tar.gz
eina: add generic infrastructure for a Eina_Safepointer
This is heavily inspired from Eo_Id infrastructure. Main change are that the lower bit are always guaranteed to be zero and ignored by all function. Also it may be a little bit less efficient in some case, but we will tune it once we have real life usage of it. Eo won't be migrated for 1.18 to it as Eo_Id is deeply integrated and it is quite risky to touch it so close from a freeze. This can wait.
-rw-r--r--configure.ac2
-rw-r--r--src/Makefile_Eina.am6
-rw-r--r--src/lib/eina/Eina.h1
-rw-r--r--src/lib/eina/eina_config.h.in5
-rw-r--r--src/lib/eina/eina_inline_safepointer.x188
-rw-r--r--src/lib/eina/eina_main.c4
-rw-r--r--src/lib/eina/eina_safepointer.c362
-rw-r--r--src/lib/eina/eina_safepointer.h115
8 files changed, 680 insertions, 3 deletions
diff --git a/configure.ac b/configure.ac
index 676624fe38..f37f3a5429 100644
--- a/configure.ac
+++ b/configure.ac
@@ -463,6 +463,8 @@ AC_CHECK_SIZEOF(int, 4)
AC_CHECK_SIZEOF(long, 4)
AC_CHECK_SIZEOF([uintptr_t])
+EINA_SIZEOF_UINTPTR_T=$ac_cv_sizeof_uintptr_t
+AC_SUBST([EINA_SIZEOF_UINTPTR_T])
AC_CHECK_TYPES([siginfo_t], [], [],
[[
diff --git a/src/Makefile_Eina.am b/src/Makefile_Eina.am
index 1b6bdff7bd..602c3dbf2a 100644
--- a/src/Makefile_Eina.am
+++ b/src/Makefile_Eina.am
@@ -97,7 +97,8 @@ lib/eina/eina_quaternion.h \
lib/eina/eina_vector.h \
lib/eina/eina_inline_vector.x \
lib/eina/eina_promise.h \
-lib/eina/eina_bezier.h
+lib/eina/eina_bezier.h \
+lib/eina/eina_safepointer.h
lib_eina_libeina_la_SOURCES = \
lib/eina/eina_abi.c \
@@ -168,7 +169,8 @@ lib/eina/eina_share_common.h \
lib/eina/eina_strbuf_common.h \
lib/eina/eina_quaternion.c \
lib/eina/eina_promise.c \
-lib/eina/eina_bezier.c
+lib/eina/eina_bezier.c \
+lib/eina/eina_safepointer.c
if HAVE_WIN32
lib_eina_libeina_la_SOURCES += lib/eina/eina_file_win32.c
diff --git a/src/lib/eina/Eina.h b/src/lib/eina/Eina.h
index fe0a4ec108..e57660e233 100644
--- a/src/lib/eina/Eina.h
+++ b/src/lib/eina/Eina.h
@@ -270,6 +270,7 @@ extern "C" {
#include <eina_quaternion.h>
#include <eina_promise.h>
#include <eina_bezier.h>
+#include <eina_safepointer.h>
#undef EAPI
#define EAPI
diff --git a/src/lib/eina/eina_config.h.in b/src/lib/eina/eina_config.h.in
index 9ec3b29372..ab970ef0fa 100644
--- a/src/lib/eina/eina_config.h.in
+++ b/src/lib/eina/eina_config.h.in
@@ -67,6 +67,11 @@
#endif
#define EINA_SIZEOF_WCHAR_T @EINA_SIZEOF_WCHAR_T@
+#ifdef EINA_SIZEOF_UINTPTR_T
+# undef EINA_SIZEOF_UINTPTR_T
+#endif
+#define EINA_SIZEOF_UINTPTR_T @EINA_SIZEOF_UINTPTR_T@
+
#ifdef EINA_CONFIGURE_HAVE_DIRENT_H
# undef EINA_CONFIGURE_HAVE_DIRENT_H
#endif
diff --git a/src/lib/eina/eina_inline_safepointer.x b/src/lib/eina/eina_inline_safepointer.x
new file mode 100644
index 0000000000..7c4cd5505c
--- /dev/null
+++ b/src/lib/eina/eina_inline_safepointer.x
@@ -0,0 +1,188 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2015-2016 Carsten Haitzler, 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/>.
+ */
+
+#ifndef EINA_SAFEPOINTER_INLINE_H_
+#define EINA_SAFEPOINTER_INLINE_H_
+
+#include <eina_trash.h>
+#include <eina_log.h>
+
+typedef struct _Eina_Memory_Table Eina_Memory_Table;
+typedef struct _Eina_Memory_Entry Eina_Memory_Entry;
+typedef uintptr_t Eina_Sp_Id;
+
+#if EINA_SIZEOF_UINTPTR_T == 4
+/* 32 bits */
+# define EINA_BITS_MID_TABLE_ID 5
+# define EINA_BITS_TABLE_ID 5
+# define EINA_BITS_ENTRY_ID 12
+# define EINA_BITS_GENERATION_COUNTER 8
+# define EINA_BITS_FREE_COUNTER 2
+# define EINA_DROPPED_TABLES 0
+# define EINA_DROPPED_ENTRIES 3
+typedef int16_t Eina_Table_Index;
+typedef uint16_t Eina_Generation_Counter;
+#else
+/* 64 bits */
+# define EINA_BITS_MID_TABLE_ID 11
+# define EINA_BITS_TABLE_ID 11
+# define EINA_BITS_ENTRY_ID 12
+# define EINA_BITS_GENERATION_COUNTER 28
+# define EINA_BITS_FREE_COUNTER 2
+# define EINA_DROPPED_TABLES 2
+# define EINA_DROPPED_ENTRIES 2
+typedef int16_t Eina_Table_Index;
+typedef uint32_t Eina_Generation_Counter;
+#endif
+
+/* Shifts macros to manipulate the SP id */
+#define EINA_SHIFT_GENERATION (EINA_BITS_FREE_COUNTER)
+#define EINA_SHIFT_ENTRY_ID (EINA_SHIFT_GENERATION + \
+ EINA_BITS_GENERATION_COUNTER)
+#define EINA_SHIFT_TABLE_ID (EINA_SHIFT_ENTRY_ID + \
+ EINA_BITS_ENTRY_ID)
+#define EINA_SHIFT_MID_TABLE_ID (EINA_SHIFT_TABLE_ID + \
+ EINA_BITS_TABLE_ID)
+
+/* Maximum ranges - a few tables and entries are dropped to minimize the amount
+ * of wasted bytes, see _eina_safepointer_calloc */
+#define EINA_MAX_MID_TABLE_ID (1 << EINA_BITS_MID_TABLE_ID)
+#define EINA_MAX_TABLE_ID ((1 << EINA_BITS_TABLE_ID) - EINA_DROPPED_TABLES )
+#define EINA_MAX_ENTRY_ID ((1 << EINA_BITS_ENTRY_ID) - EINA_DROPPED_ENTRIES)
+#define EINA_MAX_GENERATIONS (1 << EINA_BITS_GENERATION_COUNTER)
+
+/* Masks */
+#define EINA_MASK_MID_TABLE_ID (EINA_MAX_MID_TABLE_ID - 1)
+#define EINA_MASK_TABLE_ID ((1 << EINA_BITS_TABLE_ID) - 1)
+#define EINA_MASK_ENTRY_ID ((1 << EINA_BITS_ENTRY_ID) - 1)
+#define EINA_MASK_GENERATIONS (EINA_MAX_GENERATIONS - 1)
+
+
+/* Macro to extract from an Eo id the indexes of the tables */
+#define EINA_SP_DECOMPOSE_ID(ID, MID_TABLE, TABLE, ENTRY, GENERATION) \
+ MID_TABLE = (ID >> EINA_SHIFT_MID_TABLE_ID) & EINA_MASK_MID_TABLE_ID; \
+ TABLE = (ID >> EINA_SHIFT_TABLE_ID) & EINA_MASK_TABLE_ID; \
+ ENTRY = (ID >> EINA_SHIFT_ENTRY_ID) & EINA_MASK_ENTRY_ID; \
+ GENERATION = (ID >> EINA_SHIFT_GENERATION) & EINA_MASK_GENERATIONS;
+
+struct _Eina_Memory_Entry
+{
+ /* Pointer to the object or
+ Eina_Trash entry if not active */
+ void *ptr;
+
+ unsigned int active : 1;
+ /* Valid generation for this entry */
+ unsigned int generation : EINA_BITS_GENERATION_COUNTER;
+};
+
+struct _Eina_Memory_Table
+{
+ /* Pointer to the first recycled entry */
+ Eina_Trash *trash;
+
+ /* Packed mid table and table indexes */
+ Eina_Sp_Id partial_id;
+
+ /* Indicates where start the "never used" entries */
+ Eina_Table_Index start;
+
+ /* Entries of the table holding real pointers and generations */
+ Eina_Memory_Entry entries[EINA_MAX_ENTRY_ID];
+};
+
+EAPI extern Eina_Memory_Table **_eina_sp_ids_tables[EINA_MAX_MID_TABLE_ID];
+EAPI extern int _eina_sp_log_dom;
+
+#ifdef _EINA_SP_ERR
+#undef _EINA_SP_ERR
+#endif
+#define _EINA_SP_ERR(...) EINA_LOG_DOM_ERR(_eina_sp_log_dom, __VA_ARGS__)
+
+static inline Eina_Memory_Entry *
+_eina_safepointer_entry_get(const Eina_Safepointer *safe,
+ Eina_Memory_Table **rtable)
+{
+ Eina_Table_Index mid_table_id, table_id, entry_id;
+ Eina_Generation_Counter generation;
+ Eina_Sp_Id id = (Eina_Sp_Id) safe;
+
+ EINA_SP_DECOMPOSE_ID(id, mid_table_id, table_id, entry_id, generation);
+
+ if (_eina_sp_ids_tables[mid_table_id] &&
+ _eina_sp_ids_tables[mid_table_id][table_id] &&
+ entry_id < EINA_MAX_ENTRY_ID)
+ {
+ Eina_Memory_Table *table;
+ Eina_Memory_Entry *entry;
+
+ table = _eina_sp_ids_tables[mid_table_id][table_id];
+ entry = &(table->entries[entry_id]);
+
+ if (entry->active &&
+ entry->generation == generation)
+ {
+ if (rtable) *rtable = table;
+ return entry;
+ }
+ }
+
+ _EINA_SP_ERR("Pointer %p is not a pointer to a valid object.", (void *) safe);
+
+ return NULL;
+}
+
+static inline void *
+eina_safepointer_get(const Eina_Safepointer *safe)
+{
+ Eina_Memory_Entry *entry;
+
+ if (!safe) return NULL;
+
+ entry = _eina_safepointer_entry_get(safe, NULL);
+ if (!entry) return NULL;
+
+ return entry->ptr;
+}
+
+#undef _EINA_SP_ERR
+
+#ifndef _EINA_INTERNAL_SAFEPOINTER
+
+#undef EINA_BITS_MID_TABLE_ID
+#undef EINA_BITS_TABLE_ID
+#undef EINA_BITS_ENTRY_ID
+#undef EINA_BITS_GENERATION_COUNTER
+#undef EINA_DROPPED_TABLES
+#undef EINA_DROPPED_ENTRIES
+#undef EINA_SHIFT_MID_TABLE_ID
+#undef EINA_SHIFT_TABLE_ID
+#undef EINA_SHIFT_ENTRY_ID
+#undef EINA_MAX_MID_TABLE_ID
+#undef EINA_MAX_TABLE_ID
+#undef EINA_MAX_ENTRY_ID
+#undef EINA_MAX_GENERATIONS
+#undef EINA_MASK_MID_TABLE_ID
+#undef EINA_MASK_TABLE_ID
+#undef EINA_MASK_ENTRY_ID
+#undef EINA_MASK_GENERATIONS
+#undef EINA_SP_DECOMPOSE_ID
+
+#endif
+
+#endif
diff --git a/src/lib/eina/eina_main.c b/src/lib/eina/eina_main.c
index 52c548e5e5..4cdb4068a3 100644
--- a/src/lib/eina/eina_main.c
+++ b/src/lib/eina/eina_main.c
@@ -155,6 +155,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL;
S(thread_queue);
S(rbtree);
S(promise);
+ S(safepointer);
/* no model for now
S(model);
*/
@@ -202,7 +203,8 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
S(cpu),
S(thread_queue),
S(rbtree),
- S(promise)
+ S(promise),
+ S(safepointer)
/* no model for now
S(model)
*/
diff --git a/src/lib/eina/eina_safepointer.c b/src/lib/eina/eina_safepointer.c
new file mode 100644
index 0000000000..8336ea0780
--- /dev/null
+++ b/src/lib/eina/eina_safepointer.c
@@ -0,0 +1,362 @@
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "eina_config.h"
+#include "eina_private.h"
+
+#define _EINA_INTERNAL_SAFEPOINTER
+#include "eina_safepointer.h"
+#include "eina_mempool.h"
+#include "eina_trash.h"
+#include "eina_log.h"
+#include "eina_lock.h"
+
+typedef struct _Eina_Memory_Header Eina_Memory_Header;
+
+#ifdef ERR
+#undef ERR
+#endif
+#define ERR(...) EINA_LOG_DOM_ERR(_eina_sp_log_dom, __VA_ARGS__)
+
+#ifdef DBG
+#undef DBG
+#endif
+#define DBG(...) EINA_LOG_DOM_DBG(_eina_sp_log_dom, __VA_ARGS__)
+
+/* Macro used to compose an Eo id */
+#define SP_COMPOSE_PARTIAL_ID(MID_TABLE, TABLE) \
+ ( \
+ ((Eina_Sp_Id)(MID_TABLE & EINA_MASK_MID_TABLE_ID) << EINA_SHIFT_MID_TABLE_ID) | \
+ ((Eina_Sp_Id)(TABLE & EINA_MASK_TABLE_ID) << EINA_SHIFT_TABLE_ID) \
+ )
+
+#define SP_COMPOSE_FINAL_ID(PARTIAL_ID, ENTRY, GENERATION) \
+ (PARTIAL_ID | \
+ ((ENTRY & EINA_MASK_ENTRY_ID) << EINA_SHIFT_ENTRY_ID) | \
+ ((GENERATION & EINA_MASK_GENERATIONS) << EINA_SHIFT_GENERATION))
+
+struct _Eina_Memory_Header
+{
+ EINA_MAGIC;
+ size_t size;
+};
+
+EAPI Eina_Memory_Table **_eina_sp_ids_tables[EINA_MAX_MID_TABLE_ID] = { NULL };
+EAPI int _eina_sp_log_dom = -1;
+
+/* Spare empty table */
+static Eina_Memory_Table *empty_table = NULL;
+
+// We are using a Spinlock even with the amount of syscall we do as it shouldn't
+// take that long anyway.
+static Eina_Spinlock sl;
+
+#define MEM_PAGE_SIZE 4096
+#define SAFEPOINTER_MAGIC 0x7DEADC03
+
+static void *
+_eina_safepointer_calloc(int number, size_t size)
+{
+#ifdef HAVE_MMAP
+ Eina_Memory_Header *header;
+ size_t newsize;
+
+ size = size * number + sizeof (Eina_Memory_Header);
+ newsize = ((size / MEM_PAGE_SIZE) +
+ (size % MEM_PAGE_SIZE ? 1 : 0))
+ * MEM_PAGE_SIZE;
+
+ header = mmap(NULL, newsize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (header == MAP_FAILED)
+ {
+ ERR("mmap of Eina_Safepointer table region failed.");
+ return NULL;
+ }
+
+ header->size = newsize;
+ EINA_MAGIC_SET(header, SAFEPOINTER_MAGIC);
+
+ return (void*)(header + 1);
+#else
+ return calloc(number, size);
+#endif
+}
+
+static void
+_eina_safepointer_free(void *pointer)
+{
+#ifdef HAVE_MMAP
+ Eina_Memory_Header *header;
+
+ if (!pointer) return ;
+
+ header = (Eina_Memory_Header*)(pointer) - 1;
+ if (!EINA_MAGIC_CHECK(header, SAFEPOINTER_MAGIC))
+ EINA_MAGIC_FAIL(header, SAFEPOINTER_MAGIC);
+
+ EINA_MAGIC_SET(header, 0);
+ munmap(header, header->size);
+#else
+ free((void*) ((uintptr_t) pointer & ~0x3));
+#endif
+}
+
+#ifdef EINA_DEBUG_MALLOC
+static void
+_eina_safepointer_protect(void *pointer, Eina_Bool may_not_write)
+{
+#ifdef HAVE_MMAP
+ Eina_Memory_Header *header;
+
+ if (!pointer) return ;
+
+ header = (Eina_Memory_Header*)(pointer) - 1;
+ if (!EINA_MAGIC_CHECK(header, SAFEPOINTER_MAGIC))
+ EINA_MAGIC_FAIL(header, SAFEPOINTER_MAGIC);
+
+ mprotect(header, header->size, PROT_READ | ( may_not_write ? 0 : PROT_WRITE));
+#else
+ (void) pointer;
+#endif
+}
+
+#define PROTECT(Ptr) _eina_safepointer_protect(Ptr, EINA_TRUE)
+#define UNPROTECT(Ptr) _eina_safepointer_protect(Ptr, EINA_FALSE)
+
+#else
+
+#define PROTECT(Ptr)
+#define UNPROTECT(Ptr)
+
+#endif
+
+static Eina_Memory_Table *
+_eina_safepointer_table_new(Eina_Table_Index mid_table_id,
+ Eina_Table_Index table_id)
+{
+ Eina_Memory_Table *table;
+
+ if (empty_table)
+ {
+ /* Recycle the available empty table */
+ table = empty_table;
+ empty_table = NULL;
+ UNPROTECT(table);
+ }
+ else
+ {
+ table = _eina_safepointer_calloc(1, sizeof (Eina_Memory_Table));
+ if (!table)
+ {
+ ERR("Failed to allocate leaf table at [%i][%i]", mid_table_id, table_id);
+ return NULL;
+ }
+ }
+
+ table->partial_id = SP_COMPOSE_PARTIAL_ID(mid_table_id,
+ table_id);
+ PROTECT(table);
+ UNPROTECT(_eina_sp_ids_tables[mid_table_id]);
+ _eina_sp_ids_tables[mid_table_id][table_id] = table;
+ PROTECT(_eina_sp_ids_tables[mid_table_id]);
+
+ return table;
+}
+
+static Eina_Memory_Table *
+_eina_safepointer_table_find(void)
+{
+ Eina_Table_Index mid_table_id;
+
+ for (mid_table_id = 0; mid_table_id < EINA_MAX_MID_TABLE_ID; mid_table_id++)
+ {
+ Eina_Table_Index table_id;
+
+ if (!_eina_sp_ids_tables[mid_table_id])
+ {
+ _eina_sp_ids_tables[mid_table_id] = _eina_safepointer_calloc(EINA_MAX_TABLE_ID, sizeof (Eina_Memory_Table*));
+ }
+ if (!_eina_sp_ids_tables[mid_table_id])
+ {
+ ERR("Failed to allocate mid table at [%i]", mid_table_id);
+ return NULL;
+ }
+
+ for (table_id = 0; table_id < EINA_MAX_TABLE_ID; table_id++)
+ {
+ Eina_Memory_Table *table;
+
+ table = _eina_sp_ids_tables[mid_table_id][table_id];
+
+ if (!table)
+ table = _eina_safepointer_table_new(mid_table_id, table_id);
+
+ if (!table) return NULL;
+
+ if (table->trash ||
+ table->start < EINA_MAX_ENTRY_ID)
+ return table;
+ }
+ }
+
+ return NULL;
+}
+
+static Eina_Memory_Entry *
+_eina_safepointer_entry_find(Eina_Memory_Table *table)
+{
+ Eina_Memory_Entry *entry = NULL;
+
+ if (table->trash)
+ {
+ entry = eina_trash_pop(&table->trash);
+ }
+ else if (table->start < EINA_MAX_ENTRY_ID)
+ {
+ entry = &(table->entries[table->start]);
+ table->start++;
+ }
+ else
+ {
+ ERR("Impossible to find an entry in %" PRIxPTR ".", table->partial_id);
+ }
+
+ return entry;
+}
+
+EAPI const Eina_Safepointer *
+eina_safepointer_register(const void *target)
+{
+ Eina_Memory_Table *table;
+ Eina_Memory_Entry *entry = NULL;
+ Eina_Sp_Id id = 0;
+
+ // We silently handle NULL
+ if (!target) return NULL;
+
+ eina_spinlock_take(&sl);
+
+ table = _eina_safepointer_table_find();
+ if (!table) goto no_table;
+
+ UNPROTECT(table);
+ entry = _eina_safepointer_entry_find(table);
+ if (!entry) goto on_error;
+
+ entry->ptr = (void*) target;
+ entry->active = 1;
+ entry->generation++;
+ if (entry->generation == EINA_MAX_GENERATIONS)
+ entry->generation = 1;
+
+ id = SP_COMPOSE_FINAL_ID(table->partial_id,
+ (entry - table->entries),
+ entry->generation);
+
+ on_error:
+ PROTECT(table);
+ no_table:
+ eina_spinlock_release(&sl);
+
+ return (void*) id;
+}
+
+EAPI void
+eina_safepointer_unregister(const Eina_Safepointer *safe)
+{
+ Eina_Memory_Table *table;
+ Eina_Memory_Entry *entry;
+ Eina_Table_Index entry_id;
+
+ // We silently handle NULL
+ if (!safe) return ;
+
+ entry = _eina_safepointer_entry_get(safe, &table);
+ if (!entry) return ;
+
+ eina_spinlock_take(&sl);
+
+ // In case of a race condition during a double free attempt
+ // The entry could have been unactivated since we did found it
+ // So check again.
+ if (!entry->active) goto on_error;
+
+ UNPROTECT(table);
+ entry->active = 0;
+ eina_trash_push(&table->trash, entry);
+ PROTECT(table);
+
+ entry_id = entry - table->entries;
+ if (entry_id == EINA_MAX_ENTRY_ID - 1)
+ {
+ Eina_Table_Index i;
+
+ for (i = entry_id; i >= 0; i--)
+ {
+ if (table->entries[i].active)
+ break ;
+ }
+
+ // No more active entry
+ // Could be speed up by tracking the
+ // number of allocated entries, but
+ // with all the syscall around, not sure
+ // it is worth it.
+ if (i == -1)
+ {
+ Eina_Table_Index mid_table_id, table_id;
+
+ mid_table_id = (table->partial_id >> EINA_SHIFT_MID_TABLE_ID) & EINA_MASK_MID_TABLE_ID;
+ table_id = (table->partial_id >> EINA_SHIFT_TABLE_ID) & EINA_MASK_TABLE_ID;
+ UNPROTECT(_eina_sp_ids_tables[mid_table_id]);
+ _eina_sp_ids_tables[mid_table_id][table_id] = NULL;
+ PROTECT(_eina_sp_ids_tables[mid_table_id]);
+ if (!empty_table)
+ empty_table = table;
+ else
+ _eina_safepointer_free(table);
+ }
+ }
+
+ on_error:
+ eina_spinlock_release(&sl);
+}
+
+Eina_Bool
+eina_safepointer_init(void)
+{
+ eina_magic_string_set(SAFEPOINTER_MAGIC, "Safepointer");
+ _eina_sp_log_dom = eina_log_domain_register("eina_safepointer",
+ EINA_LOG_COLOR_DEFAULT);
+ if (_eina_sp_log_dom < 0)
+ {
+ EINA_LOG_ERR("Could not register log domain: eina_safepointer.");
+ return EINA_FALSE;
+ }
+
+ eina_spinlock_new(&sl);
+
+ DBG("entry[Size, Align] = { %zu, %u }",
+ sizeof (Eina_Memory_Entry), eina_mempool_alignof(sizeof (Eina_Memory_Entry)));
+ DBG("table[Size, Align] = { %zu, %u }\n",
+ sizeof (Eina_Memory_Table), eina_mempool_alignof(sizeof (Eina_Memory_Table)));
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+eina_safepointer_shutdown(void)
+{
+ eina_spinlock_free(&sl);
+
+ return EINA_TRUE;
+}
diff --git a/src/lib/eina/eina_safepointer.h b/src/lib/eina/eina_safepointer.h
new file mode 100644
index 0000000000..02ee2763e7
--- /dev/null
+++ b/src/lib/eina/eina_safepointer.h
@@ -0,0 +1,115 @@
+/* EINA - EFL data type library
+ * Copyright (C) 2015-2016 Carsten Haitzler, 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/>.
+ */
+
+#ifndef EINA_SAFEPOINTER_H__
+#define EINA_SAFEPOINTER_H__
+
+/**
+ * @addtogroup Eina_Safepointer_Group Safe Pointer
+ *
+ * @brief These functions provide a wrapper that protect access to pointers
+ *
+ * Eina_Safepointer is an pointer to index converter that allow an increased
+ * level of safety by forbidding direct access to the pointer. The protection
+ * work by using a set of indirection table that are mmapped and mprotected
+ * against write access. This the pointer they store and that map to a specific
+ * index is always correct. Also once a pointer is unregistered the index
+ * won't be served back for 2^8 on 32 bits system and 2^28 on 64 bits system
+ * for that specific slot. Finally we do guarantee that the lower 2 bits of the
+ * returned index are actually never used and completly ignored by our API.
+ * So you can safely store whatever information you want in it, we will ignore
+ * it and threat as if it wasn't there.
+ *
+ * @note The use of Eina_Safepointer is thread safe.
+ */
+
+/**
+ * @addtogroup Eina_Data_Types_Group Data Types
+ *
+ * @{
+ */
+
+/**
+ * @addtogroup Eina_Containers_Group Containers
+ *
+ * @{
+ */
+
+/**
+ * @defgroup Eina_Safepointer_Group Safe Pointer
+ *
+ * @{
+ */
+
+/**
+ * @typedef Eina_Safepointer
+ * Type of the protected index.
+ */
+typedef struct _Eina_Safepointer Eina_Safepointer;
+
+/**
+ * @brief Register a pointer and get an Eina_Safepointer that map to it.
+ *
+ * @param target The pointer to register.
+ * @return A valid pointer that is an index to the mapped pointer.
+ *
+ * @note It will return @c NULL on error or if @p target is @c NULL.
+ *
+ * @note The lower 2 bits of the returned pointer will always be 0.
+ *
+ * @note The returned pointer can be used like a pointer, but can not
+ * be touched except with Eina_Safepointer functions.
+ */
+EAPI const Eina_Safepointer *eina_safepointer_register(const void *target);
+
+/**
+ * @brief Unregister an Eina_Safepointer and the pointer that map to it.
+ *
+ * @param safe The index to unregister from the mapping.
+ *
+ * @note This function will ignore the lower 2 bits of the given pointer.
+ */
+EAPI void eina_safepointer_unregister(const Eina_Safepointer *safe);
+
+/**
+ * @brief Get the associated pointer from an Eina_Safepointer mapping.
+ *
+ * @param safe The Eina_Safepointer index to lookup at.
+ * @return The pointer registered with that index or @c NULL in any other case.
+ *
+ * @note It is always safe to ask for a pointer for any value of the mapping.
+ * If the pointer is invalid or @c NULL, we will return @c NULL and not crash.
+ */
+static inline void *eina_safepointer_get(const Eina_Safepointer *safe);
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+/**
+ * @}
+ */
+
+
+# include "eina_inline_safepointer.x"
+
+#endif