#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)
}
}
-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
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);
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
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 ";
}
}
-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;
}
////////////////////////////////////////////////////////////////////////////
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 ";
Eina_Bool can_write : 1;
} fd;
#else
- Eina_Promise *promise;
Eo *exit_handler;
pid_t pid;
struct {
(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);
}
}
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
//////////////////////////////////////////////////////////////////////////
return pri;
}
-EOLIAN static Eina_Future *
+EOLIAN static Eina_Bool
_efl_exe_efl_task_run(Eo *obj, Efl_Exe_Data *pd)
{
#ifdef _WIN32
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];
{
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)
{
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)
{
_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);
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.
(errno == ENOEXEC) || (errno == ENOMEM))
exit(126);
exit(127);
- return NULL;
+ return EINA_FALSE;
#endif
}
{
#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)
{
_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
}
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
}
}
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;
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;
{
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);
}
}
//////////////////////////////////////////////////////////////////////////
-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)
{
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)
{
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;
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;
{
ERR("Can't create to_thread pipe");
free(thdat);
- return NULL;
+ return EINA_FALSE;
}
}
if (td->flags & EFL_TASK_FLAGS_USE_STDOUT)
close(pipe_from_thread[1]);
}
free(thdat);
- return NULL;
+ return EINA_FALSE;
}
}
if (td->flags & EFL_TASK_FLAGS_USE_STDIN)
{
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)
{
_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
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