eo2: add tests for thread safe call stack

Summary:
   2 threads run 'eo2_do(o, a(), b());'
   - A goes first, creates an object, enters 'eo2_do(o, a(), b());'
     in a() call, it blocks, releases B and waits for it.
   - B when released, creates an object, enters 'eo2_do(o, a(), b());'
     in a() call, it joins and releases A, then blocks.
   - A returns from a(); and enters b() using current call stack frame,
     which is the one pushed by B! then pop the frame and releases B.
   - B does as above using the stack pushed by A!
This commit is contained in:
Jérémy Zurcher 2014-01-21 17:42:07 +01:00 committed by Tom Hacohen
parent 64aa007caf
commit 4b9c37501c
4 changed files with 133 additions and 0 deletions

View File

@ -99,6 +99,7 @@ tests/eo/suite/eo_test_class_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_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\" \

View File

@ -22,6 +22,7 @@ static const Eo_Test_Case etc[] = {
{ "Eo class errors", eo_test_class_errors },
{ "Eo call errors", eo_test_call_errors },
{ "Eo eina value", eo_test_value },
{ "Eo threaded eo calls", eo_test_threaded_calls },
{ NULL, NULL }
};

View File

@ -8,5 +8,6 @@ void eo_test_general(TCase *tc);
void eo_test_class_errors(TCase *tc);
void eo_test_call_errors(TCase *tc);
void eo_test_value(TCase *tc);
void eo_test_threaded_calls(TCase *tc);
#endif /* _EO_SUITE_H */

View File

@ -0,0 +1,130 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include "Eo.h"
#include "eo_suite.h"
static Eina_Barrier barrier;
static Eina_Spinlock locks[2];
typedef struct
{
int v;
} Thread_Test_Public_Data;
#define THREAD_TEST_CLASS thread_test_class_get()
const Eo_Class *thread_test_class_get(void);
EO2_FUNC_BODY(thread_test_v_get, int, 0);
EO2_VOID_FUNC_BODY(thread_test_try_swap_stack);
EO2_VOID_FUNC_BODYV(thread_test_constructor, EO2_FUNC_CALL(v), int v);
static int
_v_get(Eo *obj EINA_UNUSED, void *class_data)
{
Thread_Test_Public_Data *pd = class_data;
return pd->v;
}
static void
_try_swap_stack(Eo *obj EINA_UNUSED, void *class_data)
{
Thread_Test_Public_Data *pd = class_data;
if (pd->v == 0 )
{
eina_spinlock_release(&locks[0]);
eina_spinlock_take(&locks[1]);
eina_barrier_wait(&barrier);
}
else if (pd->v == 1 )
{
eina_barrier_wait(&barrier);
eina_spinlock_take(&locks[1]);
}
}
static void
_constructor(Eo *obj, void *class_data EINA_UNUSED, int v)
{
Thread_Test_Public_Data *pd = class_data;
eo2_do_super(obj, THREAD_TEST_CLASS, eo2_constructor());
pd->v = v;
}
static Eo2_Op_Description op_descs[] = {
EO2_OP_FUNC(thread_test_constructor, _constructor, "Constructor."),
EO2_OP_FUNC(thread_test_v_get, _v_get, "Get property v."),
EO2_OP_FUNC(thread_test_try_swap_stack, _try_swap_stack, "Swap call stack frames if it is not thread safe."),
EO2_OP_SENTINEL
};
static const Eo_Class_Description class_desc = {
EO2_VERSION,
"Thread Test",
EO_CLASS_TYPE_REGULAR,
EO2_CLASS_DESCRIPTION_OPS(op_descs),
NULL,
sizeof(Thread_Test_Public_Data),
NULL,
NULL
};
EO_DEFINE_CLASS(thread_test_class_get, &class_desc, EO2_BASE_CLASS, NULL)
static void *
_thread_job(void *data, Eina_Thread t EINA_UNUSED)
{
Eo *obj;
int v = (int) (uintptr_t) data;
if (v == 1)
eina_spinlock_take(&locks[0]);
obj = eo2_add_custom(THREAD_TEST_CLASS, NULL, thread_test_constructor(v));
eo2_do(obj, thread_test_try_swap_stack(), v = thread_test_v_get());
eina_spinlock_release(&locks[1]);
eo_unref(obj);
return (void *) (uintptr_t) v;
}
START_TEST(eo_threaded_calls_test)
{
Eina_Thread threads[2];
eo_init();
fail_if(!eina_spinlock_new(&locks[0]));
fail_if(!eina_spinlock_new(&locks[1]));
fail_if(!eina_barrier_new(&barrier, 2));
eina_spinlock_take(&locks[0]);
fail_if(!eina_thread_create(&threads[0], EINA_THREAD_NORMAL, 0, _thread_job, (void *) (uintptr_t)0));
fail_if(!eina_thread_create(&threads[1], EINA_THREAD_NORMAL, 0, _thread_job, (void *) (uintptr_t)1));
fail_if(0 != (int)(uintptr_t)eina_thread_join(threads[0]));
fail_if(1 != (int)(uintptr_t)eina_thread_join(threads[1]));
eina_spinlock_free(&locks[0]);
eina_spinlock_free(&locks[1]);
eina_barrier_free(&barrier);
eo_shutdown();
}
END_TEST
void eo_test_threaded_calls(TCase *tc)
{
tcase_add_test(tc, eo_threaded_calls_test);
}