forked from enlightenment/efl
efl task - change exit method to use normal event for multiple listeners
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.
This commit is contained in:
parent
ad48272ffe
commit
d1890f5eca
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 ";
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue