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;