raster pushed a commit to branch master.

http://git.enlightenment.org/core/efl.git/commit/?id=d4c123d360beeb06889e69d8d8780049efc89d56

commit d4c123d360beeb06889e69d8d8780049efc89d56
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Mon Aug 26 13:46:32 2019 +0100

    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.
---
 src/examples/ecore/efl_thread.c |  5 ++++-
 src/lib/ecore/ecore_private.h   |  7 ++++++-
 src/lib/ecore/efl_exe.c         |  8 ++++----
 src/lib/ecore/efl_exe.eo        |  1 -
 src/lib/ecore/efl_loop.c        | 23 ++++++++++++++++++++-
 src/lib/ecore/efl_task.c        |  8 ++++++++
 src/lib/ecore/efl_task.eo       |  6 +++++-
 src/lib/ecore/efl_thread.c      | 45 ++++++++++++++++++++++++++++++++++++++++-
 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;

-- 


Reply via email to