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.
This commit is contained in:
Tom Hacohen 2016-03-29 14:47:22 +01:00
parent 19139450c0
commit 4a75116cb4
5 changed files with 267 additions and 9 deletions

View File

@ -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 \

View File

@ -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.

View File

@ -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)

View File

@ -0,0 +1,188 @@
#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;
}

View File

@ -0,0 +1,18 @@
#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