efl task - change exit method to use normal event for multiple listeners
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Tue, 10 Sep 2019 22:01:19 +0000 (23:01 +0100)
committerYeongjong Lee <yj34.lee@samsung.com>
Mon, 16 Sep 2019 01:23:00 +0000 (10:23 +0900)
we couldn't have multilpe listeners before. now we can. better this
way. have to do this now because i can't mark efl task as @beta
without taking out massive wads of efl with it.

src/examples/ecore/efl_exe.c
src/examples/ecore/efl_thread.c
src/lib/ecore/efl_exe.c
src/lib/ecore/efl_loop.c
src/lib/ecore/efl_task.eo
src/lib/ecore/efl_thread.c

index b546676..1458d06 100644 (file)
@@ -5,8 +5,8 @@
 #include <Eo.h>
 #include <Efl_Core.h>
 
-static void       _read_change(void *data EINA_UNUSED, const Efl_Event *ev);
-static Eina_Value _task_exit(void *data, Eina_Value v, const Eina_Future *dead EINA_UNUSED);
+static void _read_change(void *data EINA_UNUSED, const Efl_Event *ev);
+static void _task_exit(void *data EINA_UNUSED, const Efl_Event *ev);
 
 static void
 _read_change(void *data EINA_UNUSED, const Efl_Event *ev)
@@ -27,16 +27,19 @@ _read_change(void *data EINA_UNUSED, const Efl_Event *ev)
      }
 }
 
-static Eina_Value
-_task_exit(void *data, Eina_Value v, const Eina_Future *dead EINA_UNUSED)
+static void
+_task_exit(void *data EINA_UNUSED, const Efl_Event *ev)
 {
    // called when the task says it has completed and exited.
    // all output to read has stopped
-   Eo *obj = data;
+   Eo *obj = ev->object;
    printf("--- [%p] EXITED exit_code=%i\n", obj, efl_task_exit_code_get(obj));
    efl_loop_quit(efl_provider_find(obj, EFL_LOOP_CLASS), eina_value_int_init(99));
-   efl_del(obj);
-   return v;
+   // exe auto deleted at this point like efl threads. more convenient as
+   // you don't need to remember to delete them yourself if launching
+   // lots of commands - this is how ecore_exe worked. so listen to the
+   // exit event (or del event) if you care about this... or ref it to keep
+   // it around longer.
 }
 
 EAPI_MAIN void
@@ -55,7 +58,8 @@ efl_main(void *data EINA_UNUSED, const Efl_Event *ev)
                      efl_exe_env_set(efl_added, env),
                      efl_task_flags_set(efl_added, EFL_TASK_FLAGS_USE_STDOUT | EFL_TASK_FLAGS_USE_STDIN),
                      efl_event_callback_add(efl_added, EFL_IO_READER_EVENT_CAN_READ_CHANGED, _read_change, NULL),
-                     eina_future_then(efl_task_run(efl_added), _task_exit, efl_added)
+                     efl_event_callback_add(efl_added, EFL_TASK_EVENT_EXIT, _task_exit, NULL),
+                     efl_task_run(efl_added)
                     );
    efl_unref(env);
 
index fe300dc..301bf5c 100644 (file)
@@ -8,7 +8,7 @@
 static void _th_read_change(void *data EINA_UNUSED, const Efl_Event *ev);
 static void _th_main(void *data EINA_UNUSED, const Efl_Event *ev);
 static void _read_change(void *data EINA_UNUSED, const Efl_Event *ev);
-static Eina_Value _task_exit(void *data, Eina_Value v, const Eina_Future *dead EINA_UNUSED);
+static void _task_exit(void *data EINA_UNUSED, const Efl_Event *ev);
 
 ////////////////////////////////////////////////////////////////////////////
 //// thread side of code
@@ -85,7 +85,8 @@ _th_main(void *data EINA_UNUSED, const Efl_Event *ev)
                            efl_task_flags_set(efl_added, EFL_TASK_FLAGS_USE_STDOUT | EFL_TASK_FLAGS_USE_STDIN | EFL_TASK_FLAGS_EXIT_WITH_PARENT),
                            efl_event_callback_add(efl_added, EFL_LOOP_EVENT_ARGUMENTS, _th_main, NULL),
                            efl_event_callback_add(efl_added, EFL_IO_READER_EVENT_CAN_READ_CHANGED, _read_change, NULL),
-                           eina_future_then(efl_task_run(efl_added), _task_exit, efl_added)
+                           efl_event_callback_add(efl_added, EFL_TASK_EVENT_EXIT, _task_exit, NULL),
+                           efl_task_run(efl_added)
                           );
 
         char *buf2 = "hello-out-there2 ";
@@ -117,18 +118,17 @@ _read_change(void *data EINA_UNUSED, const Efl_Event *ev)
      }
 }
 
-static Eina_Value
-_task_exit(void *data, Eina_Value v, const Eina_Future *dead EINA_UNUSED)
+static void
+_task_exit(void *data EINA_UNUSED, const Efl_Event *ev)
 {
    // called when the task says it has completed and exited.
    // all output to read has stopped
-   Eo *obj = data;
+   Eo *obj = ev->object;
    printf("--- [%p] EXITED exit_code=%i outdata=%p\n", obj, efl_task_exit_code_get(obj), efl_threadio_outdata_get(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
+   // EFL_TASK_FLAGS_EXIT_WITH_PARENT 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;
 }
 
 ////////////////////////////////////////////////////////////////////////////
@@ -181,7 +181,8 @@ efl_main(void *data EINA_UNUSED, const Efl_Event *ev)
                           efl_task_flags_set(efl_added, EFL_TASK_FLAGS_USE_STDOUT | EFL_TASK_FLAGS_USE_STDIN | EFL_TASK_FLAGS_EXIT_WITH_PARENT),
                           efl_event_callback_add(efl_added, EFL_LOOP_EVENT_ARGUMENTS, _th_main, NULL),
                           efl_event_callback_add(efl_added, EFL_IO_READER_EVENT_CAN_READ_CHANGED, _read_change, NULL),
-                          eina_future_then(efl_task_run(efl_added), _task_exit, efl_added)
+                          efl_event_callback_add(efl_added, EFL_TASK_EVENT_EXIT, _task_exit, NULL),
+                          efl_task_run(efl_added)
                          );
 
         char *buf2 = "hello-out-there ";
index 21dfdf5..6dcac4f 100644 (file)
@@ -56,7 +56,6 @@ struct _Efl_Exe_Data
       Eina_Bool can_write : 1;
    } fd;
 #else
-   Eina_Promise *promise;
    Eo *exit_handler;
    pid_t pid;
    struct {
@@ -178,47 +177,8 @@ _exe_exit_eval(Eo *obj, Efl_Exe_Data *pd)
        (pd->fd.exited_read == -1) && (!pd->exit_called))
      {
         pd->exit_called = EINA_TRUE;
-        if (pd->promise)
-          {
-             Eina_Promise *p = pd->promise;
-             int exit_code = efl_task_exit_code_get(obj);
-             if ((exit_code != 0) && (!(efl_task_flags_get(obj) &
-                                        EFL_TASK_FLAGS_NO_EXIT_CODE_ERROR)))
-               {
-                  Eina_Error err = exit_code + 1000000;
-                  // Code  Meaning                        Example             Comments
-                  // ---------------------------------------------------------------------------------------------------------------------------------------------------------------------
-                  // 1     Catchall for general errors    let "var1 = 1/0"    Miscellaneous errors, such as "divide by zero" and other impermissible operations
-                  // 2     Misuse of shell builtins       empty_function() {} Missing keyword or command, or permission problem (and diff return code on a failed binary file comparison).
-                  // 126   Command invoked cannot execute /dev/null           Permission problem or command is not an executable
-                  // 127   "command not found"            illegal_command     Possible problem with $PATH or a typo
-                  // 128   Invalid argument to exit       exit 3.14159        exit takes only integer args in the range 0 - 255 (see first footnote)
-                  // 128+n Fatal error signal "n"         kill -9 $PPID       $? returns 137 (128 + 9)
-                  // 130   Script terminated by Control-C Ctl-C               Control-C is fatal error signal 2, (130 = 128 + 2, see above)
-                  // 255*  Exit status out of range       exit -1             exit takes only integer args in the range 0 - 255
-                  //
-                  // According to the above table, exit codes 1 - 2,
-                  // 126 - 165, and 255 [1] have special meanings, and
-                  // should therefore be avoided for user-specified exit
-                  // parameters. Ending a script with exit 127 would
-                  // certainly cause confusion when troubleshooting (is
-                  // the error code a "command not found" or a user-defined
-                  // one?). However, many scripts use an exit 1 as a general
-                  // bailout-upon-error. Since exit code 1 signifies so many
-                  // possible errors, it is not particularly useful in
-                  // debugging.
-                  if      (exit_code == 1  ) err = EBADF;
-                  else if (exit_code == 2  ) err = EDOM;
-                  else if (exit_code == 126) err = ENOEXEC;
-                  else if (exit_code == 127) err = ENOENT;
-                  else if (exit_code == 128) err = EINVAL;
-                  else if (exit_code == 129) err = EFAULT;
-                  else if (exit_code == 130) err = EINTR;
-                  else if ((exit_code >= 131) && (exit_code <= 165)) err = EFAULT;
-                  eina_promise_reject(p, err);
-               }
-             else eina_promise_resolve(p, eina_value_int_init(exit_code));
-          }
+        efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
+        efl_del(obj);
      }
 }
 
@@ -268,24 +228,6 @@ _cb_exe_in(void *data, const Efl_Event *event EINA_UNUSED)
    Eo *obj = data;
    efl_io_writer_can_write_set(obj, EINA_TRUE);
 }
-
-static Eina_Value
-_run_cancel_cb(Efl_Loop_Consumer *consumer, void *data EINA_UNUSED, Eina_Error error)
-{
-   if (error == ECANCELED) efl_task_end(consumer);
-
-   return eina_value_error_init(error);
-}
-
-static void
-_run_clean_cb(Efl_Loop_Consumer *consumer EINA_UNUSED,
-              void *data,
-              const Eina_Future *dead_future EINA_UNUSED)
-{
-   Efl_Exe_Data *pd = data;
-   pd->promise = NULL;
-}
-
 #endif
 
 //////////////////////////////////////////////////////////////////////////
@@ -399,7 +341,7 @@ _efl_exe_efl_task_priority_get(const Eo *obj EINA_UNUSED, Efl_Exe_Data *pd)
    return pri;
 }
 
-EOLIAN static Eina_Future *
+EOLIAN static Eina_Bool
 _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
 {
 #ifdef _WIN32
@@ -414,20 +356,20 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
    int pipe_exited[2];
    int ret;
 
-   if (pd->run) return NULL;
-   if (pd->pid != -1) return NULL;
-   if (!td) return NULL;
+   if (pd->run) return EINA_FALSE;
+   if (pd->pid != -1) return EINA_FALSE;
+   if (!td) return EINA_FALSE;
 
    // get a cmdline to run
    cmd = efl_core_command_line_command_get(obj);
-   if (!cmd) return NULL;
+   if (!cmd) return EINA_FALSE;
 
    ret = pipe(pipe_exited);
    if (EINA_UNLIKELY(ret != 0))
      {
         const int error = errno;
         ERR("pipe() failed: %s", strerror(error));
-        return NULL;
+        return EINA_FALSE;
      }
 
    pd->fd.exited_read = pipe_exited[0];
@@ -442,7 +384,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
           {
              const int error = errno;
              ERR("pipe() failed: %s", strerror(error));
-             return NULL;
+             return EINA_FALSE;
           }
         pd->fd.in = pipe_stdin[1];
         if (fcntl(pd->fd.in, F_SETFL, O_NONBLOCK) < 0)
@@ -461,7 +403,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
           {
              const int error = errno;
              ERR("pipe() failed: %s", strerror(error));
-             return NULL;
+             return EINA_FALSE;
           }
         pd->fd.out = pipe_stdout[0];
         if (fcntl(pd->fd.out, F_SETFL, O_NONBLOCK) < 0)
@@ -488,7 +430,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
           {
              _close_fds(pd);
              _ecore_signal_pid_unlock();
-             return NULL;
+             return EINA_FALSE;
           }
         // register this pid in the core sigchild/pid exit code watcher
         _ecore_signal_pid_register(pd->pid, pd->fd.exited_write);
@@ -502,11 +444,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
                                               EFL_LOOP_HANDLER_FLAGS_READ));
         _ecore_signal_pid_unlock();
         pd->run = EINA_TRUE;
-        pd->promise = efl_loop_promise_new(obj);
-        return efl_future_then(obj, eina_future_new(pd->promise),
-                               .data = pd,
-                               .error = _run_cancel_cb,
-                               .free = _run_clean_cb);
+        return EINA_TRUE;
      }
    // this code is in the child here, and is temporary setup until we
    // exec() the child to replace everything.
@@ -609,7 +547,7 @@ _efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
        (errno == ENOEXEC) || (errno == ENOMEM))
      exit(126);
    exit(127);
-   return NULL;
+   return EINA_FALSE;
 #endif
 }
 
@@ -651,7 +589,7 @@ _efl_exe_efl_object_destructor(Eo *obj, Efl_Exe_Data *pd)
 {
 #ifdef _WIN32
 #else
-   if (pd->promise)
+   if (!pd->exit_called)
      ERR("Exe being destroyed while child has not exited yet.");
    if (pd->fd.exited_read >= 0)
      {
index 17a2835..e40dbef 100644 (file)
@@ -642,21 +642,11 @@ efl_build_version_set(int vmaj, int vmin, int vmic, int revision,
    _app_efl_version.build_id = build_id ? strdup(build_id) : NULL;
 }
 
-EOLIAN static Eina_Future *
+EOLIAN static Eina_Bool
 _efl_loop_efl_task_run(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
 {
-   Eina_Value *ret;
-   int real;
-
-   ret = efl_loop_begin(obj);
-   real = efl_loop_exit_code_process(ret);
-   if (real == 0)
-     {
-        // we never return a valid future here because there is no loop
-        // any more to process the future callback as we would have quit
-        return NULL;
-     }
-   return NULL;
+   efl_loop_exit_code_process(efl_loop_begin(obj));
+   return EINA_TRUE;
 }
 
 EOLIAN static void
index 6fd162b..caef983 100644 (file)
@@ -54,7 +54,7 @@ abstract Efl.Task extends Efl.Loop_Consumer
       }
       run @pure_virtual {
          [[Actually run the task.]]
-         return: future<void> @move; [[A future triggered when task exits and is passed int exit code.]]
+         return: bool; [[On success in starting the task, return true, otherwise false]]
       }
       end @pure_virtual {
          [[Request the task end (may send a signal or interrupt
@@ -63,6 +63,7 @@ abstract Efl.Task extends Efl.Loop_Consumer
       }
    }
    events {
+      exit: void; [[Called when the task exits. You can pick up any information you need at this point such as exit_code etc.]]
    }
    implements {
       Efl.Object.constructor;
index d0aaea7..8bd4c3e 100644 (file)
@@ -68,7 +68,6 @@ struct _Efl_Thread_Data
       Eina_Bool can_write : 1;
    } fd, ctrl;
    int read_listeners;
-   Eina_Promise *promise;
    Eo *loop;
    Thread_Data *thdat;
    Efl_Callback_Array_Item_Full *event_cb;
@@ -363,15 +362,7 @@ _thread_exit_eval(Eo *obj, Efl_Thread_Data *pd)
      {
         pd->exit_called = EINA_TRUE;
         if (pd->thdat) efl_threadio_outdata_set(obj, pd->thdat->outdata);
-        if (pd->promise)
-          {
-             Eina_Promise *p = pd->promise;
-             int exit_code = efl_task_exit_code_get(obj);
-             if ((exit_code != 0) && (!(efl_task_flags_get(obj) &
-                                        EFL_TASK_FLAGS_NO_EXIT_CODE_ERROR)))
-               eina_promise_reject(p, exit_code + 1000000);
-             else eina_promise_resolve(p, eina_value_int_init(exit_code));
-          }
+        efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
         efl_del(obj);
      }
 }
@@ -448,22 +439,6 @@ _cb_thread_parent_ctrl_out(void *data, const Efl_Event *event EINA_UNUSED)
 
 //////////////////////////////////////////////////////////////////////////
 
-static Eina_Value
-_run_cancel_cb(Efl_Loop_Consumer *consumer, void *data EINA_UNUSED, Eina_Error error)
-{
-   if (error == ECANCELED) efl_task_end(consumer);
-
-   return eina_value_error_init(error);
-}
-
-static void
-_run_clean_cb(Efl_Loop_Consumer *consumer EINA_UNUSED,void *data, const Eina_Future *dead_future EINA_UNUSED)
-{
-   Efl_Thread_Data *pd = data;
-
-   pd->promise = NULL;
-}
-
 static void
 _thread_parent_read_listeners_modify(Efl_Thread_Data *pd, int mod)
 {
@@ -613,7 +588,7 @@ _efl_thread_efl_object_finalize(Eo *obj, Efl_Thread_Data *pd EINA_UNUSED)
 EOLIAN static void
 _efl_thread_efl_object_destructor(Eo *obj, Efl_Thread_Data *pd)
 {
-   if (pd->promise)
+   if (pd->exit_called)
      ERR("Thread being destroyed while real worker has  not exited yet.");
    if (pd->thdat)
      {
@@ -664,7 +639,7 @@ _task_run_pipe_fail_clear(Thread_Data *thdat, Efl_Thread_Data *pd)
    free(thdat);
 }
 
-EOLIAN static Eina_Future *
+EOLIAN static Eina_Bool
 _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
 {
    Eina_Thread_Priority pri;
@@ -676,10 +651,10 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
    Efl_Callback_Array_Item_Full *it;
    Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
 
-   if (pd->run) return NULL;
-   if (!td) return NULL;
+   if (pd->run) return EINA_FALSE;
+   if (!td) return EINA_FALSE;
    thdat = calloc(1, sizeof(Thread_Data));
-   if (!thdat) return NULL;
+   if (!thdat) return EINA_FALSE;
    thdat->fd.in = -1;
    thdat->fd.out = -1;
    thdat->ctrl.in = -1;
@@ -695,7 +670,7 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
           {
              ERR("Can't create to_thread pipe");
              free(thdat);
-             return NULL;
+             return EINA_FALSE;
           }
      }
    if (td->flags & EFL_TASK_FLAGS_USE_STDOUT)
@@ -709,7 +684,7 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
                   close(pipe_from_thread[1]);
                }
              free(thdat);
-             return NULL;
+             return EINA_FALSE;
           }
      }
    if (td->flags & EFL_TASK_FLAGS_USE_STDIN)
@@ -752,7 +727,7 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
      {
         ERR("Can't create to_thread control pipe");
         _task_run_pipe_fail_clear(thdat, pd);
-        return NULL;
+        return EINA_FALSE;
      }
    if (pipe(pipe_from_thread) != 0)
      {
@@ -760,7 +735,7 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
         _task_run_pipe_fail_clear(thdat, pd);
         close(pipe_to_thread[0]);
         close(pipe_to_thread[1]);
-        return NULL;
+        return EINA_FALSE;
      }
    thdat->ctrl.in  = pipe_from_thread[1]; // write - input to parent
    thdat->ctrl.out = pipe_to_thread  [0]; // read - output from parent
@@ -864,13 +839,11 @@ _efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
         pd->fd.out = -1;
         pd->ctrl.in = -1;
         pd->ctrl.out = -1;
-        return NULL;
+        return EINA_FALSE;
      }
    pd->thdat = thdat;
    pd->run = EINA_TRUE;
-   pd->promise = efl_loop_promise_new(obj);
-   return efl_future_then(obj, eina_future_new(pd->promise),
-                          .data = pd, .error = _run_cancel_cb, .free = _run_clean_cb);
+   return EINA_TRUE;
 }
 
 EOLIAN static void