summaryrefslogtreecommitdiff
path: root/src/lib/eo/eo_add_fallback.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/eo/eo_add_fallback.c')
-rw-r--r--src/lib/eo/eo_add_fallback.c160
1 files changed, 160 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..2adc39acff
--- /dev/null
+++ b/src/lib/eo/eo_add_fallback.c
@@ -0,0 +1,160 @@
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#if defined HAVE_DLADDR && ! defined _WIN32
+# include <dlfcn.h>
+#endif
+
+#include <Eina.h>
+
+#include "eo_ptr_indirection.h"
+#include "eo_private.h"
+
+#include "eo_add_fallback.h"
+
+// 1024 entries == 16k or 32k (32 or 64bit) for eo call stack. that's 1023
+// imbricated/recursive calls it can handle before barfing. i'd say that's ok
+#define EO_CALL_STACK_DEPTH_MIN 1024
+
+#define EO_CALL_STACK_SIZE (EO_CALL_STACK_DEPTH_MIN * sizeof(Eo_Stack_Frame))
+
+static Eina_TLS _eo_call_stack_key = 0;
+
+#define MEM_PAGE_SIZE 4096
+
+static void *
+_eo_call_stack_mem_alloc(size_t size)
+{
+#ifdef HAVE_MMAP
+ // allocate eo call stack via mmped anon segment if on linux - more
+ // secure and safe. also gives page aligned memory allowing madvise
+ void *ptr;
+ size_t newsize;
+ newsize = MEM_PAGE_SIZE * ((size + MEM_PAGE_SIZE - 1) /
+ MEM_PAGE_SIZE);
+ ptr = mmap(NULL, newsize, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ if (ptr == MAP_FAILED)
+ {
+ ERR("eo call stack mmap failed.");
+ return NULL;
+ }
+ return ptr;
+#else
+ //in regular cases just use malloc
+ return calloc(1, size);
+#endif
+}
+
+static void
+_eo_call_stack_mem_free(void *ptr, size_t size)
+{
+#ifdef HAVE_MMAP
+ munmap(ptr, size);
+#else
+ (void) size;
+ free(ptr);
+#endif
+}
+
+static Eo_Call_Stack *
+_eo_call_stack_create()
+{
+ Eo_Call_Stack *stack;
+
+ stack = calloc(1, sizeof(Eo_Call_Stack));
+ if (!stack)
+ return NULL;
+
+ stack->frames = _eo_call_stack_mem_alloc(EO_CALL_STACK_SIZE);
+ if (!stack->frames)
+ {
+ free(stack);
+ return NULL;
+ }
+
+ // first frame is never used
+ stack->frame_ptr = stack->frames;
+
+ return stack;
+}
+
+static void
+_eo_call_stack_free(void *ptr)
+{
+ Eo_Call_Stack *stack = (Eo_Call_Stack *) ptr;
+
+ if (!stack) return;
+
+ if (stack->frames)
+ _eo_call_stack_mem_free(stack->frames, EO_CALL_STACK_SIZE);
+
+ free(stack);
+}
+
+static Eo_Call_Stack *main_loop_stack = NULL;
+
+#define _EO_CALL_STACK_GET() ((EINA_LIKELY(eina_main_loop_is())) ? main_loop_stack : _eo_call_stack_get_thread())
+
+static inline Eo_Call_Stack *
+_eo_call_stack_get_thread(void)
+{
+ Eo_Call_Stack *stack = eina_tls_get(_eo_call_stack_key);
+
+ if (stack) return stack;
+
+ stack = _eo_call_stack_create();
+ eina_tls_set(_eo_call_stack_key, stack);
+
+ return stack;
+}
+
+Eo_Call_Stack *
+_eo_add_fallback_stack_get(void)
+{
+ return _EO_CALL_STACK_GET();
+}
+
+EAPI Eo *
+_eo_self_get(void)
+{
+ return _EO_CALL_STACK_GET()->frame_ptr->obj;
+}
+
+Eina_Bool
+_eo_add_fallback_init(void)
+{
+ if (_eo_call_stack_key != 0)
+ WRN("_eo_call_stack_key already set, this should not happen.");
+ else
+ {
+ if (!eina_tls_cb_new(&_eo_call_stack_key, _eo_call_stack_free))
+ {
+ EINA_LOG_ERR("Could not create TLS key for call stack.");
+ return EINA_FALSE;
+
+ }
+ }
+
+ main_loop_stack = _eo_call_stack_create();
+ if (!main_loop_stack)
+ {
+ EINA_LOG_ERR("Could not alloc eo call stack.");
+ return EINA_FALSE;
+ }
+
+ return EINA_TRUE;
+}
+
+Eina_Bool
+_eo_add_fallback_shutdown(void)
+{
+ if (_eo_call_stack_key != 0)
+ {
+ eina_tls_free(_eo_call_stack_key);
+ _eo_call_stack_key = 0;
+ }
+
+ return EINA_TRUE;
+}