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.
This commit is contained in:
parent
634ebfeaf1
commit
d4c123d360
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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.]]
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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; }
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue