summaryrefslogtreecommitdiff
path: root/src/lib/eo/eo_add_fallback.c
diff options
context:
space:
mode:
authorTom Hacohen <tom@stosb.com>2016-03-29 14:47:22 +0100
committerTom Hacohen <tom@stosb.com>2016-03-29 16:01:52 +0100
commit4a75116cb44ef10a93925d2505bcce337d663b6e (patch)
tree86288a671d078dba124ea1e00397f39659b41cc0 /src/lib/eo/eo_add_fallback.c
parent19139450c089bf8600cb2f0056fc616e13e05252 (diff)
Eo: Implement the fallback eo_add implementation.
The current eo_add uses a (very useful) gcc extension that is only available in gcc compatible compilers (e.g clang). Until this commit we just temporarily ignored this fact. This adds a fallback implementation that can be used interchangeably with the non portable one. This means that the same binary can call either at any point in time and the code will work. Breaks ABI.
Diffstat (limited to '')
-rw-r--r--src/lib/eo/eo_add_fallback.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/lib/eo/eo_add_fallback.c b/src/lib/eo/eo_add_fallback.c
new file mode 100644
index 0000000000..6d714d677f
--- /dev/null
+++ b/src/lib/eo/eo_add_fallback.c
@@ -0,0 +1,188 @@
1#ifdef HAVE_CONFIG_H
2# include <config.h>
3#endif
4
5#if defined HAVE_DLADDR && ! defined _WIN32
6# include <dlfcn.h>
7#endif
8
9#include <Eina.h>
10
11#include "eo_ptr_indirection.h"
12#include "eo_private.h"
13
14#include "eo_add_fallback.h"
15
16// 1024 entries == 16k or 32k (32 or 64bit) for eo call stack. that's 1023
17// imbricated/recursive calls it can handle before barfing. i'd say that's ok
18#define EO_CALL_STACK_DEPTH_MIN 1024
19
20typedef struct _Eo_Call_Stack {
21 Eo_Stack_Frame *frames;
22 Eo_Stack_Frame *frame_ptr;
23} Eo_Call_Stack;
24
25#define EO_CALL_STACK_SIZE (EO_CALL_STACK_DEPTH_MIN * sizeof(Eo_Stack_Frame))
26
27static Eina_TLS _eo_call_stack_key = 0;
28
29#define MEM_PAGE_SIZE 4096
30
31static void *
32_eo_call_stack_mem_alloc(size_t size)
33{
34#ifdef HAVE_MMAP
35 // allocate eo call stack via mmped anon segment if on linux - more
36 // secure and safe. also gives page aligned memory allowing madvise
37 void *ptr;
38 size_t newsize;
39 newsize = MEM_PAGE_SIZE * ((size + MEM_PAGE_SIZE - 1) /
40 MEM_PAGE_SIZE);
41 ptr = mmap(NULL, newsize, PROT_READ | PROT_WRITE,
42 MAP_PRIVATE | MAP_ANON, -1, 0);
43 if (ptr == MAP_FAILED)
44 {
45 ERR("eo call stack mmap failed.");
46 return NULL;
47 }
48 return ptr;
49#else
50 //in regular cases just use malloc
51 return calloc(1, size);
52#endif
53}
54
55static void
56_eo_call_stack_mem_free(void *ptr, size_t size)
57{
58#ifdef HAVE_MMAP
59 munmap(ptr, size);
60#else
61 (void) size;
62 free(ptr);
63#endif
64}
65
66static Eo_Call_Stack *
67_eo_call_stack_create()
68{
69 Eo_Call_Stack *stack;
70
71 stack = calloc(1, sizeof(Eo_Call_Stack));
72 if (!stack)
73 return NULL;
74
75 stack->frames = _eo_call_stack_mem_alloc(EO_CALL_STACK_SIZE);
76 if (!stack->frames)
77 {
78 free(stack);
79 return NULL;
80 }
81
82 // first frame is never used
83 stack->frame_ptr = stack->frames;
84
85 return stack;
86}
87
88static void
89_eo_call_stack_free(void *ptr)
90{
91 Eo_Call_Stack *stack = (Eo_Call_Stack *) ptr;
92
93 if (!stack) return;
94
95 if (stack->frames)
96 _eo_call_stack_mem_free(stack->frames, EO_CALL_STACK_SIZE);
97
98 free(stack);
99}
100
101static Eo_Call_Stack *main_loop_stack = NULL;
102
103#define _EO_CALL_STACK_GET() ((EINA_LIKELY(eina_main_loop_is())) ? main_loop_stack : _eo_call_stack_get_thread())
104
105static inline Eo_Call_Stack *
106_eo_call_stack_get_thread(void)
107{
108 Eo_Call_Stack *stack = eina_tls_get(_eo_call_stack_key);
109
110 if (stack) return stack;
111
112 stack = _eo_call_stack_create();
113 eina_tls_set(_eo_call_stack_key, stack);
114
115 return stack;
116}
117
118EAPI Eo *
119_eo_self_get(void)
120{
121 return _EO_CALL_STACK_GET()->frame_ptr->obj;
122}
123
124Eo_Stack_Frame *
125_eo_add_fallback_stack_push(Eo *obj)
126{
127 Eo_Call_Stack *stack = _EO_CALL_STACK_GET();
128 if (stack->frame_ptr == (stack->frames + EO_CALL_STACK_DEPTH_MIN))
129 {
130 CRI("eo_add fallback stack overflow.");
131 }
132
133 stack->frame_ptr++;
134 stack->frame_ptr->obj = obj;
135
136 return stack->frame_ptr;
137}
138
139Eo_Stack_Frame *
140_eo_add_fallback_stack_pop(void)
141{
142 Eo_Call_Stack *stack = _EO_CALL_STACK_GET();
143 if (stack->frame_ptr == stack->frames)
144 {
145 CRI("eo_add fallback stack underflow.");
146 }
147
148 stack->frame_ptr--;
149
150 return stack->frame_ptr;
151}
152
153Eina_Bool
154_eo_add_fallback_init(void)
155{
156 if (_eo_call_stack_key != 0)
157 WRN("_eo_call_stack_key already set, this should not happen.");
158 else
159 {
160 if (!eina_tls_cb_new(&_eo_call_stack_key, _eo_call_stack_free))
161 {
162 EINA_LOG_ERR("Could not create TLS key for call stack.");
163 return EINA_FALSE;
164
165 }
166 }
167
168 main_loop_stack = _eo_call_stack_create();
169 if (!main_loop_stack)
170 {
171 EINA_LOG_ERR("Could not alloc eo call stack.");
172 return EINA_FALSE;
173 }
174
175 return EINA_TRUE;
176}
177
178Eina_Bool
179_eo_add_fallback_shutdown(void)
180{
181 if (_eo_call_stack_key != 0)
182 {
183 eina_tls_free(_eo_call_stack_key);
184 _eo_call_stack_key = 0;
185 }
186
187 return EINA_TRUE;
188}