cedric pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=692b2c9fc9b347fc0be80b674d4580648e2f6541

commit 692b2c9fc9b347fc0be80b674d4580648e2f6541
Author: Cedric BAIL <[email protected]>
Date:   Fri Jun 10 13:42:19 2016 -0700

    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.
---
 configure.ac                           |   2 +
 src/Makefile_Eina.am                   |   6 +-
 src/lib/eina/Eina.h                    |   1 +
 src/lib/eina/eina_config.h.in          |   5 +
 src/lib/eina/eina_inline_safepointer.x | 188 +++++++++++++++++
 src/lib/eina/eina_main.c               |   4 +-
 src/lib/eina/eina_safepointer.c        | 362 +++++++++++++++++++++++++++++++++
 src/lib/eina/eina_safepointer.h        | 115 +++++++++++
 8 files changed, 680 insertions(+), 3 deletions(-)

diff --git a/configure.ac b/configure.ac
index 676624f..f37f3a5 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 1b6bdff..602c3db 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 fe0a4ec..e57660e 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 9ec3b29..ab970ef 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 0000000..7c4cd55
--- /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 52c548e..4cdb406 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 0000000..8336ea0
--- /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 0000000..02ee276
--- /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

-- 


Reply via email to