summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>2019-08-26 13:46:32 +0100
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>2019-08-26 14:19:30 +0100
commitd4c123d360beeb06889e69d8d8780049efc89d56 (patch)
tree5c9efbf58b7599af6c05d130e8c096c17ef207f8
parent634ebfeaf15ba475ed9f8dabcb9ca66c9d06f939 (diff)
downloadefl-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.c5
-rw-r--r--src/lib/ecore/ecore_private.h7
-rw-r--r--src/lib/ecore/efl_exe.c8
-rw-r--r--src/lib/ecore/efl_exe.eo1
-rw-r--r--src/lib/ecore/efl_loop.c23
-rw-r--r--src/lib/ecore/efl_task.c8
-rw-r--r--src/lib/ecore/efl_task.eo6
-rw-r--r--src/lib/ecore/efl_thread.c45
-rw-r--r--src/lib/ecore/efl_thread.eo1
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;