Efl_Object: make main domain accessible in Eina_Coro.

Currently Eina_Coro is implemented with actual threads, that barf Eo
checkings and makes main thread objects unusuable.

Since this is an implementation detail, let's use Eina_Coro hooks to
adopt the main domain and return when it's done... The user doesn't
see this, it's transparent.
This commit is contained in:
Gustavo Sverzut Barbieri 2017-08-26 17:26:38 -03:00
parent d10a35628c
commit 109bf1b387
6 changed files with 183 additions and 0 deletions

View File

@ -146,6 +146,7 @@ tests/eo/suite/eo_test_class_behaviour_errors.c \
tests/eo/suite/eo_test_call_errors.c \
tests/eo/suite/eo_test_general.c \
tests/eo/suite/eo_test_value.c \
tests/eo/suite/eo_test_coro.c \
tests/eo/suite/eo_test_event.c \
tests/eo/suite/eo_test_threaded_calls.c \
tests/eo/suite/eo_test_init.c

View File

@ -68,3 +68,5 @@ struct @extern Eina.Future; [[Eina Future handles]]
struct @extern Eina.Future.Scheduler; [[This struct is used as a bridge between Eina and the future scheduler.
By using the provided functions Eina can schedule futures resolutions,
rejections and cancelations to a safe context.]]
struct @extern Eina.Coro; [[Eina Coro (coroutine) handle.]]

View File

@ -2137,6 +2137,118 @@ _eo_table_del_cb(void *in)
* This is used by the gdb debug helper script */
Eo_Id_Data *_eo_gdb_main_domain = NULL;
typedef struct _Eo_Coro_Hook_Data
{
EINA_INLIST;
const Eina_Coro *coro;
Efl_Domain_Data *domain_data;
Efl_Id_Domain return_domain;
} Eo_Coro_Hook_Data;
static Eina_Inlist *_eo_coro_hook_data = NULL;
static Eina_Lock _eo_coro_hook_data_lock;
/* Flow:
*
* main_exit -> coro_enter -> coro_exit -> main_enter
*
* main_exit: efl_domain_data_get()
* coro_enter: efl_domain_data_adopt()
* coro_exit: efl_domain_data_return()
* main_enter: remove from list
*/
static Eo_Coro_Hook_Data *
_eo_coro_hook_data_find_unlocked(const Eina_Coro *coro)
{
Eo_Coro_Hook_Data *d;
EINA_INLIST_FOREACH(_eo_coro_hook_data, d)
{
if (d->coro == coro)
{
if (_eo_coro_hook_data != EINA_INLIST_GET(d))
_eo_coro_hook_data = eina_inlist_promote(_eo_coro_hook_data,
EINA_INLIST_GET(d));
return d;
}
}
return NULL;
}
static Eo_Coro_Hook_Data *
_eo_coro_hook_data_find(const Eina_Coro *coro)
{
Eo_Coro_Hook_Data *d;
eina_lock_take(&_eo_coro_hook_data_lock);
d = _eo_coro_hook_data_find_unlocked(coro);
eina_lock_release(&_eo_coro_hook_data_lock);
return d;
}
static Eina_Bool
_eo_coro_hook_main_exit(void *data EINA_UNUSED, const Eina_Coro *coro)
{
Eo_Coro_Hook_Data *d = malloc(sizeof(Eo_Coro_Hook_Data));
EINA_SAFETY_ON_NULL_RETURN_VAL(d, EINA_FALSE);
d->coro = coro;
d->domain_data = efl_domain_data_get();
d->return_domain = EFL_ID_DOMAIN_INVALID;
eina_lock_take(&_eo_coro_hook_data_lock);
_eo_coro_hook_data = eina_inlist_prepend(_eo_coro_hook_data, EINA_INLIST_GET(d));
eina_lock_release(&_eo_coro_hook_data_lock);
return EINA_TRUE;
}
static void
_eo_coro_hook_main_enter(void *data EINA_UNUSED, const Eina_Coro *coro)
{
Eo_Coro_Hook_Data *d;
eina_lock_take(&_eo_coro_hook_data_lock);
d = _eo_coro_hook_data_find_unlocked(coro);
if (d)
_eo_coro_hook_data = eina_inlist_remove(_eo_coro_hook_data, EINA_INLIST_GET(d));
eina_lock_release(&_eo_coro_hook_data_lock);
EINA_SAFETY_ON_NULL_RETURN(d); // just to print-out unexpected error.
free(d);
}
static Eina_Bool
_eo_coro_hook_coro_enter(void *data EINA_UNUSED, const Eina_Coro *coro)
{
Eo_Coro_Hook_Data *d = _eo_coro_hook_data_find(coro);
EINA_SAFETY_ON_NULL_RETURN_VAL(d, EINA_FALSE);
EINA_SAFETY_ON_NULL_RETURN_VAL(d->domain_data, EINA_FALSE);
EINA_SAFETY_ON_TRUE_RETURN_VAL(d->return_domain != EFL_ID_DOMAIN_INVALID, EINA_FALSE);
d->return_domain = efl_domain_data_adopt(d->domain_data);
EINA_SAFETY_ON_TRUE_RETURN_VAL(d->return_domain == EFL_ID_DOMAIN_INVALID, EINA_FALSE);
return EINA_TRUE;
}
static void
_eo_coro_hook_coro_exit(void *data EINA_UNUSED, const Eina_Coro *coro)
{
Eo_Coro_Hook_Data *d = _eo_coro_hook_data_find(coro);
EINA_SAFETY_ON_NULL_RETURN(d);
EINA_SAFETY_ON_NULL_RETURN(d->domain_data);
EINA_SAFETY_ON_TRUE_RETURN(d->return_domain == EFL_ID_DOMAIN_INVALID);
efl_domain_data_return(d->return_domain);
d->domain_data = NULL;
}
EAPI Eina_Bool
efl_object_init(void)
{
@ -2229,6 +2341,13 @@ efl_object_init(void)
_efl_add_fallback_init();
eina_lock_new(&_eo_coro_hook_data_lock);
eina_coro_hook_add(_eo_coro_hook_coro_enter,
_eo_coro_hook_coro_exit,
_eo_coro_hook_main_enter,
_eo_coro_hook_main_exit,
NULL);
eina_log_timing(_eo_log_dom,
EINA_LOG_STATE_STOP,
EINA_LOG_STATE_INIT);
@ -2252,6 +2371,13 @@ efl_object_shutdown(void)
EINA_LOG_STATE_START,
EINA_LOG_STATE_SHUTDOWN);
eina_coro_hook_del(_eo_coro_hook_coro_enter,
_eo_coro_hook_coro_exit,
_eo_coro_hook_main_enter,
_eo_coro_hook_main_exit,
NULL);
eina_lock_free(&_eo_coro_hook_data_lock);
_efl_add_fallback_shutdown();
efl_future_shutdown();

View File

@ -12,6 +12,7 @@ static const Efl_Test_Case etc[] = {
{ "Eo class behaviour errors", eo_test_class_behaviour_errors },
{ "Eo call errors", eo_test_call_errors },
{ "Eo eina value", eo_test_value },
{ "Eo eina coroutines", eo_test_coro },
{ "Eo threaded eo calls", eo_test_threaded_calls },
{ "Eo event calls", eo_test_event},
{ NULL, NULL }

View File

@ -9,6 +9,7 @@ void eo_test_class_errors(TCase *tc);
void eo_test_class_behaviour_errors(TCase *tc);
void eo_test_call_errors(TCase *tc);
void eo_test_value(TCase *tc);
void eo_test_coro(TCase *tc);
void eo_test_threaded_calls(TCase *tc);
void eo_test_event(TCase *tc);

View File

@ -0,0 +1,52 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <Eo.h>
#include "eo_suite.h"
#include "eo_test_class_simple.h"
#define RETVAL ((void *)0x1234)
static const void *
func(void *data, Eina_Bool canceled EINA_UNUSED, Eina_Coro *coro EINA_UNUSED)
{
Eo *obj = data;
fail_unless(efl_ref(obj)); // if efl_domain_data is wrong, this fails...
return RETVAL;
}
START_TEST(eo_coro)
{
Eo *obj;
Eina_Coro *coro;
void *result;
efl_object_init();
obj = efl_add(SIMPLE_CLASS, NULL);
fail_unless(obj);
coro = eina_coro_new(func, obj, EINA_CORO_STACK_SIZE_DEFAULT);
fail_unless(coro);
fail_if(eina_coro_run(&coro, &result, NULL)); // doesn't yield, so should finish
ck_assert_ptr_eq(result, RETVAL);
ck_assert_int_eq(efl_ref_get(obj), 2);
efl_unref(obj);
efl_unref(obj);
efl_object_shutdown();
}
END_TEST
void eo_test_coro(TCase *tc)
{
tcase_add_test(tc, eo_coro);
}