summaryrefslogtreecommitdiff
path: root/src
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 /src
parent5964008946abad2b8c4fac019b3f2ea090a7498d (diff)
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.
Diffstat (limited to 'src')
-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
7 files changed, 678 insertions, 3 deletions
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 \
97lib/eina/eina_vector.h \ 97lib/eina/eina_vector.h \
98lib/eina/eina_inline_vector.x \ 98lib/eina/eina_inline_vector.x \
99lib/eina/eina_promise.h \ 99lib/eina/eina_promise.h \
100lib/eina/eina_bezier.h 100lib/eina/eina_bezier.h \
101lib/eina/eina_safepointer.h
101 102
102lib_eina_libeina_la_SOURCES = \ 103lib_eina_libeina_la_SOURCES = \
103lib/eina/eina_abi.c \ 104lib/eina/eina_abi.c \
@@ -168,7 +169,8 @@ lib/eina/eina_share_common.h \
168lib/eina/eina_strbuf_common.h \ 169lib/eina/eina_strbuf_common.h \
169lib/eina/eina_quaternion.c \ 170lib/eina/eina_quaternion.c \
170lib/eina/eina_promise.c \ 171lib/eina/eina_promise.c \
171lib/eina/eina_bezier.c 172lib/eina/eina_bezier.c \
173lib/eina/eina_safepointer.c
172 174
173if HAVE_WIN32 175if HAVE_WIN32
174lib_eina_libeina_la_SOURCES += lib/eina/eina_file_win32.c 176lib_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" {
270#include <eina_quaternion.h> 270#include <eina_quaternion.h>
271#include <eina_promise.h> 271#include <eina_promise.h>
272#include <eina_bezier.h> 272#include <eina_bezier.h>
273#include <eina_safepointer.h>
273 274
274#undef EAPI 275#undef EAPI
275#define EAPI 276#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 @@
67#endif 67#endif
68#define EINA_SIZEOF_WCHAR_T @EINA_SIZEOF_WCHAR_T@ 68#define EINA_SIZEOF_WCHAR_T @EINA_SIZEOF_WCHAR_T@
69 69
70#ifdef EINA_SIZEOF_UINTPTR_T
71# undef EINA_SIZEOF_UINTPTR_T
72#endif
73#define EINA_SIZEOF_UINTPTR_T @EINA_SIZEOF_UINTPTR_T@
74
70#ifdef EINA_CONFIGURE_HAVE_DIRENT_H 75#ifdef EINA_CONFIGURE_HAVE_DIRENT_H
71# undef EINA_CONFIGURE_HAVE_DIRENT_H 76# undef EINA_CONFIGURE_HAVE_DIRENT_H
72#endif 77#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 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2015-2016 Carsten Haitzler, Cedric Bail
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef EINA_SAFEPOINTER_INLINE_H_
20#define EINA_SAFEPOINTER_INLINE_H_
21
22#include <eina_trash.h>
23#include <eina_log.h>
24
25typedef struct _Eina_Memory_Table Eina_Memory_Table;
26typedef struct _Eina_Memory_Entry Eina_Memory_Entry;
27typedef uintptr_t Eina_Sp_Id;
28
29#if EINA_SIZEOF_UINTPTR_T == 4
30/* 32 bits */
31# define EINA_BITS_MID_TABLE_ID 5
32# define EINA_BITS_TABLE_ID 5
33# define EINA_BITS_ENTRY_ID 12
34# define EINA_BITS_GENERATION_COUNTER 8
35# define EINA_BITS_FREE_COUNTER 2
36# define EINA_DROPPED_TABLES 0
37# define EINA_DROPPED_ENTRIES 3
38typedef int16_t Eina_Table_Index;
39typedef uint16_t Eina_Generation_Counter;
40#else
41/* 64 bits */
42# define EINA_BITS_MID_TABLE_ID 11
43# define EINA_BITS_TABLE_ID 11
44# define EINA_BITS_ENTRY_ID 12
45# define EINA_BITS_GENERATION_COUNTER 28
46# define EINA_BITS_FREE_COUNTER 2
47# define EINA_DROPPED_TABLES 2
48# define EINA_DROPPED_ENTRIES 2
49typedef int16_t Eina_Table_Index;
50typedef uint32_t Eina_Generation_Counter;
51#endif
52
53/* Shifts macros to manipulate the SP id */
54#define EINA_SHIFT_GENERATION (EINA_BITS_FREE_COUNTER)
55#define EINA_SHIFT_ENTRY_ID (EINA_SHIFT_GENERATION + \
56 EINA_BITS_GENERATION_COUNTER)
57#define EINA_SHIFT_TABLE_ID (EINA_SHIFT_ENTRY_ID + \
58 EINA_BITS_ENTRY_ID)
59#define EINA_SHIFT_MID_TABLE_ID (EINA_SHIFT_TABLE_ID + \
60 EINA_BITS_TABLE_ID)
61
62/* Maximum ranges - a few tables and entries are dropped to minimize the amount
63 * of wasted bytes, see _eina_safepointer_calloc */
64#define EINA_MAX_MID_TABLE_ID (1 << EINA_BITS_MID_TABLE_ID)
65#define EINA_MAX_TABLE_ID ((1 << EINA_BITS_TABLE_ID) - EINA_DROPPED_TABLES )
66#define EINA_MAX_ENTRY_ID ((1 << EINA_BITS_ENTRY_ID) - EINA_DROPPED_ENTRIES)
67#define EINA_MAX_GENERATIONS (1 << EINA_BITS_GENERATION_COUNTER)
68
69/* Masks */
70#define EINA_MASK_MID_TABLE_ID (EINA_MAX_MID_TABLE_ID - 1)
71#define EINA_MASK_TABLE_ID ((1 << EINA_BITS_TABLE_ID) - 1)
72#define EINA_MASK_ENTRY_ID ((1 << EINA_BITS_ENTRY_ID) - 1)
73#define EINA_MASK_GENERATIONS (EINA_MAX_GENERATIONS - 1)
74
75
76/* Macro to extract from an Eo id the indexes of the tables */
77#define EINA_SP_DECOMPOSE_ID(ID, MID_TABLE, TABLE, ENTRY, GENERATION) \
78 MID_TABLE = (ID >> EINA_SHIFT_MID_TABLE_ID) & EINA_MASK_MID_TABLE_ID; \
79 TABLE = (ID >> EINA_SHIFT_TABLE_ID) & EINA_MASK_TABLE_ID; \
80 ENTRY = (ID >> EINA_SHIFT_ENTRY_ID) & EINA_MASK_ENTRY_ID; \
81 GENERATION = (ID >> EINA_SHIFT_GENERATION) & EINA_MASK_GENERATIONS;
82
83struct _Eina_Memory_Entry
84{
85 /* Pointer to the object or
86 Eina_Trash entry if not active */
87 void *ptr;
88
89 unsigned int active : 1;
90 /* Valid generation for this entry */
91 unsigned int generation : EINA_BITS_GENERATION_COUNTER;
92};
93
94struct _Eina_Memory_Table
95{
96 /* Pointer to the first recycled entry */
97 Eina_Trash *trash;
98
99 /* Packed mid table and table indexes */
100 Eina_Sp_Id partial_id;
101
102 /* Indicates where start the "never used" entries */
103 Eina_Table_Index start;
104
105 /* Entries of the table holding real pointers and generations */
106 Eina_Memory_Entry entries[EINA_MAX_ENTRY_ID];
107};
108
109EAPI extern Eina_Memory_Table **_eina_sp_ids_tables[EINA_MAX_MID_TABLE_ID];
110EAPI extern int _eina_sp_log_dom;
111
112#ifdef _EINA_SP_ERR
113#undef _EINA_SP_ERR
114#endif
115#define _EINA_SP_ERR(...) EINA_LOG_DOM_ERR(_eina_sp_log_dom, __VA_ARGS__)
116
117static inline Eina_Memory_Entry *
118_eina_safepointer_entry_get(const Eina_Safepointer *safe,
119 Eina_Memory_Table **rtable)
120{
121 Eina_Table_Index mid_table_id, table_id, entry_id;
122 Eina_Generation_Counter generation;
123 Eina_Sp_Id id = (Eina_Sp_Id) safe;
124
125 EINA_SP_DECOMPOSE_ID(id, mid_table_id, table_id, entry_id, generation);
126
127 if (_eina_sp_ids_tables[mid_table_id] &&
128 _eina_sp_ids_tables[mid_table_id][table_id] &&
129 entry_id < EINA_MAX_ENTRY_ID)
130 {
131 Eina_Memory_Table *table;
132 Eina_Memory_Entry *entry;
133
134 table = _eina_sp_ids_tables[mid_table_id][table_id];
135 entry = &(table->entries[entry_id]);
136
137 if (entry->active &&
138 entry->generation == generation)
139 {
140 if (rtable) *rtable = table;
141 return entry;
142 }
143 }
144
145 _EINA_SP_ERR("Pointer %p is not a pointer to a valid object.", (void *) safe);
146
147 return NULL;
148}
149
150static inline void *
151eina_safepointer_get(const Eina_Safepointer *safe)
152{
153 Eina_Memory_Entry *entry;
154
155 if (!safe) return NULL;
156
157 entry = _eina_safepointer_entry_get(safe, NULL);
158 if (!entry) return NULL;
159
160 return entry->ptr;
161}
162
163#undef _EINA_SP_ERR
164
165#ifndef _EINA_INTERNAL_SAFEPOINTER
166
167#undef EINA_BITS_MID_TABLE_ID
168#undef EINA_BITS_TABLE_ID
169#undef EINA_BITS_ENTRY_ID
170#undef EINA_BITS_GENERATION_COUNTER
171#undef EINA_DROPPED_TABLES
172#undef EINA_DROPPED_ENTRIES
173#undef EINA_SHIFT_MID_TABLE_ID
174#undef EINA_SHIFT_TABLE_ID
175#undef EINA_SHIFT_ENTRY_ID
176#undef EINA_MAX_MID_TABLE_ID
177#undef EINA_MAX_TABLE_ID
178#undef EINA_MAX_ENTRY_ID
179#undef EINA_MAX_GENERATIONS
180#undef EINA_MASK_MID_TABLE_ID
181#undef EINA_MASK_TABLE_ID
182#undef EINA_MASK_ENTRY_ID
183#undef EINA_MASK_GENERATIONS
184#undef EINA_SP_DECOMPOSE_ID
185
186#endif
187
188#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;
155 S(thread_queue); 155 S(thread_queue);
156 S(rbtree); 156 S(rbtree);
157 S(promise); 157 S(promise);
158 S(safepointer);
158/* no model for now 159/* no model for now
159 S(model); 160 S(model);
160 */ 161 */
@@ -202,7 +203,8 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
202 S(cpu), 203 S(cpu),
203 S(thread_queue), 204 S(thread_queue),
204 S(rbtree), 205 S(rbtree),
205 S(promise) 206 S(promise),
207 S(safepointer)
206/* no model for now 208/* no model for now
207 S(model) 209 S(model)
208 */ 210 */
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 @@
1#ifdef HAVE_CONFIG_H
2# include "config.h"
3#endif
4
5#include <stdint.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <sys/mman.h>
9#include <fcntl.h>
10#include <inttypes.h>
11
12#include "eina_config.h"
13#include "eina_private.h"
14
15#define _EINA_INTERNAL_SAFEPOINTER
16#include "eina_safepointer.h"
17#include "eina_mempool.h"
18#include "eina_trash.h"
19#include "eina_log.h"
20#include "eina_lock.h"
21
22typedef struct _Eina_Memory_Header Eina_Memory_Header;
23
24#ifdef ERR
25#undef ERR
26#endif
27#define ERR(...) EINA_LOG_DOM_ERR(_eina_sp_log_dom, __VA_ARGS__)
28
29#ifdef DBG
30#undef DBG
31#endif
32#define DBG(...) EINA_LOG_DOM_DBG(_eina_sp_log_dom, __VA_ARGS__)
33
34/* Macro used to compose an Eo id */
35#define SP_COMPOSE_PARTIAL_ID(MID_TABLE, TABLE) \
36 ( \
37 ((Eina_Sp_Id)(MID_TABLE & EINA_MASK_MID_TABLE_ID) << EINA_SHIFT_MID_TABLE_ID) | \
38 ((Eina_Sp_Id)(TABLE & EINA_MASK_TABLE_ID) << EINA_SHIFT_TABLE_ID) \
39 )
40
41#define SP_COMPOSE_FINAL_ID(PARTIAL_ID, ENTRY, GENERATION) \
42 (PARTIAL_ID | \
43 ((ENTRY & EINA_MASK_ENTRY_ID) << EINA_SHIFT_ENTRY_ID) | \
44 ((GENERATION & EINA_MASK_GENERATIONS) << EINA_SHIFT_GENERATION))
45
46struct _Eina_Memory_Header
47{
48 EINA_MAGIC;
49 size_t size;
50};
51
52EAPI Eina_Memory_Table **_eina_sp_ids_tables[EINA_MAX_MID_TABLE_ID] = { NULL };
53EAPI int _eina_sp_log_dom = -1;
54
55/* Spare empty table */
56static Eina_Memory_Table *empty_table = NULL;
57
58// We are using a Spinlock even with the amount of syscall we do as it shouldn't
59// take that long anyway.
60static Eina_Spinlock sl;
61
62#define MEM_PAGE_SIZE 4096
63#define SAFEPOINTER_MAGIC 0x7DEADC03
64
65static void *
66_eina_safepointer_calloc(int number, size_t size)
67{
68#ifdef HAVE_MMAP
69 Eina_Memory_Header *header;
70 size_t newsize;
71
72 size = size * number + sizeof (Eina_Memory_Header);
73 newsize = ((size / MEM_PAGE_SIZE) +
74 (size % MEM_PAGE_SIZE ? 1 : 0))
75 * MEM_PAGE_SIZE;
76
77 header = mmap(NULL, newsize, PROT_READ | PROT_WRITE,
78 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
79 if (header == MAP_FAILED)
80 {
81 ERR("mmap of Eina_Safepointer table region failed.");
82 return NULL;
83 }
84
85 header->size = newsize;
86 EINA_MAGIC_SET(header, SAFEPOINTER_MAGIC);
87
88 return (void*)(header + 1);
89#else
90 return calloc(number, size);
91#endif
92}
93
94static void
95_eina_safepointer_free(void *pointer)
96{
97#ifdef HAVE_MMAP
98 Eina_Memory_Header *header;
99
100 if (!pointer) return ;
101
102 header = (Eina_Memory_Header*)(pointer) - 1;
103 if (!EINA_MAGIC_CHECK(header, SAFEPOINTER_MAGIC))
104 EINA_MAGIC_FAIL(header, SAFEPOINTER_MAGIC);
105
106 EINA_MAGIC_SET(header, 0);
107 munmap(header, header->size);
108#else
109 free((void*) ((uintptr_t) pointer & ~0x3));
110#endif
111}
112
113#ifdef EINA_DEBUG_MALLOC
114static void
115_eina_safepointer_protect(void *pointer, Eina_Bool may_not_write)
116{
117#ifdef HAVE_MMAP
118 Eina_Memory_Header *header;
119
120 if (!pointer) return ;
121
122 header = (Eina_Memory_Header*)(pointer) - 1;
123 if (!EINA_MAGIC_CHECK(header, SAFEPOINTER_MAGIC))
124 EINA_MAGIC_FAIL(header, SAFEPOINTER_MAGIC);
125
126 mprotect(header, header->size, PROT_READ | ( may_not_write ? 0 : PROT_WRITE));
127#else
128 (void) pointer;
129#endif
130}
131
132#define PROTECT(Ptr) _eina_safepointer_protect(Ptr, EINA_TRUE)
133#define UNPROTECT(Ptr) _eina_safepointer_protect(Ptr, EINA_FALSE)
134
135#else
136
137#define PROTECT(Ptr)
138#define UNPROTECT(Ptr)
139
140#endif
141
142static Eina_Memory_Table *
143_eina_safepointer_table_new(Eina_Table_Index mid_table_id,
144 Eina_Table_Index table_id)
145{
146 Eina_Memory_Table *table;
147
148 if (empty_table)
149 {
150 /* Recycle the available empty table */
151 table = empty_table;
152 empty_table = NULL;
153 UNPROTECT(table);
154 }
155 else
156 {
157 table = _eina_safepointer_calloc(1, sizeof (Eina_Memory_Table));
158 if (!table)
159 {
160 ERR("Failed to allocate leaf table at [%i][%i]", mid_table_id, table_id);
161 return NULL;
162 }
163 }
164
165 table->partial_id = SP_COMPOSE_PARTIAL_ID(mid_table_id,
166 table_id);
167 PROTECT(table);
168 UNPROTECT(_eina_sp_ids_tables[mid_table_id]);
169 _eina_sp_ids_tables[mid_table_id][table_id] = table;
170 PROTECT(_eina_sp_ids_tables[mid_table_id]);
171
172 return table;
173}
174
175static Eina_Memory_Table *
176_eina_safepointer_table_find(void)
177{
178 Eina_Table_Index mid_table_id;
179
180 for (mid_table_id = 0; mid_table_id < EINA_MAX_MID_TABLE_ID; mid_table_id++)
181 {
182 Eina_Table_Index table_id;
183
184 if (!_eina_sp_ids_tables[mid_table_id])
185 {
186 _eina_sp_ids_tables[mid_table_id] = _eina_safepointer_calloc(EINA_MAX_TABLE_ID, sizeof (Eina_Memory_Table*));
187 }
188 if (!_eina_sp_ids_tables[mid_table_id])
189 {
190 ERR("Failed to allocate mid table at [%i]", mid_table_id);
191 return NULL;
192 }
193
194 for (table_id = 0; table_id < EINA_MAX_TABLE_ID; table_id++)
195 {
196 Eina_Memory_Table *table;
197
198 table = _eina_sp_ids_tables[mid_table_id][table_id];
199
200 if (!table)
201 table = _eina_safepointer_table_new(mid_table_id, table_id);
202
203 if (!table) return NULL;
204
205 if (table->trash ||
206 table->start < EINA_MAX_ENTRY_ID)
207 return table;
208 }
209 }
210
211 return NULL;
212}
213
214static Eina_Memory_Entry *
215_eina_safepointer_entry_find(Eina_Memory_Table *table)
216{
217 Eina_Memory_Entry *entry = NULL;
218
219 if (table->trash)
220 {
221 entry = eina_trash_pop(&table->trash);
222 }
223 else if (table->start < EINA_MAX_ENTRY_ID)
224 {
225 entry = &(table->entries[table->start]);
226 table->start++;
227 }
228 else
229 {
230 ERR("Impossible to find an entry in %" PRIxPTR ".", table->partial_id);
231 }
232
233 return entry;
234}
235
236EAPI const Eina_Safepointer *
237eina_safepointer_register(const void *target)
238{
239 Eina_Memory_Table *table;
240 Eina_Memory_Entry *entry = NULL;
241 Eina_Sp_Id id = 0;
242
243 // We silently handle NULL
244 if (!target) return NULL;
245
246 eina_spinlock_take(&sl);
247
248 table = _eina_safepointer_table_find();
249 if (!table) goto no_table;
250
251 UNPROTECT(table);
252 entry = _eina_safepointer_entry_find(table);
253 if (!entry) goto on_error;
254
255 entry->ptr = (void*) target;
256 entry->active = 1;
257 entry->generation++;
258 if (entry->generation == EINA_MAX_GENERATIONS)
259 entry->generation = 1;
260
261 id = SP_COMPOSE_FINAL_ID(table->partial_id,
262 (entry - table->entries),
263 entry->generation);
264
265 on_error:
266 PROTECT(table);
267 no_table:
268 eina_spinlock_release(&sl);
269
270 return (void*) id;
271}
272
273EAPI void
274eina_safepointer_unregister(const Eina_Safepointer *safe)
275{
276 Eina_Memory_Table *table;
277 Eina_Memory_Entry *entry;
278 Eina_Table_Index entry_id;
279
280 // We silently handle NULL
281 if (!safe) return ;
282
283 entry = _eina_safepointer_entry_get(safe, &table);
284 if (!entry) return ;
285
286 eina_spinlock_take(&sl);
287
288 // In case of a race condition during a double free attempt
289 // The entry could have been unactivated since we did found it
290 // So check again.
291 if (!entry->active) goto on_error;
292
293 UNPROTECT(table);
294 entry->active = 0;
295 eina_trash_push(&table->trash, entry);
296 PROTECT(table);
297
298 entry_id = entry - table->entries;
299 if (entry_id == EINA_MAX_ENTRY_ID - 1)
300 {
301 Eina_Table_Index i;
302
303 for (i = entry_id; i >= 0; i--)
304 {
305 if (table->entries[i].active)
306 break ;
307 }
308
309 // No more active entry
310 // Could be speed up by tracking the
311 // number of allocated entries, but
312 // with all the syscall around, not sure
313 // it is worth it.
314 if (i == -1)
315 {
316 Eina_Table_Index mid_table_id, table_id;
317
318 mid_table_id = (table->partial_id >> EINA_SHIFT_MID_TABLE_ID) & EINA_MASK_MID_TABLE_ID;
319 table_id = (table->partial_id >> EINA_SHIFT_TABLE_ID) & EINA_MASK_TABLE_ID;
320 UNPROTECT(_eina_sp_ids_tables[mid_table_id]);
321 _eina_sp_ids_tables[mid_table_id][table_id] = NULL;
322 PROTECT(_eina_sp_ids_tables[mid_table_id]);
323 if (!empty_table)
324 empty_table = table;
325 else
326 _eina_safepointer_free(table);
327 }
328 }
329
330 on_error:
331 eina_spinlock_release(&sl);
332}
333
334Eina_Bool
335eina_safepointer_init(void)
336{
337 eina_magic_string_set(SAFEPOINTER_MAGIC, "Safepointer");
338 _eina_sp_log_dom = eina_log_domain_register("eina_safepointer",
339 EINA_LOG_COLOR_DEFAULT);
340 if (_eina_sp_log_dom < 0)
341 {
342 EINA_LOG_ERR("Could not register log domain: eina_safepointer.");
343 return EINA_FALSE;
344 }
345
346 eina_spinlock_new(&sl);
347
348 DBG("entry[Size, Align] = { %zu, %u }",
349 sizeof (Eina_Memory_Entry), eina_mempool_alignof(sizeof (Eina_Memory_Entry)));
350 DBG("table[Size, Align] = { %zu, %u }\n",
351 sizeof (Eina_Memory_Table), eina_mempool_alignof(sizeof (Eina_Memory_Table)));
352
353 return EINA_TRUE;
354}
355
356Eina_Bool
357eina_safepointer_shutdown(void)
358{
359 eina_spinlock_free(&sl);
360
361 return EINA_TRUE;
362}
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 @@
1/* EINA - EFL data type library
2 * Copyright (C) 2015-2016 Carsten Haitzler, Cedric Bail
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library;
16 * if not, see <http://www.gnu.org/licenses/>.
17 */
18
19#ifndef EINA_SAFEPOINTER_H__
20#define EINA_SAFEPOINTER_H__
21
22/**
23 * @addtogroup Eina_Safepointer_Group Safe Pointer
24 *
25 * @brief These functions provide a wrapper that protect access to pointers
26 *
27 * Eina_Safepointer is an pointer to index converter that allow an increased
28 * level of safety by forbidding direct access to the pointer. The protection
29 * work by using a set of indirection table that are mmapped and mprotected
30 * against write access. This the pointer they store and that map to a specific
31 * index is always correct. Also once a pointer is unregistered the index
32 * won't be served back for 2^8 on 32 bits system and 2^28 on 64 bits system
33 * for that specific slot. Finally we do guarantee that the lower 2 bits of the
34 * returned index are actually never used and completly ignored by our API.
35 * So you can safely store whatever information you want in it, we will ignore
36 * it and threat as if it wasn't there.
37 *
38 * @note The use of Eina_Safepointer is thread safe.
39 */
40
41/**
42 * @addtogroup Eina_Data_Types_Group Data Types
43 *
44 * @{
45 */
46
47/**
48 * @addtogroup Eina_Containers_Group Containers
49 *
50 * @{
51 */
52
53/**
54 * @defgroup Eina_Safepointer_Group Safe Pointer
55 *
56 * @{
57 */
58
59/**
60 * @typedef Eina_Safepointer
61 * Type of the protected index.
62 */
63typedef struct _Eina_Safepointer Eina_Safepointer;
64
65/**
66 * @brief Register a pointer and get an Eina_Safepointer that map to it.
67 *
68 * @param target The pointer to register.
69 * @return A valid pointer that is an index to the mapped pointer.
70 *
71 * @note It will return @c NULL on error or if @p target is @c NULL.
72 *
73 * @note The lower 2 bits of the returned pointer will always be 0.
74 *
75 * @note The returned pointer can be used like a pointer, but can not
76 * be touched except with Eina_Safepointer functions.
77 */
78EAPI const Eina_Safepointer *eina_safepointer_register(const void *target);
79
80/**
81 * @brief Unregister an Eina_Safepointer and the pointer that map to it.
82 *
83 * @param safe The index to unregister from the mapping.
84 *
85 * @note This function will ignore the lower 2 bits of the given pointer.
86 */
87EAPI void eina_safepointer_unregister(const Eina_Safepointer *safe);
88
89/**
90 * @brief Get the associated pointer from an Eina_Safepointer mapping.
91 *
92 * @param safe The Eina_Safepointer index to lookup at.
93 * @return The pointer registered with that index or @c NULL in any other case.
94 *
95 * @note It is always safe to ask for a pointer for any value of the mapping.
96 * If the pointer is invalid or @c NULL, we will return @c NULL and not crash.
97 */
98static inline void *eina_safepointer_get(const Eina_Safepointer *safe);
99
100/**
101 * @}
102 */
103
104/**
105 * @}
106 */
107
108/**
109 * @}
110 */
111
112
113# include "eina_inline_safepointer.x"
114
115#endif