raster pushed a commit to branch master. http://git.enlightenment.org/core/efl.git/commit/?id=6865ad177368cdc54b587ab0979f39b20ff61552
commit 6865ad177368cdc54b587ab0979f39b20ff61552 Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com> Date: Tue Mar 6 20:49:51 2018 +0900 ecore - efl threads - add thredio class this adds a simple indata and outdata void ptr to begin that you can set on efl.thread objects (set the indata) and get the outdata too to get results. then on the efl.appthread side the indata is set on the efl.appthread before it runs and on quit the thresad can set the outdata on the appthread, and this appears back on the efl.thread object in the parent thread. so you can basically share pointers to anything in and out this way on start/exit in addition to string args etc. the reason i made it an extra class (mixin actually) is for future expansion. sharing more complex data - eina values maybe or objects as long as they are shared objects, and perhaps acting as an interface for calling a function at the other end like ecore_thread_async_call etc. --- src/Makefile_Ecore.am | 2 + src/lib/ecore/Ecore_Eo.h | 1 + src/lib/ecore/ecore_private.h | 3 +- src/lib/ecore/efl_appthread.c | 16 ++++ src/lib/ecore/efl_appthread.eo | 4 +- src/lib/ecore/efl_thread.c | 190 ++++++++++++++++++++++++++++++++++++----- src/lib/ecore/efl_thread.eo | 4 +- src/lib/ecore/efl_threadio.c | 58 +++++++++++++ src/lib/ecore/efl_threadio.eo | 53 ++++++++++++ 9 files changed, 305 insertions(+), 26 deletions(-) diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am index 238d7acb89..d2eba218dd 100644 --- a/src/Makefile_Ecore.am +++ b/src/Makefile_Ecore.am @@ -17,6 +17,7 @@ ecore_eolian_files_public = \ lib/ecore/efl_loop_message_handler.eo \ lib/ecore/efl_exe.eo \ lib/ecore/efl_thread.eo \ + lib/ecore/efl_threadio.eo \ lib/ecore/efl_appthread.eo \ lib/ecore/efl_task.eo \ lib/ecore/efl_io_closer_fd.eo \ @@ -138,6 +139,7 @@ lib/ecore/efl_interpolator_cubic_bezier.c \ lib/ecore/efl_task.c \ lib/ecore/efl_exe.c \ lib/ecore/efl_thread.c \ +lib/ecore/efl_threadio.c \ lib/ecore/efl_appthread.c \ lib/ecore/ecore_main_timechanges.c \ lib/ecore/ecore_pipe.c \ diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h index be4df7e377..58a781e239 100644 --- a/src/lib/ecore/Ecore_Eo.h +++ b/src/lib/ecore/Ecore_Eo.h @@ -46,6 +46,7 @@ #include "efl_task.eo.h" #include "efl_thread.eo.h" +#include "efl_threadio.eo.h" #include "efl_exe.eo.h" #include "efl_loop.eo.h" diff --git a/src/lib/ecore/ecore_private.h b/src/lib/ecore/ecore_private.h index 847a8b42b0..3e86cf68c6 100644 --- a/src/lib/ecore/ecore_private.h +++ b/src/lib/ecore/ecore_private.h @@ -197,6 +197,7 @@ struct _Efl_Task_Data struct _Efl_Appthread_Data { + int read_listeners; struct { int in, out; Eo *in_handler, *out_handler; @@ -204,7 +205,7 @@ struct _Efl_Appthread_Data Eina_Bool eos_read : 1; Eina_Bool can_write : 1; } fd, ctrl; - int read_listeners; + void *thdat; }; diff --git a/src/lib/ecore/efl_appthread.c b/src/lib/ecore/efl_appthread.c index 93de9c0917..abe51a73e5 100644 --- a/src/lib/ecore/efl_appthread.c +++ b/src/lib/ecore/efl_appthread.c @@ -240,6 +240,22 @@ _efl_appthread_efl_io_writer_can_write_get(Eo *obj EINA_UNUSED, Efl_Appthread_Da return pd->fd.can_write; } +void _appthread_threadio_call(Eo *obj, Efl_Appthread_Data *pd, void *func_data, EFlThreadIOCall func, Eina_Free_Cb func_free_cb); + +EOLIAN static void +_efl_appthread_efl_threadio_call(Eo *obj, Efl_Appthread_Data *pd, void *func_data, EFlThreadIOCall func, Eina_Free_Cb func_free_cb) +{ + _appthread_threadio_call(obj, pd, func_data, func, func_free_cb); +} + +void *_appthread_threadio_call_sync(Eo *obj, Efl_Appthread_Data *pd, void *func_data, EFlThreadIOCallSync func, Eina_Free_Cb func_free_cb); + +EOLIAN static void * +_efl_appthread_efl_threadio_call_sync(Eo *obj, Efl_Appthread_Data *pd, void *func_data, EFlThreadIOCallSync func, Eina_Free_Cb func_free_cb) +{ + return _appthread_threadio_call_sync(obj, pd, func_data, func, func_free_cb); +} + ////////////////////////////////////////////////////////////////////////// #include "efl_appthread.eo.c" diff --git a/src/lib/ecore/efl_appthread.eo b/src/lib/ecore/efl_appthread.eo index 2f5021a720..67de1c7c73 100644 --- a/src/lib/ecore/efl_appthread.eo +++ b/src/lib/ecore/efl_appthread.eo @@ -1,7 +1,7 @@ import efl_types; import eina_types; -class Efl.Appthread (Efl.Loop) +class Efl.Appthread (Efl.Loop, Efl.ThreadIO) { [[ ]] methods { @@ -18,5 +18,7 @@ class Efl.Appthread (Efl.Loop) Efl.Io.Reader.eos { get; set; } Efl.Io.Writer.write; Efl.Io.Writer.can_write { get; set; } + Efl.ThreadIO.call; + Efl.ThreadIO.call_sync; } } diff --git a/src/lib/ecore/efl_thread.c b/src/lib/ecore/efl_thread.c index 83c7017b79..857c3c529e 100644 --- a/src/lib/ecore/efl_thread.c +++ b/src/lib/ecore/efl_thread.c @@ -16,6 +16,8 @@ #define MY_CLASS EFL_THREAD_CLASS +#define APPTHREAD_CLASS EFL_APPTHREAD_CLASS + typedef struct { const char *name; @@ -28,15 +30,30 @@ typedef struct const char **argv; } args; Efl_Callback_Array_Item_Full *event_cb; + void *indata, *outdata; } Thread_Data; -#define CMD_EXIT 1 -#define CMD_EXITED 2 +#define CMD_EXIT 1 +#define CMD_EXITED 2 +#define CMD_CALL 3 +#define CMD_CALL_SYNC 4 typedef struct { - int command; - int data; + Eina_Semaphore sem; + void *data; +} Control_Reply; + +typedef struct +{ + union { + struct { + int command; + int data; + void *ptr[4]; + } d; + unsigned char b[64]; + }; } Control_Data; typedef struct _Efl_Thread_Data Efl_Thread_Data; @@ -84,17 +101,34 @@ _cb_thread_ctrl_out(void *data, const Efl_Event *event EINA_UNUSED) ssize_t ret; Efl_Appthread_Data *ad; - ad = efl_data_scope_get(obj, EFL_APPTHREAD_CLASS); - cmd.command = 0; - cmd.data = 0; + ad = efl_data_scope_get(obj, APPTHREAD_CLASS); + memset(&cmd, 0, sizeof(cmd)); ret = read(ad->ctrl.out, &cmd, sizeof(Control_Data)); if (ret == sizeof(Control_Data)) { - if (cmd.command == CMD_EXIT) + if (cmd.d.command == CMD_EXIT) { efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL); efl_loop_quit(obj, eina_value_int_init(0)); } + else if (cmd.d.command == CMD_CALL) + { + EFlThreadIOCall func = cmd.d.ptr[0]; + void *data = cmd.d.ptr[1]; + Eina_Free_Cb free_func = cmd.d.ptr[2]; + if (func) func(data, obj); + if (free_func) free_func(data); + } + else if (cmd.d.command == CMD_CALL_SYNC) + { + EFlThreadIOCallSync func = cmd.d.ptr[0]; + void *data = cmd.d.ptr[1]; + Eina_Free_Cb free_func = cmd.d.ptr[2]; + Control_Reply *rep = cmd.d.ptr[3]; + if (func) rep->data = func(data, obj); + if (free_func) free_func(data); + eina_semaphore_release(&(rep->sem), 1); + } } } @@ -193,8 +227,10 @@ _efl_thread_main(void *data, Eina_Thread t) if (thdat->name) eina_thread_name_set(t, thdat->name); else eina_thread_name_set(t, "Eflthread"); - obj = efl_add(EFL_APPTHREAD_CLASS, NULL); - ad = efl_data_scope_get(obj, EFL_APPTHREAD_CLASS); + obj = efl_add(APPTHREAD_CLASS, NULL); + ad = efl_data_scope_get(obj, APPTHREAD_CLASS); + efl_threadio_indata_set(obj, thdat->indata); + efl_threadio_outdata_set(obj, thdat->outdata); efl_event_callback_array_add(obj, _appthread_event_callback_watch(), ad); // add handlers for "stdio" @@ -227,6 +263,7 @@ _efl_thread_main(void *data, Eina_Thread t) ad->fd.out_handler = thdat->fd.out_handler; ad->ctrl.in_handler = thdat->ctrl.in_handler; ad->ctrl.out_handler = thdat->ctrl.out_handler; + ad->thdat = thdat; if (thdat->event_cb) { @@ -248,9 +285,11 @@ _efl_thread_main(void *data, Eina_Thread t) ret = efl_loop_begin(obj); real = efl_loop_exit_code_process(ret); + thdat->outdata = efl_threadio_outdata_get(obj); - cmd.command = CMD_EXITED; - cmd.data = real; + memset(&cmd, 0, sizeof(cmd)); + cmd.d.command = CMD_EXITED; + cmd.d.data = real; write(thdat->ctrl.in, &cmd, sizeof(Control_Data)); efl_del(obj); @@ -292,6 +331,7 @@ _thread_exit_eval(Eo *obj, Efl_Thread_Data *pd) pd->exit_called = EINA_TRUE; efl_ref(obj); + if (pd->thdat) efl_threadio_outdata_set(obj, pd->thdat->outdata); job = eina_future_then(efl_loop_job(loop), _efl_loop_task_exit, obj); efl_future_Eina_FutureXXX_then(loop, job); } @@ -321,22 +361,39 @@ _cb_thread_parent_ctrl_out(void *data, const Efl_Event *event EINA_UNUSED) if (!pd) return; - cmd.command = 0; - cmd.data = 0; + memset(&cmd, 0, sizeof(cmd)); ret = read(pd->ctrl.out, &cmd, sizeof(Control_Data)); if (ret == sizeof(Control_Data)) { - if (cmd.command == CMD_EXITED) + if (cmd.d.command == CMD_EXITED) { if (!pd->exit_read) { Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS); - if (td) td->exit_code = cmd.data; + if (td) td->exit_code = cmd.d.data; pd->exit_read = EINA_TRUE; _thread_exit_eval(obj, pd); } } + else if (cmd.d.command == CMD_CALL) + { + EFlThreadIOCall func = cmd.d.ptr[0]; + void *data = cmd.d.ptr[1]; + Eina_Free_Cb free_func = cmd.d.ptr[2]; + if (func) func(data, obj); + if (free_func) free_func(data); + } + else if (cmd.d.command == CMD_CALL_SYNC) + { + EFlThreadIOCallSync func = cmd.d.ptr[0]; + void *data = cmd.d.ptr[1]; + Eina_Free_Cb free_func = cmd.d.ptr[2]; + Control_Reply *rep = cmd.d.ptr[3]; + if (func) rep->data = func(data, obj); + if (free_func) free_func(data); + eina_semaphore_release(&(rep->sem), 1); + } } } @@ -461,18 +518,17 @@ _efl_thread_efl_object_destructor(Eo *obj, Efl_Thread_Data *pd) // if it hasn't been asked to exit... ask it if (!pd->end_sent) efl_task_end(obj); - cmd.command = 0; - cmd.data = 0; + memset(&cmd, 0, sizeof(cmd)); ret = read(pd->ctrl.out, &cmd, sizeof(Control_Data)); while (ret == sizeof(Control_Data)) { - if (cmd.command == CMD_EXITED) + if (cmd.d.command == CMD_EXITED) { if (!pd->exit_read) { Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS); - if (td) td->exit_code = cmd.data; + if (td) td->exit_code = cmd.d.data; pd->exit_read = EINA_TRUE; efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL); break; @@ -534,6 +590,9 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd) thdat->ctrl.in = -1; thdat->ctrl.out = -1; + thdat->indata = efl_threadio_indata_get(obj); + thdat->outdata = efl_threadio_outdata_get(obj); + // input/output pipes if (td->flags & EFL_TASK_FLAGS_USE_STDIN) { @@ -625,7 +684,10 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd) thdat->ctrl.out = pipe_to_thread [0]; // read - output from parent pd->ctrl.in = pipe_to_thread [1]; // write - input to child pd->ctrl.out = pipe_from_thread[0]; // read - output from child - // yes - these are blocking because we write and read very little + fcntl(thdat->ctrl.in, F_SETFL, O_NONBLOCK); + fcntl(thdat->ctrl.out, F_SETFL, O_NONBLOCK); + fcntl(pd->ctrl.in, F_SETFL, O_NONBLOCK); + fcntl(pd->ctrl.out, F_SETFL, O_NONBLOCK); eina_file_close_on_exec(pd->ctrl.in, EINA_TRUE); eina_file_close_on_exec(pd->ctrl.out, EINA_TRUE); eina_file_close_on_exec(thdat->ctrl.in, EINA_TRUE); @@ -733,8 +795,8 @@ _efl_thread_efl_task_end(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd) Control_Data cmd; pd->end_sent = EINA_TRUE; - cmd.command = CMD_EXIT; - cmd.data = 0; + memset(&cmd, 0, sizeof(cmd)); + cmd.d.command = CMD_EXIT; write(pd->ctrl.in, &cmd, sizeof(Control_Data)); } } @@ -928,6 +990,88 @@ _efl_thread_efl_io_writer_can_write_get(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd return pd->fd.can_write; } +void +_appthread_threadio_call(Eo *obj EINA_UNUSED, Efl_Appthread_Data *pd, + void *func_data, EFlThreadIOCall func, Eina_Free_Cb func_free_cb) +{ + Thread_Data *thdat = pd->thdat; + Control_Data cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.d.command = CMD_CALL; + cmd.d.ptr[0] = func; + cmd.d.ptr[1] = func_data; + cmd.d.ptr[2] = func_free_cb; + write(thdat->ctrl.in, &cmd, sizeof(Control_Data)); +} + +EOLIAN static void +_efl_thread_efl_threadio_call(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd, + void *func_data, EFlThreadIOCall func, Eina_Free_Cb func_free_cb) +{ + Thread_Data *thdat = pd->thdat; + Control_Data cmd; + + memset(&cmd, 0, sizeof(cmd)); + cmd.d.command = CMD_CALL; + cmd.d.ptr[0] = func; + cmd.d.ptr[1] = func_data; + cmd.d.ptr[2] = func_free_cb; + write(pd->ctrl.in, &cmd, sizeof(Control_Data)); +} + +void * +_appthread_threadio_call_sync(Eo *obj EINA_UNUSED, Efl_Appthread_Data *pd, + void *func_data, EFlThreadIOCallSync func, Eina_Free_Cb func_free_cb) +{ + Thread_Data *thdat = pd->thdat; + Control_Data cmd; + Control_Reply *rep; + void *data; + + memset(&cmd, 0, sizeof(cmd)); + cmd.d.command = CMD_CALL_SYNC; + cmd.d.ptr[0] = func; + cmd.d.ptr[1] = func_data; + cmd.d.ptr[2] = func_free_cb; + rep = malloc(sizeof(Control_Reply)); + if (!rep) return NULL; + cmd.d.ptr[3] = rep; + rep->data = NULL; + eina_semaphore_new(&(rep->sem), 0); + write(thdat->ctrl.in, &cmd, sizeof(Control_Data)); + eina_semaphore_lock(&(rep->sem)); + data = rep->data; + free(rep); + return data; +} + +EOLIAN static void * +_efl_thread_efl_threadio_call_sync(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd, + void *func_data, EFlThreadIOCallSync func, Eina_Free_Cb func_free_cb) +{ + Thread_Data *thdat = pd->thdat; + Control_Data cmd; + Control_Reply *rep; + void *data; + + memset(&cmd, 0, sizeof(cmd)); + cmd.d.command = CMD_CALL_SYNC; + cmd.d.ptr[0] = func; + cmd.d.ptr[1] = func_data; + cmd.d.ptr[2] = func_free_cb; + rep = malloc(sizeof(Control_Reply)); + if (!rep) return NULL; + cmd.d.ptr[3] = rep; + rep->data = NULL; + eina_semaphore_new(&(rep->sem), 0); + write(pd->ctrl.in, &cmd, sizeof(Control_Data)); + eina_semaphore_lock(&(rep->sem)); + data = rep->data; + free(rep); + return data; +} + ////////////////////////////////////////////////////////////////////////// #include "efl_thread.eo.c" diff --git a/src/lib/ecore/efl_thread.eo b/src/lib/ecore/efl_thread.eo index 214c0fd07f..15f8173395 100644 --- a/src/lib/ecore/efl_thread.eo +++ b/src/lib/ecore/efl_thread.eo @@ -1,7 +1,7 @@ import efl_types; import eina_types; -class Efl.Thread (Efl.Task) +class Efl.Thread (Efl.Task, Efl.ThreadIO) { methods { } @@ -18,5 +18,7 @@ class Efl.Thread (Efl.Task) Efl.Io.Reader.eos { get; set; } Efl.Io.Writer.write; Efl.Io.Writer.can_write { get; set; } + Efl.ThreadIO.call; + Efl.ThreadIO.call_sync; } } diff --git a/src/lib/ecore/efl_threadio.c b/src/lib/ecore/efl_threadio.c new file mode 100644 index 0000000000..c7a283a6cf --- /dev/null +++ b/src/lib/ecore/efl_threadio.c @@ -0,0 +1,58 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Ecore.h> + +#include "ecore_private.h" + +#define MY_CLASS EFL_THREADIO_CLASS + +typedef struct _Efl_ThreadIO_Data Efl_ThreadIO_Data; + +struct _Efl_ThreadIO_Data +{ + void *indata, *outdata; +}; + +////////////////////////////////////////////////////////////////////////// + +////////////////////////////////////////////////////////////////////////// + +EOLIAN static void +_efl_threadio_indata_set(Eo *obj EINA_UNUSED, Efl_ThreadIO_Data *pd, void *data) +{ + pd->indata = data; +} + +EOLIAN static void * +_efl_threadio_indata_get(Eo *obj EINA_UNUSED, Efl_ThreadIO_Data *pd) +{ + return pd->indata; +} + +EOLIAN static void +_efl_threadio_outdata_set(Eo *obj EINA_UNUSED, Efl_ThreadIO_Data *pd, void *data) +{ + pd->outdata = data; +} + +EOLIAN static void * +_efl_threadio_outdata_get(Eo *obj EINA_UNUSED, Efl_ThreadIO_Data *pd) +{ + return pd->outdata; +} + +EOLIAN static void +_efl_threadio_call(Eo *obj EINA_UNUSED, Efl_ThreadIO_Data *pd EINA_UNUSED, void *func_data EINA_UNUSED, EFlThreadIOCall func EINA_UNUSED, Eina_Free_Cb func_free_cb EINA_UNUSED) +{ +} + +EOLIAN static void * +_efl_threadio_call_sync(Eo *obj EINA_UNUSED, Efl_ThreadIO_Data *pd EINA_UNUSED, void *func_data EINA_UNUSED, EFlThreadIOCallSync func EINA_UNUSED, Eina_Free_Cb func_free_cb EINA_UNUSED) +{ +} + +////////////////////////////////////////////////////////////////////////// + +#include "efl_threadio.eo.c" diff --git a/src/lib/ecore/efl_threadio.eo b/src/lib/ecore/efl_threadio.eo new file mode 100644 index 0000000000..53085ba51f --- /dev/null +++ b/src/lib/ecore/efl_threadio.eo @@ -0,0 +1,53 @@ +import efl_types; +import eina_types; + +function EFlThreadIOCall { + [[ A Function to call on the "other end" of a thread obvject ]] + params { + obj: Efl.Object; [[ ]] + } +}; + +function EFlThreadIOCallSync { + [[ A Function to call on the "other end" of a thread obvject ]] + params { + obj: Efl.Object; [[ ]] + } + return: void_ptr; [[ ]] +}; + +mixin Efl.ThreadIO +{ + [[ ]] + methods { + @property indata { + set { } + get { } + values { + data: void_ptr; [[ ]] + } + } + @property outdata { + set { } + get { } + values { + data: void_ptr; [[ ]] + } + } + call { + params { + func: EFlThreadIOCall; [[ ]] + } + } + call_sync { + params { + func: EFlThreadIOCallSync; [[ ]] + } + return: void_ptr; [[ ]] + } + } + events { + } + implements { + } +} --