From 4a75116cb44ef10a93925d2505bcce337d663b6e Mon Sep 17 00:00:00 2001 From: Tom Hacohen Date: Tue, 29 Mar 2016 14:47:22 +0100 Subject: [PATCH] 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. --- src/Makefile_Eo.am | 15 ++- src/lib/eo/Eo.h | 30 ++++-- src/lib/eo/eo.c | 25 ++++- src/lib/eo/eo_add_fallback.c | 188 +++++++++++++++++++++++++++++++++++ src/lib/eo/eo_add_fallback.h | 18 ++++ 5 files changed, 267 insertions(+), 9 deletions(-) create mode 100644 src/lib/eo/eo_add_fallback.c create mode 100644 src/lib/eo/eo_add_fallback.h diff --git a/src/Makefile_Eo.am b/src/Makefile_Eo.am index e388318e8d..c8fbd52ee3 100644 --- a/src/Makefile_Eo.am +++ b/src/Makefile_Eo.am @@ -31,6 +31,8 @@ lib/eo/eo_ptr_indirection.c \ lib/eo/eo_ptr_indirection.h \ lib/eo/eo_base_class.c \ lib/eo/eo_class_class.c \ +lib/eo/eo_add_fallback.c \ +lib/eo/eo_add_fallback.h \ lib/eo/eo_private.h lib_eo_libeo_la_CPPFLAGS = -I$(top_builddir)/src/lib/efl @EO_CFLAGS@ @@ -58,6 +60,7 @@ tests/eo/test_interface \ tests/eo/test_mixin \ tests/eo/test_signals \ tests/eo/test_children \ +tests/eo/eo_suite_add_fallback \ tests/eo/eo_suite tests_eo_test_children_SOURCES = \ @@ -129,15 +132,25 @@ tests/eo/suite/eo_test_general.c \ tests/eo/suite/eo_test_value.c \ tests/eo/suite/eo_test_threaded_calls.c \ tests/eo/suite/eo_test_init.c + tests_eo_eo_suite_CPPFLAGS = -I$(top_builddir)/src/lib/efl \ -DTESTS_BUILD_DIR=\"$(top_builddir)/src/tests/eo\" \ @CHECK_CFLAGS@ \ @EO_CFLAGS@ -TESTS += tests/eo/eo_suite tests_eo_eo_suite_LDADD = @CHECK_LIBS@ @USE_EO_LIBS@ tests_eo_eo_suite_DEPENDENCIES = @USE_EO_INTERNAL_LIBS@ +TESTS += tests/eo/eo_suite + +tests_eo_eo_suite_add_fallback_SOURCES = $(tests_eo_eo_suite_SOURCES) +tests_eo_eo_suite_add_fallback_CPPFLAGS = $(tests_eo_eo_suite_CPPFLAGS) \ + -D_EO_ADD_FALLBACK_FORCE=1 +tests_eo_eo_suite_add_fallback_LDADD = $(tests_eo_eo_suite_LDADD) +tests_eo_eo_suite_add_fallback_DEPENDENCIES = $(tests_eo_eo_suite_DEPENDENCIES) + +TESTS += tests/eo/eo_suite_add_fallback + tests_eo_test_function_overrides_SOURCES = \ tests/eo/function_overrides/function_overrides_inherit.c \ tests/eo/function_overrides/function_overrides_inherit.h \ diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h index 13d82836fd..dc6aa0e2ab 100644 --- a/src/lib/eo/Eo.h +++ b/src/lib/eo/Eo.h @@ -582,7 +582,7 @@ EAPI Eina_Bool _eo_call_resolve(Eo *obj, const char *func_name, Eo_Op_Call_Data EAPI void _eo_call_end(Eo_Op_Call_Data *call); // end of the eo_add. Calls finalize among others -EAPI Eo * _eo_add_end(Eo *obj); +EAPI Eo * _eo_add_end(Eo *obj, Eina_Bool is_fallback); EAPI Eo *eo_super(const Eo *obj, const Eo_Class *cur_klass); @@ -597,15 +597,33 @@ EAPI Eo *eo_super(const Eo *obj, const Eo_Class *cur_klass); */ EAPI const Eo_Class *eo_class_get(const Eo *obj); -#define eo_self __eo_self +EAPI Eo *_eo_self_get(void); -#define _eo_add_common(klass, parent, is_ref, ...) \ +/* Check if GCC compatible (both GCC and clang define this) */ +#if defined(__GNUC__) && !defined(_EO_ADD_FALLBACK_FORCE) + +# define eo_self __eo_self + +# define _eo_add_common(klass, parent, is_ref, ...) \ ({ \ - Eo * const __eo_self = _eo_add_internal_start(__FILE__, __LINE__, klass, parent, is_ref); \ + Eo * const __eo_self = _eo_add_internal_start(__FILE__, __LINE__, klass, parent, is_ref, EINA_FALSE); \ __VA_ARGS__; \ - (Eo *) _eo_add_end(eo_self); \ + (Eo *) _eo_add_end(eo_self, EINA_FALSE); \ }) +#else + +# define eo_self _eo_self_get() + +# define _eo_add_common(klass, parent, is_ref, ...) \ + ( \ + _eo_add_internal_start(__FILE__, __LINE__, klass, parent, is_ref, EINA_TRUE), \ + ##__VA_ARGS__, \ + (Eo *) _eo_add_end(eo_self, EINA_TRUE) \ + ) + +#endif + /** * @def eo_add * @brief Create a new object and call its constructor(If it exits). @@ -644,7 +662,7 @@ EAPI const Eo_Class *eo_class_get(const Eo *obj); */ #define eo_add_ref(klass, parent, ...) _eo_add_common(klass, parent, EINA_TRUE, ##__VA_ARGS__) -EAPI Eo * _eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo *parent, Eina_Bool ref); +EAPI Eo * _eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo *parent, Eina_Bool ref, Eina_Bool is_fallback); /** * @brief Get a pointer to the data of an object for a specific class. diff --git a/src/lib/eo/eo.c b/src/lib/eo/eo.c index ba12fbd252..434ab3ec4f 100644 --- a/src/lib/eo/eo.c +++ b/src/lib/eo/eo.c @@ -13,6 +13,7 @@ #include "Eo.h" #include "eo_ptr_indirection.h" #include "eo_private.h" +#include "eo_add_fallback.h" #define EO_CLASS_IDS_FIRST 1 #define EO_OP_IDS_FIRST 1 @@ -615,9 +616,15 @@ _eo_class_funcs_set(_Eo_Class *klass) } EAPI Eo * -_eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo *parent_id, Eina_Bool ref) +_eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo *parent_id, Eina_Bool ref, Eina_Bool is_fallback) { _Eo_Object *obj; + Eo_Stack_Frame *fptr = NULL; + + if (is_fallback) + { + fptr = _eo_add_fallback_stack_push(NULL); + } EO_CLASS_POINTER_RETURN_VAL(klass_id, klass, NULL); @@ -680,6 +687,11 @@ _eo_add_internal_start(const char *file, int line, const Eo_Class *klass_id, Eo return NULL; } + if (is_fallback) + { + fptr->obj = eo_id; + } + return eo_id; } @@ -726,11 +738,16 @@ cleanup: } EAPI Eo * -_eo_add_end(Eo *eo_id) +_eo_add_end(Eo *eo_id, Eina_Bool is_fallback) { Eo *ret = eo_finalize(eo_id); ret = _eo_add_internal_end(eo_id, ret); + if (is_fallback) + { + _eo_add_fallback_stack_pop(); + } + return ret; } @@ -1595,6 +1612,8 @@ eo_init(void) _eo_class_isa_func(NULL, NULL, NULL); #endif + _eo_add_fallback_init(); + eina_log_timing(_eo_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT); @@ -1618,6 +1637,8 @@ eo_shutdown(void) EINA_LOG_STATE_START, EINA_LOG_STATE_SHUTDOWN); + _eo_add_fallback_shutdown(); + for (i = 0 ; i < _eo_classes_last_id ; i++, cls_itr++) { if (*cls_itr) 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 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#if defined HAVE_DLADDR && ! defined _WIN32 +# include +#endif + +#include + +#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 + +typedef struct _Eo_Call_Stack { + Eo_Stack_Frame *frames; + Eo_Stack_Frame *frame_ptr; +} Eo_Call_Stack; + +#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; +} + +EAPI Eo * +_eo_self_get(void) +{ + return _EO_CALL_STACK_GET()->frame_ptr->obj; +} + +Eo_Stack_Frame * +_eo_add_fallback_stack_push(Eo *obj) +{ + Eo_Call_Stack *stack = _EO_CALL_STACK_GET(); + if (stack->frame_ptr == (stack->frames + EO_CALL_STACK_DEPTH_MIN)) + { + CRI("eo_add fallback stack overflow."); + } + + stack->frame_ptr++; + stack->frame_ptr->obj = obj; + + return stack->frame_ptr; +} + +Eo_Stack_Frame * +_eo_add_fallback_stack_pop(void) +{ + Eo_Call_Stack *stack = _EO_CALL_STACK_GET(); + if (stack->frame_ptr == stack->frames) + { + CRI("eo_add fallback stack underflow."); + } + + stack->frame_ptr--; + + return stack->frame_ptr; +} + +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; +} diff --git a/src/lib/eo/eo_add_fallback.h b/src/lib/eo/eo_add_fallback.h new file mode 100644 index 0000000000..4b5e4a5625 --- /dev/null +++ b/src/lib/eo/eo_add_fallback.h @@ -0,0 +1,18 @@ +#ifndef _EO_ADD_FALLBACK_H +#define _EO_ADD_FALLBACK_H + +#include +#include + +typedef struct _Eo_Stack_Frame +{ + Eo *obj; +} Eo_Stack_Frame; + +Eina_Bool _eo_add_fallback_init(void); +Eina_Bool _eo_add_fallback_shutdown(void); + +Eo_Stack_Frame *_eo_add_fallback_stack_push(Eo *obj); +Eo_Stack_Frame *_eo_add_fallback_stack_pop(void); + +#endif