diff options
author | Carsten Haitzler (Rasterman) <raster@rasterman.com> | 2019-08-26 13:46:32 +0100 |
---|---|---|
committer | Carsten Haitzler (Rasterman) <raster@rasterman.com> | 2019-08-26 14:19:30 +0100 |
commit | d4c123d360beeb06889e69d8d8780049efc89d56 (patch) | |
tree | 5c9efbf58b7599af6c05d130e8c096c17ef207f8 | |
parent | 634ebfeaf15ba475ed9f8dabcb9ca66c9d06f939 (diff) | |
download | efl-d4c123d360beeb06889e69d8d8780049efc89d56.tar.gz |
efl loops/threads - by defaylt tasks (exe and threads) exit with parent
this also defers parent exit until all children exit and will wait
around looping until those children do report back with exited status
etc. - this meay mean some hangs for badly written/blocking apps that
have efl thrrads that refuse to exit. a slight policy change also
means that by default thread objects also get auto-deleted whent hey
report back exit codes etc. which leads to less code if you don't care
about this.
-rw-r--r-- | src/examples/ecore/efl_thread.c | 5 | ||||
-rw-r--r-- | src/lib/ecore/ecore_private.h | 7 | ||||
-rw-r--r-- | src/lib/ecore/efl_exe.c | 8 | ||||
-rw-r--r-- | src/lib/ecore/efl_exe.eo | 1 | ||||
-rw-r--r-- | src/lib/ecore/efl_loop.c | 23 | ||||
-rw-r--r-- | src/lib/ecore/efl_task.c | 8 | ||||
-rw-r--r-- | src/lib/ecore/efl_task.eo | 6 | ||||
-rw-r--r-- | src/lib/ecore/efl_thread.c | 45 | ||||
-rw-r--r-- | src/lib/ecore/efl_thread.eo | 1 |
9 files changed, 94 insertions, 10 deletions
diff --git a/src/examples/ecore/efl_thread.c b/src/examples/ecore/efl_thread.c index 927218d41a..b3d695ddd0 100644 --- a/src/examples/ecore/efl_thread.c +++ b/src/examples/ecore/efl_thread.c @@ -124,7 +124,10 @@ _task_exit(void *data, Eina_Value v, const Eina_Future *dead EINA_UNUSED) // all output to read has stopped Eo *obj = data; printf("--- [%p] EXITED exit_code=%i outdata=%p\n", obj, efl_task_exit_code_get(obj), efl_threadio_outdata_get(obj)); - efl_del(obj); + // thread object will be automatically deleted after as long as + // EFL_TASK_FLAGS_EXIT_WITH_PAREN is set on task flags, and this is + // actually the default unless you change the flags to be something + // else. if you don't use this then the task/thread becomes orphaned return v; } diff --git a/src/lib/ecore/ecore_private.h b/src/lib/ecore/ecore_private.h index 99a3fb7740..de3b47b60c 100644 --- a/src/lib/ecore/ecore_private.h +++ b/src/lib/ecore/ecore_private.h @@ -144,6 +144,8 @@ struct _Efl_Loop_Data Eina_List *win32_handlers_to_delete; # endif + Eina_List *thread_children; + Eina_Inlist *message_queue; unsigned int message_walking; @@ -176,7 +178,8 @@ struct _Efl_Loop_Data char **environ_copy; } env; - Eina_Bool do_quit; + Eina_Bool do_quit : 1; + Eina_Bool quit_on_last_thread_child_del : 1; }; struct _Efl_Task_Data @@ -457,6 +460,8 @@ void _efl_loop_messages_call(Eo *obj, Efl_Loop_Data *pd, void *func, void *data) void _efl_loop_message_send_info_set(Eo *obj, Eina_Inlist *node, Eo *loop, Efl_Loop_Data *loop_data); void _efl_loop_message_unsend(Eo *obj); +void _efl_thread_child_remove(Eo *loop, Efl_Loop_Data *pd, Eo *child); + static inline Eina_Bool _ecore_call_task_cb(Ecore_Task_Cb func, void *data) diff --git a/src/lib/ecore/efl_exe.c b/src/lib/ecore/efl_exe.c index 75cba04404..21dfdf50d1 100644 --- a/src/lib/ecore/efl_exe.c +++ b/src/lib/ecore/efl_exe.c @@ -98,7 +98,7 @@ _close_fds(Efl_Exe_Data *pd) } static void -_exec(const char *cmd, Efl_Exe_Flags flags) +_exec(const char *cmd, Efl_Exe_Flags flags, Efl_Task_Flags task_flags) { char use_sh = 1, *buf = NULL, **args = NULL; @@ -149,7 +149,7 @@ _exec(const char *cmd, Efl_Exe_Flags flags) } } # ifdef HAVE_PRCTL - if (flags & EFL_EXE_FLAGS_EXIT_WITH_PARENT) + if (task_flags & EFL_TASK_FLAGS_EXIT_WITH_PARENT) prctl(PR_SET_PDEATHSIG, SIGTERM); # endif @@ -603,7 +603,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd) } // actually execute! - _exec(cmd, pd->flags); + _exec(cmd, pd->flags, td->flags); // we couldn't exec... uh oh. HAAAAAAAALP! if ((errno == EACCES) || (errno == EINVAL) || (errno == ELOOP) || (errno == ENOEXEC) || (errno == ENOMEM)) @@ -641,7 +641,7 @@ _efl_exe_efl_object_constructor(Eo *obj, Efl_Exe_Data *pd) pd->fd.exited_read = -1; #endif pd->fd.can_write = EINA_TRUE; - pd->flags = EFL_EXE_FLAGS_EXIT_WITH_PARENT; + pd->flags = 0; pd->exit_signal = -1; return obj; } diff --git a/src/lib/ecore/efl_exe.eo b/src/lib/ecore/efl_exe.eo index 823858e4a3..8cf8466f93 100644 --- a/src/lib/ecore/efl_exe.eo +++ b/src/lib/ecore/efl_exe.eo @@ -18,7 +18,6 @@ enum @beta Efl.Exe_Flags { [[Flags to customize task behavior.]] // TODO: This needs more detail. none = 0, [[No special flags.]] group_leader = 1, [[Process will be executed in its own session.]] - exit_with_parent = 2, [[Exit process when parent process exits.]] hide_io = 4 [[All console IO will be hidden.]] } diff --git a/src/lib/ecore/efl_loop.c b/src/lib/ecore/efl_loop.c index 3a7171c565..17a2835396 100644 --- a/src/lib/ecore/efl_loop.c +++ b/src/lib/ecore/efl_loop.c @@ -55,6 +55,26 @@ EOLIAN static Eina_Value * _efl_loop_begin(Eo *obj, Efl_Loop_Data *pd) { _ecore_main_loop_begin(obj, pd); + if (pd->thread_children) + { + Eina_List *l, *ll; + Eo *child; + + // request all child threads to die and defer the quit until + // the children have all died and returned. + // run main loop again to clean out children and their exits + pd->quit_on_last_thread_child_del = EINA_TRUE; + EINA_LIST_FOREACH_SAFE(pd->thread_children, l, ll, child) + { + Efl_Task_Flags task_flags = efl_task_flags_get(child); + + if (task_flags & EFL_TASK_FLAGS_EXIT_WITH_PARENT) + efl_task_end(child); + else + _efl_thread_child_remove(obj, pd, child); + } + if (pd->thread_children) _ecore_main_loop_begin(obj, pd); + } return &(pd->exit_code); } @@ -304,7 +324,8 @@ EOLIAN static void _efl_loop_efl_object_destructor(Eo *obj, Efl_Loop_Data *pd) { pd->future_message_handler = NULL; - + while (pd->thread_children) + _efl_thread_child_remove(obj, pd, pd->thread_children->data); efl_destructor(efl_super(obj, EFL_LOOP_CLASS)); } diff --git a/src/lib/ecore/efl_task.c b/src/lib/ecore/efl_task.c index d610fcbf8b..502c767aaa 100644 --- a/src/lib/ecore/efl_task.c +++ b/src/lib/ecore/efl_task.c @@ -50,6 +50,14 @@ _efl_task_efl_object_destructor(Eo *obj EINA_UNUSED, Efl_Task_Data *pd) efl_destructor(efl_super(obj, MY_CLASS)); } +EOLIAN static Efl_Object * +_efl_task_efl_object_constructor(Eo *obj, Efl_Task_Data *pd) +{ + obj = efl_constructor(efl_super(obj, EFL_TASK_CLASS)); + pd->flags = EFL_TASK_FLAGS_EXIT_WITH_PARENT; + return obj; +} + EOLIAN static void _efl_task_efl_object_parent_set(Eo *obj, Efl_Task_Data *pd EINA_UNUSED, Efl_Object *parent) { diff --git a/src/lib/ecore/efl_task.eo b/src/lib/ecore/efl_task.eo index 2d1c7dfe60..9fe006a34c 100644 --- a/src/lib/ecore/efl_task.eo +++ b/src/lib/ecore/efl_task.eo @@ -18,6 +18,7 @@ enum Efl.Task_Flags { use_stdin = 1, [[Task will require console input.]] use_stdout = 2, [[Task will require console output.]] no_exit_code_error = 4, [[Task will not produce an exit code upon termination.]] + exit_with_parent = 8, [[Exit when parent exits.]] } abstract Efl.Task extends Efl.Loop_Consumer @@ -42,7 +43,9 @@ abstract Efl.Task extends Efl.Loop_Consumer } } @property flags { - [[Flags to further customize task's behavior.]] + [[Flags to further customize task's behavior. The default value: + exit_with_parent + ]] set { } get { } values { @@ -62,6 +65,7 @@ abstract Efl.Task extends Efl.Loop_Consumer events { } implements { + Efl.Object.constructor; Efl.Object.destructor; Efl.Object.parent { set; } } diff --git a/src/lib/ecore/efl_thread.c b/src/lib/ecore/efl_thread.c index a5bb07caef..5211b541b4 100644 --- a/src/lib/ecore/efl_thread.c +++ b/src/lib/ecore/efl_thread.c @@ -372,6 +372,7 @@ _thread_exit_eval(Eo *obj, Efl_Thread_Data *pd) eina_promise_reject(p, exit_code + 1000000); else eina_promise_resolve(p, eina_value_int_init(exit_code)); } + efl_del(obj); } } @@ -567,6 +568,48 @@ _efl_thread_efl_object_constructor(Eo *obj, Efl_Thread_Data *pd) return obj; } + +static void +_child_thread_del_cb(void *data, const Efl_Event *event) +{ + Eo *loop = data; + Efl_Loop_Data *loop_data = efl_data_scope_get(loop, EFL_LOOP_CLASS); + + if (!loop_data) return; + _efl_thread_child_remove(loop, loop_data, event->object); + if (!loop_data->quit_on_last_thread_child_del) return; + if (loop_data->thread_children) return; + // no more children waiting exits - quit the loop + _ecore_main_loop_quit(loop, loop_data); +} + +EFL_CALLBACKS_ARRAY_DEFINE(thread_child_del, + { EFL_EVENT_DEL, _child_thread_del_cb }); + +void +_efl_thread_child_remove(Eo *loop, Efl_Loop_Data *pd, Eo *child) +{ + pd->thread_children = eina_list_remove(pd->thread_children, child); + efl_event_callback_array_del(child, thread_child_del(), loop); +} + +EOLIAN static Efl_Object * +_efl_thread_efl_object_finalize(Eo *obj, Efl_Thread_Data *pd EINA_UNUSED) +{ + Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS); + if (loop != obj) + { + Efl_Loop_Data *loop_data = efl_data_scope_get(loop, EFL_LOOP_CLASS); + if (loop_data) + { + loop_data->thread_children = + eina_list_prepend(loop_data->thread_children, obj); + efl_event_callback_array_add(obj, thread_child_del(), loop); + } + } + return obj; +} + EOLIAN static void _efl_thread_efl_object_destructor(Eo *obj, Efl_Thread_Data *pd) { @@ -834,7 +877,7 @@ EOLIAN static void _efl_thread_efl_task_end(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd) { if (pd->end_sent) return; - if (pd->thdat) + if ((pd->thdat) && (!pd->exit_called)) { Control_Data cmd; diff --git a/src/lib/ecore/efl_thread.eo b/src/lib/ecore/efl_thread.eo index b935077d8e..901ecf4f78 100644 --- a/src/lib/ecore/efl_thread.eo +++ b/src/lib/ecore/efl_thread.eo @@ -4,6 +4,7 @@ class @beta Efl.Thread extends Efl.Task implements Efl.ThreadIO, Efl.Io.Reader, } implements { Efl.Object.constructor; + Efl.Object.finalize; Efl.Object.destructor; Efl.Object.parent { set; } Efl.Task.run; |