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@
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 = \
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 \
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);
*/
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).
*/
#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.
#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
}
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);
return NULL;
}
+ if (is_fallback)
+ {
+ fptr->obj = eo_id;
+ }
+
return eo_id;
}
}
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;
}
_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);
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)
--- /dev/null
+#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
+
+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;
+}
--- /dev/null
+#ifndef _EO_ADD_FALLBACK_H
+#define _EO_ADD_FALLBACK_H
+
+#include <Eina.h>
+#include <Eo.h>
+
+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