ecore - a different take on efl.app class as a super class to efl.loop

so the MAIN loop is actually an efl.app object. which inherits from
efl.loop. the idea is that other loops in threads will not be efl.app
objects. thread on the creator side return an efl.thread object.
inside the thread, like the mainloop, there is now an efl.appthread
object that is for all non-main-loop threads.

every thread (main loop or child) when it spawns a thread is the
parent. there are i/o pipes from parnet to child and back. so parents
are generally expected to, if they want to talk to child thread, so
use the efl.io interfaces on efl.thread, and the main loop's elf.app
class allows you to talk to stdio back to the parent process like the
efl.appthread does the same using the efl.io interfaces to talk to its
parent app or appthread. it's symmetrical

no tests here - sure. i have been holding off on tests until things
settle. that's why i haven't done them yet. those will come back in a
subsequent commit

for really quick examples on using this see:

https://phab.enlightenment.org/F2983118
https://phab.enlightenment.org/F2983142

they are just my test code for this.

Please see this design document:

https://phab.enlightenment.org/w/efl-loops-threads/
This commit is contained in:
Carsten Haitzler 2018-02-27 21:19:17 +09:00
parent 1c74aaa7e9
commit 1bdd9e4dd1
35 changed files with 1881 additions and 185 deletions

View File

@ -8,6 +8,7 @@ ecore_eolian_files_legacy = \
lib/ecore/efl_loop_timer.eo
ecore_eolian_files_public = \
lib/ecore/efl_app.eo \
lib/ecore/efl_loop.eo \
lib/ecore/efl_loop_consumer.eo \
lib/ecore/efl_loop_fd.eo \
@ -16,6 +17,8 @@ ecore_eolian_files_public = \
lib/ecore/efl_loop_message_handler.eo \
lib/ecore/efl_exe.eo \
lib/ecore/efl_thread.eo \
lib/ecore/efl_appthread.eo \
lib/ecore/efl_task.eo \
lib/ecore/efl_io_closer_fd.eo \
lib/ecore/efl_io_positioner_fd.eo \
lib/ecore/efl_io_reader_fd.eo \
@ -35,8 +38,7 @@ ecore_eolian_files_public = \
lib/ecore/efl_interpolator_divisor.eo \
lib/ecore/efl_interpolator_bounce.eo \
lib/ecore/efl_interpolator_spring.eo \
lib/ecore/efl_interpolator_cubic_bezier.eo \
lib/ecore/efl_task.eo
lib/ecore/efl_interpolator_cubic_bezier.eo
ecore_eolian_files = \
$(ecore_eolian_files_public) \
@ -95,6 +97,7 @@ lib/ecore/ecore_job.c \
lib/ecore/ecore_main.c \
lib/ecore/ecore_event_message.c \
lib/ecore/ecore_event_message_handler.c \
lib/ecore/efl_app.c \
lib/ecore/efl_loop.c \
lib/ecore/efl_loop_consumer.c \
lib/ecore/efl_loop_fd.c \
@ -134,6 +137,8 @@ lib/ecore/efl_interpolator_spring.c \
lib/ecore/efl_interpolator_cubic_bezier.c \
lib/ecore/efl_task.c \
lib/ecore/efl_exe.c \
lib/ecore/efl_thread.c \
lib/ecore/efl_appthread.c \
lib/ecore/ecore_main_timechanges.c \
lib/ecore/ecore_pipe.c \
lib/ecore/ecore_poller.c \

View File

@ -45,9 +45,12 @@
#include "efl_loop_message_handler.eo.h"
#include "efl_task.eo.h"
#include "efl_thread.eo.h"
#include "efl_exe.eo.h"
#include "efl_loop.eo.h"
#include "efl_app.eo.h"
#include "efl_appthread.eo.h"
/**
* @brief Quits the main loop once all the events currently on the queue have
@ -103,6 +106,7 @@ EAPI Eina_Promise *efl_loop_promise_new(const Eo *obj, Eina_Promise_Cancel_Cb ca
/* We ue the factory pattern here, so you shouldn't call eo_add directly. */
EAPI Eo *efl_main_loop_get(void);
EAPI Eo *efl_app_get(void);
typedef struct _Efl_Future_Composite_Progress Efl_Future_All_Progress;

View File

@ -215,8 +215,7 @@ _efl_first_loop_iterate(void *data, const Efl_Event *event)
case 'T': fprintf(stderr, "Loop started: '%f' - '%f' = '%f' sec\n", end, _efl_startup_time, end - _efl_startup_time);
break;
}
efl_event_callback_del(event->object, EFL_LOOP_EVENT_RESUME,
efl_event_callback_del(event->object, EFL_APP_EVENT_RESUME,
_efl_first_loop_iterate, data);
}
@ -345,13 +344,11 @@ ecore_init(void)
if (!_no_system_modules)
ecore_system_modules_load();
if (getenv("EFL_FIRST_LOOP"))
efl_event_callback_add(efl_main_loop_get(),
EFL_LOOP_EVENT_RESUME,
EFL_APP_EVENT_RESUME,
_efl_first_loop_iterate,
getenv("EFL_FIRST_LOOP"));
_ecore_init_count_threshold = _ecore_init_count;
eina_log_timing(_ecore_log_dom,
@ -390,8 +387,7 @@ ecore_shutdown(void)
}
if (_ecore_init_count-- != _ecore_init_count_threshold)
goto end;
efl_event_callback_call(efl_main_loop_get(), EFL_LOOP_EVENT_TERMINATE, NULL);
efl_event_callback_call(efl_main_loop_get(), EFL_APP_EVENT_TERMINATE, NULL);
ecore_system_modules_unload();

View File

@ -66,7 +66,7 @@ ecore_exe_pipe_run(const char *exe_cmd,
const void *data)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
Ecore_Exe *ret = efl_add(MY_CLASS, efl_loop_main_get(EFL_LOOP_CLASS),
Ecore_Exe *ret = efl_add(MY_CLASS, efl_main_loop_get(),
ecore_obj_exe_command_set(efl_added, exe_cmd,
flags));
if (ret)

View File

@ -1372,7 +1372,7 @@ ecore_main_fd_handler_add(int fd,
{
Ecore_Fd_Handler *fdh = NULL;
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
fdh = _ecore_main_fd_handler_add(efl_loop_main_get(EFL_LOOP_CLASS),
fdh = _ecore_main_fd_handler_add(efl_main_loop_get(),
ML_DAT, NULL, fd, flags, func, data,
buf_func, buf_data, EINA_FALSE);
if (fdh) fdh->legacy = EINA_TRUE;
@ -1388,7 +1388,7 @@ ecore_main_fd_handler_file_add(int fd,
const void *buf_data)
{
EINA_MAIN_LOOP_CHECK_RETURN_VAL(NULL);
return _ecore_main_fd_handler_add(efl_loop_main_get(EFL_LOOP_CLASS),
return _ecore_main_fd_handler_add(efl_main_loop_get(),
ML_DAT, NULL, fd, flags, func, data,
buf_func, buf_data, EINA_TRUE);
}
@ -1595,7 +1595,7 @@ ecore_main_fd_handler_active_set(Ecore_Fd_Handler *fd_handler,
}
void
_ecore_main_content_clear(Efl_Loop_Data *pd)
_ecore_main_content_clear(Eo *obj, Efl_Loop_Data *pd)
{
Efl_Promise *promise;
Efl_Future *future;
@ -1608,7 +1608,7 @@ _ecore_main_content_clear(Efl_Loop_Data *pd)
ecore_loop_promise_fulfill(promise);
// FIXME
__eina_promise_cancel_all();
__eina_promise_cancel_data(obj);
while (pd->fd_handlers)
{

View File

@ -88,6 +88,7 @@ typedef struct _Efl_Loop_Future_Scheduler Efl_Loop_Future_Scheduler;
typedef struct _Efl_Loop_Data Efl_Loop_Data;
typedef struct _Efl_Task_Data Efl_Task_Data;
typedef struct _Efl_Appthread_Data Efl_Appthread_Data;
typedef struct _Message_Handler Message_Handler;
typedef struct _Message Message;
@ -193,6 +194,18 @@ struct _Efl_Task_Data
Eina_Bool exited : 1;
};
struct _Efl_Appthread_Data
{
struct {
int in, out;
Eo *in_handler, *out_handler;
Eina_Bool can_read : 1;
Eina_Bool eos_read : 1;
Eina_Bool can_write : 1;
} fd, ctrl;
int read_listeners;
};
#define EVAS_FRAME_QUEUING 1 /* for test */
@ -325,7 +338,7 @@ _ecore_main_win32_handler_del(Eo *obj,
Efl_Loop_Data *pd,
Ecore_Win32_Handler *win32_handler);
void _ecore_main_content_clear(Efl_Loop_Data *pd);
void _ecore_main_content_clear(Eo *obj, Efl_Loop_Data *pd);
void _ecore_main_shutdown(void);
#if defined (_WIN32) || defined (__lv2ppu__) || defined (HAVE_EXOTIC)
@ -525,7 +538,7 @@ void ecore_loop_promise_fulfill(Efl_Promise *p);
// access to direct input cb
#define ECORE_EVAS_INTERNAL
#define EFL_LOOP_DATA efl_data_scope_get(efl_loop_main_get(EFL_LOOP_CLASS), EFL_LOOP_CLASS)
#define EFL_LOOP_DATA efl_data_scope_get(efl_main_loop_get(), EFL_LOOP_CLASS)
EOAPI Eina_Bool efl_loop_message_process(Eo *obj);

View File

@ -78,9 +78,9 @@ _ecore_signal_pipe_read(Eo *obj)
if (loop)
{
if (sdata.sig == SIGUSR1)
efl_event_callback_call(loop, EFL_LOOP_EVENT_SIGNAL_USR1, NULL);
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_USR1, NULL);
else
efl_event_callback_call(loop, EFL_LOOP_EVENT_SIGNAL_USR2, NULL);
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_USR2, NULL);
}
}
break;
@ -95,7 +95,7 @@ _ecore_signal_pipe_read(Eo *obj)
}
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
if (loop)
efl_event_callback_call(loop, EFL_LOOP_EVENT_SIGNAL_HUP, NULL);
efl_event_callback_call(loop, EFL_APP_EVENT_SIGNAL_HUP, NULL);
}
break;
case SIGQUIT:
@ -112,6 +112,9 @@ _ecore_signal_pipe_read(Eo *obj)
ecore_event_add(ECORE_EVENT_SIGNAL_EXIT, e,
_ecore_signal_generic_free, NULL);
}
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
if (loop)
efl_event_callback_call(loop, EFL_TASK_EVENT_EXIT, NULL);
}
break;
#ifdef SIGPWR

View File

@ -74,7 +74,7 @@ static void
_check_timer_event_catcher_add(void *data, const Efl_Event *event)
{
Efl_Loop_Timer_Data *timer = data;
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
@ -94,7 +94,7 @@ static void
_check_timer_event_catcher_del(void *data, const Efl_Event *event)
{
Efl_Loop_Timer_Data *timer = data;
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)

415
src/lib/ecore/efl_app.c Normal file
View File

@ -0,0 +1,415 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#define EFL_IO_READER_PROTECTED 1
#define EFL_IO_WRITER_PROTECTED 1
#define EFL_IO_CLOSER_PROTECTED 1
#include <Ecore.h>
#include "ecore_private.h"
#ifndef _WIN32
# include <sys/resource.h>
#endif
#define MY_CLASS EFL_APP_CLASS
typedef struct _Efl_App_Data Efl_App_Data;
struct _Efl_App_Data
{
struct {
int in, out;
Eo *in_handler, *out_handler;
Eina_Bool can_read : 1;
Eina_Bool eos_read : 1;
Eina_Bool can_write : 1;
} fd;
int read_listeners;
};
Efl_Version _app_efl_version = { 0, 0, 0, 0, NULL, NULL };
//////////////////////////////////////////////////////////////////////////
EAPI Eo *
efl_app_get(void)
{
return efl_main_loop_get();
}
//////////////////////////////////////////////////////////////////////////
static void
_parent_read_listeners_modify(Efl_App_Data *pd, int mod)
{
pd->read_listeners += mod;
if (pd->fd.out_handler)
{
if ((pd->read_listeners == 0) && (mod < 0))
efl_loop_handler_active_set
(pd->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_NONE);
else if ((pd->read_listeners == 1) && (mod > 0))
efl_loop_handler_active_set
(pd->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_READ);
}
}
static void
_cb_event_callback_add(void *data, const Efl_Event *event)
{
Efl_App_Data *pd = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_IO_READER_EVENT_CAN_READ_CHANGED)
_parent_read_listeners_modify(pd, 1);
}
}
static void
_cb_event_callback_del(void *data, const Efl_Event *event)
{
Efl_App_Data *pd = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_IO_READER_EVENT_CAN_READ_CHANGED)
_parent_read_listeners_modify(pd, -1);
}
}
static void
_cb_out(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
efl_io_reader_can_read_set(obj, EINA_TRUE);
}
static void
_cb_in(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
efl_io_writer_can_write_set(obj, EINA_TRUE);
}
EFL_CALLBACKS_ARRAY_DEFINE(_event_callback_watch,
{ EFL_EVENT_CALLBACK_ADD, _cb_event_callback_add },
{ EFL_EVENT_CALLBACK_DEL, _cb_event_callback_del });
//////////////////////////////////////////////////////////////////////////
EOLIAN static Efl_Loop *
_efl_app_loop_main_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED)
{
if (_mainloop_singleton) return _mainloop_singleton;
_mainloop_singleton = efl_add(EFL_APP_CLASS, NULL);
_mainloop_singleton_data = efl_data_scope_get(_mainloop_singleton, EFL_LOOP_CLASS);
return _mainloop_singleton;
}
EOLIAN static const Efl_Version *
_efl_app_build_efl_version_get(Eo *obj EINA_UNUSED, Efl_App_Data *pd EINA_UNUSED)
{
return &_app_efl_version;
}
EOLIAN static const Efl_Version *
_efl_app_efl_version_get(Eo *obj EINA_UNUSED, Efl_App_Data *pd EINA_UNUSED)
{
/* vanilla EFL: flavor = NULL */
static const Efl_Version version = {
.major = VMAJ,
.minor = VMIN,
.micro = VMIC,
.revision = VREV,
.build_id = EFL_BUILD_ID,
.flavor = NULL
};
return &version;
}
EOLIAN static Efl_Object *
_efl_app_efl_object_constructor(Eo *obj, Efl_App_Data *pd)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
efl_event_callback_array_add(obj, _event_callback_watch(), pd);
pd->fd.in = 1;
pd->fd.out = 0;
pd->fd.can_write = EINA_TRUE;
pd->fd.in_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, pd->fd.in),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_WRITE, _cb_in, obj));
pd->fd.out_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, pd->fd.out),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_READ, _cb_out, obj));
return obj;
}
EOLIAN static void
_efl_app_efl_object_destructor(Eo *obj, Efl_App_Data *pd)
{
efl_del(pd->fd.in_handler);
efl_del(pd->fd.out_handler);
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
pd->fd.in = -1;
pd->fd.out = -1;
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Eina_Error
_efl_app_efl_io_closer_close(Eo *obj, Efl_App_Data *pd)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(obj), EBADF);
efl_io_writer_can_write_set(obj, EINA_FALSE);
efl_io_reader_can_read_set(obj, EINA_FALSE);
efl_io_reader_eos_set(obj, EINA_TRUE);
if (pd->fd.in_handler) efl_del(pd->fd.in_handler);
if (pd->fd.out_handler) efl_del(pd->fd.out_handler);
pd->fd.in = -1;
pd->fd.out = -1;
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
return 0;
}
EOLIAN static Eina_Bool
_efl_app_efl_io_closer_closed_get(Eo *obj EINA_UNUSED, Efl_App_Data *pd)
{
if ((pd->fd.in == -1) && (pd->fd.out == -1)) return EINA_TRUE;
return EINA_FALSE;
}
EOLIAN static Eina_Error
_efl_app_efl_io_reader_read(Eo *obj, Efl_App_Data *pd, Eina_Rw_Slice *rw_slice)
{
ssize_t r;
errno = 0;
if (pd->fd.out == -1) goto err;
do
{
errno = 0;
r = read(pd->fd.out, rw_slice->mem, rw_slice->len);
if (r == -1)
{
if (errno == EINTR) continue;
goto err;
}
}
while (r == -1);
rw_slice->len = r;
if (r == 0)
{
efl_io_reader_can_read_set(obj, EINA_FALSE);
efl_io_reader_eos_set(obj, EINA_TRUE);
close(pd->fd.out);
pd->fd.out = -1;
efl_del(pd->fd.out_handler);
pd->fd.out_handler = NULL;
return EPIPE;
}
return 0;
err:
if ((pd->fd.out != -1) && (errno != EAGAIN))
{
close(pd->fd.out);
pd->fd.out = -1;
efl_del(pd->fd.out_handler);
pd->fd.out_handler = NULL;
}
rw_slice->len = 0;
rw_slice->mem = NULL;
efl_io_reader_can_read_set(obj, EINA_FALSE);
return EINVAL;
}
EOLIAN static void
_efl_app_efl_io_reader_can_read_set(Eo *obj, Efl_App_Data *pd, Eina_Bool can_read)
{
Eina_Bool old = efl_io_reader_can_read_get(obj);
if (old == can_read) return;
pd->fd.can_read = can_read;
if (can_read)
efl_loop_handler_active_set(pd->fd.in_handler, 0);
else
efl_loop_handler_active_set(pd->fd.in_handler,
EFL_LOOP_HANDLER_FLAGS_READ);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_CAN_READ_CHANGED, NULL);
}
EOLIAN static Eina_Bool
_efl_app_efl_io_reader_can_read_get(Eo *obj EINA_UNUSED, Efl_App_Data *pd)
{
return pd->fd.can_read;
}
EOLIAN static void
_efl_app_efl_io_reader_eos_set(Eo *obj, Efl_App_Data *pd, Eina_Bool is_eos)
{
Eina_Bool old = efl_io_reader_eos_get(obj);
if (old == is_eos) return;
pd->fd.eos_read = is_eos;
if (!is_eos) return;
if (pd->fd.out_handler)
efl_loop_handler_active_set(pd->fd.out_handler, 0);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_EOS, NULL);
}
EOLIAN static Eina_Bool
_efl_app_efl_io_reader_eos_get(Eo *obj EINA_UNUSED, Efl_App_Data *pd)
{
return pd->fd.eos_read;
}
EOLIAN static Eina_Error
_efl_app_efl_io_writer_write(Eo *obj, Efl_App_Data *pd, Eina_Slice *slice, Eina_Slice *remaining)
{
ssize_t r;
errno = 0;
if (pd->fd.in == -1) goto err;
do
{
errno = 0;
r = write(pd->fd.in, slice->mem, slice->len);
if (r == -1)
{
if (errno == EINTR) continue;
goto err;
}
}
while (r == -1);
if (remaining)
{
remaining->len = slice->len - r;
remaining->bytes = slice->bytes + r;
}
slice->len = r;
if ((slice) && (slice->len > 0))
efl_io_writer_can_write_set(obj, EINA_FALSE);
if (r == 0)
{
close(pd->fd.in);
pd->fd.in = -1;
efl_del(pd->fd.in_handler);
pd->fd.in_handler = NULL;
return EPIPE;
}
return 0;
err:
if ((pd->fd.in != -1) && (errno != EAGAIN))
{
close(pd->fd.in);
pd->fd.in = -1;
efl_del(pd->fd.in_handler);
pd->fd.in_handler = NULL;
}
if (remaining) *remaining = *slice;
slice->len = 0;
slice->mem = NULL;
efl_io_writer_can_write_set(obj, EINA_FALSE);
return EINVAL;
}
EOLIAN static void
_efl_app_efl_io_writer_can_write_set(Eo *obj, Efl_App_Data *pd, Eina_Bool can_write)
{
Eina_Bool old = efl_io_writer_can_write_get(obj);
if (old == can_write) return;
pd->fd.can_write = can_write;
if (can_write)
efl_loop_handler_active_set(pd->fd.in_handler, 0);
else
efl_loop_handler_active_set(pd->fd.in_handler,
EFL_LOOP_HANDLER_FLAGS_WRITE);
efl_event_callback_call(obj, EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, NULL);
}
EOLIAN static Eina_Bool
_efl_app_efl_io_writer_can_write_get(Eo *obj EINA_UNUSED, Efl_App_Data *pd)
{
return pd->fd.can_write;
}
#ifdef _WIN32
#else
static const signed char primap[EFL_TASK_PRIORITY_ULTRA + 1] =
{
10, // EFL_TASK_PRIORITY_NORMAL
19, // EFL_TASK_PRIORITY_BACKGROUND
15, // EFL_TASK_PRIORITY_LOW
5, // EFL_TASK_PRIORITY_HIGH
0 // EFL_TASK_PRIORITY_ULTRA
};
#endif
EOLIAN static void
_efl_app_efl_task_priority_set(Eo *obj, Efl_App_Data *pd EINA_UNUSED, Efl_Task_Priority priority)
{
efl_task_priority_set(efl_super(obj, MY_CLASS), priority);
#ifdef _WIN32
#else
// -20 (high) -> 19 (low)
int p = 0;
if ((priority >= EFL_TASK_PRIORITY_NORMAL) &&
(priority <= EFL_TASK_PRIORITY_ULTRA))
p = primap[priority];
setpriority(PRIO_PROCESS, 0, p);
#endif
}
EOLIAN static Efl_Task_Priority
_efl_app_efl_task_priority_get(Eo *obj, Efl_App_Data *pd EINA_UNUSED)
{
Efl_Task_Priority pri = EFL_TASK_PRIORITY_NORMAL;
#ifdef _WIN32
#else
int p, i, dist = 0x7fffffff, d;
errno = 0;
p = getpriority(PRIO_PROCESS, 0);
if (errno != 0)
return efl_task_priority_get(efl_super(obj, MY_CLASS));
// find the closest matching priority in primap
for (i = EFL_TASK_PRIORITY_NORMAL; i <= EFL_TASK_PRIORITY_ULTRA; i++)
{
d = primap[i] - p;
if (d < 0) d = -d;
if (d < dist)
{
pri = i;
dist = d;
}
}
Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
if (td) td->priority = pri;
#endif
return pri;
}
//////////////////////////////////////////////////////////////////////////
#include "efl_app.eo.c"

57
src/lib/ecore/efl_app.eo Normal file
View File

@ -0,0 +1,57 @@
import efl_types;
import eina_types;
class Efl.App (Efl.Loop)
{
[[ ]]
methods {
@property loop_main @class {
[[ Points to the main loop instance of the application. ]]
get {}
values {
main_loop: Efl.Loop; [[Application main loop]]
}
}
@property build_efl_version {
[[ Indicates the version of EFL with which this application was
compiled against/for.
This might differ from @.efl_version.
]]
get {}
values {
@cref version: Efl.Version; [[Efl version]]
}
}
@property efl_version {
[[ Indicates the currently running version of EFL.
This might differ from @.build_efl_version.
]]
get {}
values {
@cref version: Efl.Version; [[Efl version]]
}
}
}
events {
pause; [[Called when the application is not going be displayed or otherwise used by a user for some time]]
resume; [[Called before a window is rendered after a pause event]]
terminate; [[Called before starting the shutdown of the application]]
signal,usr1; [[System specific, but on unix maps to SIGUSR1 signal to the process - only called on main loop object]]
signal,usr2; [[System specific, but on unix maps to SIGUSR2 signal to the process - only called on main loop object]]
signal,hup; [[System specific, but on unix maps to SIGHUP signal to the process - only called on main loop object]]
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Io.Closer.close;
Efl.Io.Closer.closed { get; }
Efl.Io.Reader.read;
Efl.Io.Reader.can_read { get; set; }
Efl.Io.Reader.eos { get; set; }
Efl.Io.Writer.write;
Efl.Io.Writer.can_write { get; set; }
Efl.Task.priority { get; set; }
}
}

View File

@ -0,0 +1,245 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#define EFL_IO_READER_PROTECTED 1
#define EFL_IO_WRITER_PROTECTED 1
#define EFL_IO_CLOSER_PROTECTED 1
#include <Ecore.h>
#include "ecore_private.h"
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define MY_CLASS EFL_APPTHREAD_CLASS
//////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
EOLIAN static Efl_Object *
_efl_appthread_efl_object_constructor(Eo *obj, Efl_Appthread_Data *pd)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
pd->fd.in = -1;
pd->fd.out = -1;
pd->fd.can_write = EINA_TRUE;
pd->ctrl.in = -1;
pd->ctrl.out = -1;
return obj;
}
EOLIAN static void
_efl_appthread_efl_object_destructor(Eo *obj, Efl_Appthread_Data *pd)
{
if (pd->fd.in >= 0)
{
efl_del(pd->fd.in_handler);
efl_del(pd->fd.out_handler);
efl_del(pd->ctrl.in_handler);
efl_del(pd->ctrl.out_handler);
close(pd->fd.in);
close(pd->fd.out);
close(pd->ctrl.in);
close(pd->ctrl.out);
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
pd->ctrl.in_handler = NULL;
pd->ctrl.out_handler = NULL;
pd->fd.in = -1;
pd->fd.out = -1;
pd->ctrl.in = -1;
pd->ctrl.out = -1;
}
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static Eina_Error
_efl_appthread_efl_io_closer_close(Eo *obj, Efl_Appthread_Data *pd)
{
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(obj), EBADF);
efl_io_writer_can_write_set(obj, EINA_FALSE);
efl_io_reader_can_read_set(obj, EINA_FALSE);
efl_io_reader_eos_set(obj, EINA_TRUE);
if (pd->fd.in >= 0) close(pd->fd.in);
if (pd->fd.out >= 0) close(pd->fd.out);
if (pd->fd.in_handler) efl_del(pd->fd.in_handler);
if (pd->fd.out_handler) efl_del(pd->fd.out_handler);
pd->fd.in = -1;
pd->fd.out = -1;
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
return 0;
}
EOLIAN static Eina_Bool
_efl_appthread_efl_io_closer_closed_get(Eo *obj EINA_UNUSED, Efl_Appthread_Data *pd)
{
if ((pd->fd.in == -1) && (pd->fd.out == -1)) return EINA_TRUE;
return EINA_FALSE;
}
EOLIAN static Eina_Error
_efl_appthread_efl_io_reader_read(Eo *obj, Efl_Appthread_Data *pd, Eina_Rw_Slice *rw_slice)
{
ssize_t r;
errno = 0;
if (pd->fd.out == -1) goto err;
do
{
errno = 0;
r = read(pd->fd.out, rw_slice->mem, rw_slice->len);
if (r == -1)
{
if (errno == EINTR) continue;
goto err;
}
}
while (r == -1);
rw_slice->len = r;
if (r == 0)
{
efl_io_reader_can_read_set(obj, EINA_FALSE);
efl_io_reader_eos_set(obj, EINA_TRUE);
close(pd->fd.out);
pd->fd.out = -1;
efl_del(pd->fd.out_handler);
pd->fd.out_handler = NULL;
return EPIPE;
}
return 0;
err:
if ((pd->fd.out != -1) && (errno != EAGAIN))
{
close(pd->fd.out);
pd->fd.out = -1;
efl_del(pd->fd.out_handler);
pd->fd.out_handler = NULL;
}
rw_slice->len = 0;
rw_slice->mem = NULL;
efl_io_reader_can_read_set(obj, EINA_FALSE);
return EINVAL;
}
EOLIAN static void
_efl_appthread_efl_io_reader_can_read_set(Eo *obj, Efl_Appthread_Data *pd, Eina_Bool can_read)
{
Eina_Bool old = efl_io_reader_can_read_get(obj);
if (old == can_read) return;
pd->fd.can_read = can_read;
if (can_read)
efl_loop_handler_active_set(pd->fd.in_handler, 0);
else
efl_loop_handler_active_set(pd->fd.in_handler,
EFL_LOOP_HANDLER_FLAGS_READ);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_CAN_READ_CHANGED, NULL);
}
EOLIAN static Eina_Bool
_efl_appthread_efl_io_reader_can_read_get(Eo *obj EINA_UNUSED, Efl_Appthread_Data *pd)
{
return pd->fd.can_read;
}
EOLIAN static void
_efl_appthread_efl_io_reader_eos_set(Eo *obj, Efl_Appthread_Data *pd, Eina_Bool is_eos)
{
Eina_Bool old = efl_io_reader_eos_get(obj);
if (old == is_eos) return;
pd->fd.eos_read = is_eos;
if (!is_eos) return;
if (pd->fd.out_handler)
efl_loop_handler_active_set(pd->fd.out_handler, 0);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_EOS, NULL);
}
EOLIAN static Eina_Bool
_efl_appthread_efl_io_reader_eos_get(Eo *obj EINA_UNUSED, Efl_Appthread_Data *pd)
{
return pd->fd.eos_read;
}
EOLIAN static Eina_Error
_efl_appthread_efl_io_writer_write(Eo *obj, Efl_Appthread_Data *pd, Eina_Slice *slice, Eina_Slice *remaining)
{
ssize_t r;
errno = 0;
if (pd->fd.in == -1) goto err;
do
{
errno = 0;
r = write(pd->fd.in, slice->mem, slice->len);
if (r == -1)
{
if (errno == EINTR) continue;
goto err;
}
}
while (r == -1);
if (remaining)
{
remaining->len = slice->len - r;
remaining->bytes = slice->bytes + r;
}
slice->len = r;
if ((slice) && (slice->len > 0))
efl_io_writer_can_write_set(obj, EINA_FALSE);
if (r == 0)
{
close(pd->fd.in);
pd->fd.in = -1;
efl_del(pd->fd.in_handler);
pd->fd.in_handler = NULL;
return EPIPE;
}
return 0;
err:
if ((pd->fd.in != -1) && (errno != EAGAIN))
{
close(pd->fd.in);
pd->fd.in = -1;
efl_del(pd->fd.in_handler);
pd->fd.in_handler = NULL;
}
if (remaining) *remaining = *slice;
slice->len = 0;
slice->mem = NULL;
efl_io_writer_can_write_set(obj, EINA_FALSE);
return EINVAL;
}
EOLIAN static void
_efl_appthread_efl_io_writer_can_write_set(Eo *obj, Efl_Appthread_Data *pd, Eina_Bool can_write)
{
Eina_Bool old = efl_io_writer_can_write_get(obj);
if (old == can_write) return;
pd->fd.can_write = can_write;
if (can_write)
efl_loop_handler_active_set(pd->fd.in_handler, 0);
else
efl_loop_handler_active_set(pd->fd.in_handler,
EFL_LOOP_HANDLER_FLAGS_WRITE);
efl_event_callback_call(obj, EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, NULL);
}
EOLIAN static Eina_Bool
_efl_appthread_efl_io_writer_can_write_get(Eo *obj EINA_UNUSED, Efl_Appthread_Data *pd)
{
return pd->fd.can_write;
}
//////////////////////////////////////////////////////////////////////////
#include "efl_appthread.eo.c"

View File

@ -0,0 +1,22 @@
import efl_types;
import eina_types;
class Efl.Appthread (Efl.Loop)
{
[[ ]]
methods {
}
events {
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Io.Closer.close;
Efl.Io.Closer.closed { get; }
Efl.Io.Reader.read;
Efl.Io.Reader.can_read { get; set; }
Efl.Io.Reader.eos { get; set; }
Efl.Io.Writer.write;
Efl.Io.Writer.can_write { get; set; }
}
}

View File

@ -179,15 +179,30 @@ _foreach_env(const Eina_Hash *hash EINA_UNUSED, const void *key, void *data, voi
return EINA_TRUE;
}
static Eina_Value
_efl_loop_task_exit(void *data, const Eina_Value v,
const Eina_Future *dead EINA_UNUSED)
{
Eo *obj = data;
efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
efl_unref(obj);
return v;
}
static void
_exe_exit_eval(Eo *obj, Efl_Exe_Data *pd)
{
// XXX: defer the below in a job
if ((pd->fd.out == -1) && (pd->fd.exited_read == -1) &&
(!pd->exit_called))
if ((pd->fd.out == -1) && /*(pd->fd.in == -1) &&*/
(pd->fd.exited_read == -1) && (!pd->exit_called))
{
Eina_Future *job;
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
pd->exit_called = EINA_TRUE;
efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
efl_ref(obj);
job = eina_future_then(efl_loop_job(loop), _efl_loop_task_exit, obj);
efl_future_Eina_FutureXXX_then(loop, job);
}
}
@ -666,10 +681,11 @@ _efl_exe_efl_io_reader_can_read_set(Eo *obj, Efl_Exe_Data *pd, Eina_Bool can_rea
Eina_Bool old = efl_io_reader_can_read_get(obj);
if (old == can_read) return;
pd->fd.can_read = can_read;
if (!pd->fd.out_handler) return;
if (can_read)
efl_loop_handler_active_set(pd->fd.in_handler, 0);
efl_loop_handler_active_set(pd->fd.out_handler, 0);
else
efl_loop_handler_active_set(pd->fd.in_handler,
efl_loop_handler_active_set(pd->fd.out_handler,
EFL_LOOP_HANDLER_FLAGS_READ);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_CAN_READ_CHANGED, NULL);
}

View File

@ -107,9 +107,9 @@
#define EFL_MAIN_EX() \
EFL_CALLBACKS_ARRAY_DEFINE(_efl_main_ex, \
{ EFL_LOOP_EVENT_ARGUMENTS, efl_main }, \
{ EFL_LOOP_EVENT_PAUSE, efl_pause }, \
{ EFL_LOOP_EVENT_RESUME, efl_resume }, \
{ EFL_LOOP_EVENT_TERMINATE, efl_terminate }); \
{ EFL_APP_EVENT_PAUSE, efl_pause }, \
{ EFL_APP_EVENT_RESUME, efl_resume }, \
{ EFL_APP_EVENT_TERMINATE, efl_terminate }); \
int main(int argc, char **argv) \
{ \
Eina_Value *ret__; \

View File

@ -8,9 +8,6 @@
#include <unistd.h>
#include <math.h>
#include <sys/time.h>
#ifndef _WIN32
# include <sys/resource.h>
#endif
#include <errno.h>
#include "Ecore.h"
@ -53,8 +50,6 @@ _efl_loop_message_handler_get(Eo *obj EINA_UNUSED, void *pd EINA_UNUSED, Efl_Loo
return mh.handler;
}
Efl_Version _app_efl_version = { 0, 0, 0, 0, NULL, NULL };
Eo *_mainloop_singleton = NULL;
Efl_Loop_Data *_mainloop_singleton_data = NULL;
@ -63,19 +58,10 @@ static Eina_List *_environ_strings_set = NULL;
static void _clean_old_environ(void);
EOLIAN static Efl_Loop *
_efl_loop_main_get(Efl_Class *klass EINA_UNUSED, void *_pd EINA_UNUSED)
{
if (_mainloop_singleton) return _mainloop_singleton;
_mainloop_singleton = efl_add(EFL_LOOP_CLASS, NULL);
_mainloop_singleton_data = efl_data_scope_get(_mainloop_singleton, EFL_LOOP_CLASS);
return _mainloop_singleton;
}
EAPI Eo *
efl_main_loop_get(void)
{
return efl_loop_main_get(EFL_LOOP_CLASS);
return efl_app_loop_main_get(EFL_APP_CLASS);
}
EOLIAN static void
@ -172,8 +158,8 @@ efl_loop_exit_code_process(Eina_Value *value)
Eina_Value v = EINA_VALUE_EMPTY;
eina_value_setup(&v, EINA_VALUE_TYPE_INT);
if (!eina_value_convert(&v, value)) r = -1;
else eina_value_get(&v, &v);
if (!eina_value_convert(value, &v)) r = -1;
else eina_value_get(&v, &r);
}
else
{
@ -203,7 +189,7 @@ _poll_trigger(void *data, const Efl_Event *event)
static void
_check_event_catcher_add(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Efl_Loop_Data *pd = data;
int i;
@ -272,7 +258,7 @@ _check_event_catcher_add(void *data, const Efl_Event *event)
static void
_check_event_catcher_del(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Efl_Loop_Data *pd = data;
int i;
@ -337,7 +323,7 @@ _efl_loop_efl_object_constructor(Eo *obj, Efl_Loop_Data *pd)
EOLIAN static void
_efl_loop_efl_object_destructor(Eo *obj, Efl_Loop_Data *pd)
{
_ecore_main_content_clear(pd);
_ecore_main_content_clear(obj, pd);
pd->future_message_handler = NULL;
@ -725,6 +711,7 @@ efl_build_version_set(int vmaj, int vmin, int vmic, int revision,
_app_efl_version.build_id = build_id ? strdup(build_id) : NULL;
}
/* HHH:
EOLIAN static const Efl_Version *
_efl_loop_app_efl_version_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
{
@ -734,7 +721,7 @@ _efl_loop_app_efl_version_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED
EOLIAN static const Efl_Version *
_efl_loop_efl_version_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
{
/* vanilla EFL: flavor = NULL */
// vanilla EFL: flavor = NULL
static const Efl_Version version = {
.major = VMAJ,
.minor = VMIN,
@ -745,6 +732,7 @@ _efl_loop_efl_version_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
};
return &version;
}
*/
static void
_env_sync(Efl_Loop_Data *pd, Efl_Task_Data *td)
@ -903,63 +891,23 @@ _efl_loop_efl_task_env_get(Eo *obj, Efl_Loop_Data *pd, const char *var)
eina_lock_release(&_environ_lock);
return efl_task_env_get(efl_super(obj, EFL_LOOP_CLASS), var);
}
#ifdef _WIN32
#else
static const signed char primap[EFL_TASK_PRIORITY_ULTRA + 1] =
{
10, // EFL_TASK_PRIORITY_NORMAL
19, // EFL_TASK_PRIORITY_BACKGROUND
15, // EFL_TASK_PRIORITY_LOW
5, // EFL_TASK_PRIORITY_HIGH
0 // EFL_TASK_PRIORITY_ULTRA
};
#endif
EOLIAN static void
_efl_loop_efl_task_priority_set(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED, Efl_Task_Priority priority)
EOLIAN static Eina_Bool
_efl_loop_efl_task_run(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
{
efl_task_priority_set(efl_super(obj, EFL_LOOP_CLASS), priority);
#ifdef _WIN32
#else
// -20 (high) -> 19 (low)
int p = 0;
Eina_Value *ret;
int real;
if ((priority >= EFL_TASK_PRIORITY_NORMAL) &&
(priority <= EFL_TASK_PRIORITY_ULTRA))
p = primap[priority];
setpriority(PRIO_PROCESS, 0, p);
#endif
ret = efl_loop_begin(obj);
real = efl_loop_exit_code_process(ret);
if (real == 0) return EINA_TRUE;
return EINA_FALSE;
}
EOLIAN static Efl_Task_Priority
_efl_loop_efl_task_priority_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
EOLIAN static void
_efl_loop_efl_task_end(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
{
Efl_Task_Priority pri = EFL_TASK_PRIORITY_NORMAL;
#ifdef _WIN32
#else
int p, i, dist = 0x7fffffff, d;
errno = 0;
p = getpriority(PRIO_PROCESS, 0);
if (errno != 0)
return efl_task_priority_get(efl_super(obj, EFL_LOOP_CLASS));
// find the closest matching priority in primap
for (i = EFL_TASK_PRIORITY_NORMAL; i <= EFL_TASK_PRIORITY_ULTRA; i++)
{
d = primap[i] - p;
if (d < 0) d = -d;
if (d < dist)
{
pri = i;
dist = d;
}
}
Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
if (td) td->priority = pri;
#endif
return pri;
efl_loop_quit(obj, eina_value_int_init(0));
}
EAPI Eina_Future_Scheduler *

View File

@ -20,33 +20,6 @@ class Efl.Loop (Efl.Task)
you can provide these if you need to.
]]
methods {
@property main @class {
[[Points to the main loop instance of the application.]]
get {}
values {
main_loop: Efl.Loop; [[Application main loop]]
}
}
@property app_efl_version {
[[Indicates the version of EFL with which this application was compiled.
This might differ from @.efl_version.
]]
get {}
values {
@cref version: Efl.Version; [[Efl version]]
}
}
@property efl_version {
[[Indicates the currently running version of EFL.
This might differ from @.app_efl_version.
]]
get {}
values {
@cref version: Efl.Version; [[Efl version]]
}
}
iterate {
[[Runs a single iteration of the main loop to process everything on the
queue.]]
@ -148,18 +121,13 @@ class Efl.Loop (Efl.Task)
poll,high; [[Event occurs multiple times per second. The exact tick is undefined and can be adjusted system wide.]]
poll,medium; [[Event occurs multiple times per minute. The exact tick is undefined and can be adjusted system wide.]]
poll,low; [[Event occurs multiple times every 15 minutes. The exact tick is undefined and can be adjusted system wide.]]
pause; [[Called when the window is not going be displayed for some time]]
resume; [[Called before a window is rendered after a pause event]]
terminate; [[Called before starting the shutdown of Elementary]]
signal,usr1; [[System specific, but on unix maps to SIGUSR1 signal to the process - only called on main loop object]]
signal,usr2; [[System specific, but on unix maps to SIGUSR2 signal to the process - only called on main loop object]]
signal,hup; [[System specific, but on unix maps to SIGHUP signal to the process - only called on main loop object]]
}
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Object.provider_find;
Efl.Task.env { set; get; }
Efl.Task.priority { get; set; }
Efl.Task.run;
Efl.Task.end;
}
}

View File

@ -111,7 +111,7 @@ _efl_loop_fd_fd_file_get(Eo *obj EINA_UNUSED, Efl_Loop_Fd_Data *pd)
static void
_check_fd_event_catcher_add(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Efl_Loop_Fd_Data *fd = data;
Eina_Bool need_reset = EINA_FALSE;
int i;
@ -142,7 +142,7 @@ _check_fd_event_catcher_add(void *data, const Efl_Event *event)
static void
_check_fd_event_catcher_del(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Efl_Loop_Fd_Data *fd = data;
Eina_Bool need_reset = EINA_FALSE;
int i;

View File

@ -132,7 +132,7 @@ _handler_reset(Eo *obj, Efl_Loop_Handler_Data *pd)
static Eina_Bool
_event_references_update(Efl_Loop_Handler_Data *pd, const Efl_Event *event, int increment)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
Eina_Bool need_reset = EINA_FALSE;

View File

@ -186,8 +186,8 @@ _escape(const char *s)
{
*d = '\"';
d++;
*d = 0;
}
*d = 0;
return s2;
}
@ -215,7 +215,7 @@ _rebuild_command(Efl_Task_Data *pd)
char *str = _escape(arg);
if (str)
{
if (!have_args) eina_strbuf_append(sb, " ");
if (have_args) eina_strbuf_append(sb, " ");
eina_strbuf_append(sb, str);
free(str);
have_args = EINA_TRUE;
@ -272,14 +272,17 @@ _efl_task_arg_value_set(Eo *obj EINA_UNUSED, Efl_Task_Data *pd, unsigned int num
if (!pd->args) pd->args = eina_array_new(16);
count = eina_array_count(pd->args);
if (count > num)
if ((count > 0) && (count > num))
parg = eina_array_data_get(pd->args, num);
else
{
unsigned int i;
for (i = count; i <= num; i++)
eina_array_push(pd->args, NULL);
{
eina_array_push(pd->args, "");
eina_array_data_set(pd->args, i, NULL);
}
}
if (arg)

917
src/lib/ecore/efl_thread.c Normal file
View File

@ -0,0 +1,917 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#define EFL_IO_READER_PROTECTED 1
#define EFL_IO_WRITER_PROTECTED 1
#define EFL_IO_CLOSER_PROTECTED 1
#include <Ecore.h>
#include "ecore_private.h"
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#define MY_CLASS EFL_THREAD_CLASS
typedef struct
{
const char *name;
struct {
int in, out;
Eo *in_handler, *out_handler;
} fd, ctrl;
struct {
unsigned int argc;
const char **argv;
} args;
Efl_Callback_Array_Item_Full *event_cb;
} Thread_Data;
#define CMD_EXIT 1
#define CMD_EXITED 2
typedef struct
{
int command;
int data;
} Control_Data;
typedef struct _Efl_Thread_Data Efl_Thread_Data;
struct _Efl_Thread_Data
{
struct {
int in, out;
Eo *in_handler, *out_handler;
Eina_Bool can_read : 1;
Eina_Bool eos_read : 1;
Eina_Bool can_write : 1;
} fd, ctrl;
int read_listeners;
Eo *loop;
Thread_Data *thdat;
Efl_Callback_Array_Item_Full *event_cb;
Eina_Thread thread;
Eina_Bool end_sent : 1;
Eina_Bool exit_read : 1;
Eina_Bool exit_called : 1;
};
//////////////////////////////////////////////////////////////////////////
static void
_cb_thread_out(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
efl_io_reader_can_read_set(obj, EINA_TRUE);
}
static void
_cb_thread_in(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
efl_io_writer_can_write_set(obj, EINA_TRUE);
}
static void
_cb_thread_ctrl_out(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
Control_Data cmd;
ssize_t ret;
Efl_Appthread_Data *ad;
ad = efl_data_scope_get(obj, EFL_APPTHREAD_CLASS);
cmd.command = 0;
cmd.data = 0;
ret = read(ad->ctrl.out, &cmd, sizeof(Control_Data));
if (ret == sizeof(Control_Data))
{
if (cmd.command == CMD_EXIT)
{
efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
efl_loop_quit(obj, eina_value_int_init(0));
}
}
}
static Eina_Value
_efl_loop_arguments_send(void *data, const Eina_Value v,
const Eina_Future *dead EINA_UNUSED)
{
Efl_Loop_Arguments arge;
Eo *obj = data;
Eina_Array *arga;
Eina_Stringshare *s;
unsigned int argc = efl_task_arg_count_get(obj);
unsigned int i;
arga = eina_array_new(argc);
if (v.type == EINA_VALUE_TYPE_ERROR) goto on_error;
for (i = 0; i < argc; i++)
{
const char *argv = efl_task_arg_value_get(obj, i);
if (argv)
eina_array_push(arga, eina_stringshare_add(argv));
}
arge.argv = arga;
arge.initialization = EINA_TRUE;
efl_event_callback_call(obj,
EFL_LOOP_EVENT_ARGUMENTS, &arge);
on_error:
while ((s = eina_array_pop(arga))) eina_stringshare_del(s);
eina_array_free(arga);
return v;
}
static void
_appthread_parent_read_listeners_modify(Efl_Appthread_Data *ad, int mod)
{
ad->read_listeners += mod;
if (ad->fd.out_handler)
{
if ((ad->read_listeners == 0) && (mod < 0))
efl_loop_handler_active_set
(ad->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_NONE);
else if ((ad->read_listeners == 1) && (mod > 0))
efl_loop_handler_active_set
(ad->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_READ);
}
}
static void
_cb_appthread_event_callback_add(void *data, const Efl_Event *event)
{
Efl_Appthread_Data *ad = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_IO_READER_EVENT_CAN_READ_CHANGED)
_appthread_parent_read_listeners_modify(ad, 1);
}
}
static void
_cb_appthread_event_callback_del(void *data, const Efl_Event *event)
{
Efl_Appthread_Data *ad = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_IO_READER_EVENT_CAN_READ_CHANGED)
_appthread_parent_read_listeners_modify(ad, -1);
}
}
EFL_CALLBACKS_ARRAY_DEFINE(_appthread_event_callback_watch,
{ EFL_EVENT_CALLBACK_ADD, _cb_appthread_event_callback_add },
{ EFL_EVENT_CALLBACK_DEL, _cb_appthread_event_callback_del });
static void *
_efl_thread_main(void *data, Eina_Thread t)
{
Efl_Appthread_Data *ad;
Thread_Data *thdat = data;
Eo *obj;
Eina_Value *ret;
Control_Data cmd;
unsigned int i;
int real;
Efl_Callback_Array_Item_Full *it;
Eina_Future *job;
if (thdat->name) eina_thread_name_set(t, thdat->name);
else eina_thread_name_set(t, "Eflthread");
obj = efl_add(EFL_APPTHREAD_CLASS, NULL);
ad = efl_data_scope_get(obj, EFL_APPTHREAD_CLASS);
efl_event_callback_array_add(obj, _appthread_event_callback_watch(), ad);
// add handlers for "stdio"
thdat->fd.in_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, thdat->fd.in),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_WRITE, _cb_thread_in, obj));
thdat->fd.out_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, thdat->fd.out),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_READ, _cb_thread_out, obj));
// add handlers for control pipes
thdat->ctrl.in_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, thdat->ctrl.in));
thdat->ctrl.out_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, thdat->ctrl.out),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_READ, _cb_thread_ctrl_out, obj),
efl_loop_handler_active_set
(efl_added, EFL_LOOP_HANDLER_FLAGS_READ));
ad->fd.in = thdat->fd.in;
ad->fd.out = thdat->fd.out;
ad->ctrl.in = thdat->ctrl.in;
ad->ctrl.out = thdat->ctrl.out;
ad->fd.in_handler = thdat->fd.in_handler;
ad->fd.out_handler = thdat->fd.out_handler;
ad->ctrl.in_handler = thdat->ctrl.in_handler;
ad->ctrl.out_handler = thdat->ctrl.out_handler;
if (thdat->event_cb)
{
for (it = thdat->event_cb; it->func; it++)
efl_event_callback_priority_add(obj, it->desc, it->priority,
it->func, it->user_data);
}
for (i = 0; i < thdat->args.argc; i++)
efl_task_arg_append(obj, thdat->args.argv[i]);
job = eina_future_then(efl_loop_job(obj), _efl_loop_arguments_send, obj);
efl_future_Eina_FutureXXX_then(obj, job);
for (i = 0; i < thdat->args.argc; i++)
eina_stringshare_del(thdat->args.argv[i]);
free(thdat->args.argv);
free(thdat->event_cb);
thdat->args.argv = NULL;
thdat->event_cb = NULL;
ret = efl_loop_begin(obj);
real = efl_loop_exit_code_process(ret);
cmd.command = CMD_EXITED;
cmd.data = real;
write(thdat->ctrl.in, &cmd, sizeof(Control_Data));
efl_del(obj);
thdat->fd.in_handler = NULL;
thdat->fd.out_handler = NULL;
thdat->ctrl.in_handler = NULL;
thdat->ctrl.out_handler = NULL;
thdat->fd.in = -1;
thdat->fd.out = -1;
thdat->ctrl.in = -1;
thdat->ctrl.out = -1;
return NULL;
}
//////////////////////////////////////////////////////////////////////////
static Eina_Value
_efl_loop_task_exit(void *data, const Eina_Value v,
const Eina_Future *dead EINA_UNUSED)
{
Eo *obj = data;
efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
efl_unref(obj);
return v;
}
static void
_thread_exit_eval(Eo *obj, Efl_Thread_Data *pd)
{
if ((pd->fd.out == -1) && /*(pd->fd.in == -1) &&*/
(pd->exit_read) && (!pd->exit_called))
{
Eina_Future *job;
Eo *loop = efl_provider_find(obj, EFL_LOOP_CLASS);
pd->exit_called = EINA_TRUE;
efl_ref(obj);
job = eina_future_then(efl_loop_job(loop), _efl_loop_task_exit, obj);
efl_future_Eina_FutureXXX_then(loop, job);
}
}
static void
_cb_thread_parent_out(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
efl_io_reader_can_read_set(obj, EINA_TRUE);
}
static void
_cb_thread_parent_in(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
efl_io_writer_can_write_set(obj, EINA_TRUE);
}
static void
_cb_thread_parent_ctrl_out(void *data, const Efl_Event *event EINA_UNUSED)
{
Eo *obj = data;
Control_Data cmd;
ssize_t ret;
Efl_Thread_Data *pd = efl_data_scope_get(obj, MY_CLASS);
if (!pd) return;
cmd.command = 0;
cmd.data = 0;
ret = read(pd->ctrl.out, &cmd, sizeof(Control_Data));
if (ret == sizeof(Control_Data))
{
if (cmd.command == CMD_EXITED)
{
if (!pd->exit_read)
{
Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
if (td) td->exit_code = cmd.data;
pd->exit_read = EINA_TRUE;
_thread_exit_eval(obj, pd);
}
}
}
}
//////////////////////////////////////////////////////////////////////////
static void
_thread_parent_read_listeners_modify(Efl_Thread_Data *pd, int mod)
{
pd->read_listeners += mod;
if (pd->fd.out_handler)
{
if ((pd->read_listeners == 0) && (mod < 0))
efl_loop_handler_active_set
(pd->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_NONE);
else if ((pd->read_listeners == 1) && (mod > 0))
efl_loop_handler_active_set
(pd->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_READ);
}
}
static void
_cb_event_callback_add(void *data, const Efl_Event *event)
{
Efl_Thread_Data *pd = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_LOOP_EVENT_ARGUMENTS)
{
Efl_Callback_Array_Item_Full *event_cb, *it;
int num;
num = 0;
if (pd->event_cb)
{
for (it = pd->event_cb; it->func; it++) num++;
}
num++;
event_cb = realloc(pd->event_cb, (num + 1) * sizeof(Efl_Callback_Array_Item_Full));
if (event_cb)
{
pd->event_cb = event_cb;
event_cb[num - 1] = array[i];
event_cb[num].desc = NULL;
event_cb[num].priority = 0;
event_cb[num].func = NULL;
event_cb[num].user_data = NULL;
}
}
else if (array[i].desc == EFL_IO_READER_EVENT_CAN_READ_CHANGED)
_thread_parent_read_listeners_modify(pd, 1);
}
}
static void
_cb_event_callback_del(void *data, const Efl_Event *event)
{
Efl_Thread_Data *pd = data;
const Efl_Callback_Array_Item_Full *array = event->info;
int i;
for (i = 0; array[i].desc != NULL; i++)
{
if (array[i].desc == EFL_LOOP_EVENT_ARGUMENTS)
{
Efl_Callback_Array_Item_Full *it;
if (pd->event_cb)
{
Eina_Bool shuffle_down = EINA_FALSE;
for (it = pd->event_cb; it->func; it++)
{
if ((it->desc == array[i].desc) &&
(it->priority == array[i].priority) &&
(it->func == array[i].func) &&
(it->user_data == array[i].user_data))
shuffle_down = EINA_TRUE;
if (shuffle_down) it[0] = it[1];
}
}
}
else if (array[i].desc == EFL_IO_READER_EVENT_CAN_READ_CHANGED)
_thread_parent_read_listeners_modify(pd, -1);
}
}
EFL_CALLBACKS_ARRAY_DEFINE(_event_callback_watch,
{ EFL_EVENT_CALLBACK_ADD, _cb_event_callback_add },
{ EFL_EVENT_CALLBACK_DEL, _cb_event_callback_del });
//////////////////////////////////////////////////////////////////////////
EOLIAN static Efl_Object *
_efl_thread_efl_object_constructor(Eo *obj, Efl_Thread_Data *pd)
{
obj = efl_constructor(efl_super(obj, MY_CLASS));
efl_event_callback_array_add(obj, _event_callback_watch(), pd);
pd->fd.in = -1;
pd->fd.out = -1;
pd->fd.can_write = EINA_TRUE;
pd->ctrl.in = -1;
pd->ctrl.out = -1;
return obj;
}
EOLIAN static void
_efl_thread_efl_object_destructor(Eo *obj, Efl_Thread_Data *pd)
{
if (pd->thdat)
{
/* we probably shouldn't do this... this simply has to orphan threads if they
* lose their parent. this stops shutdown from blocking.
// if exit response not read yet, read until fetched
if (!pd->exit_read)
{
Control_Data cmd;
ssize_t ret;
// if it hasn't been asked to exit... ask it
if (!pd->end_sent) efl_task_end(obj);
cmd.command = 0;
cmd.data = 0;
ret = read(pd->ctrl.out, &cmd, sizeof(Control_Data));
while (ret == sizeof(Control_Data))
{
if (cmd.command == CMD_EXITED)
{
if (!pd->exit_read)
{
Efl_Task_Data *td = efl_data_scope_get(obj, EFL_TASK_CLASS);
if (td) td->exit_code = cmd.data;
pd->exit_read = EINA_TRUE;
efl_event_callback_call(obj, EFL_TASK_EVENT_EXIT, NULL);
break;
}
}
ret = read(pd->ctrl.out, &cmd, sizeof(Control_Data));
}
}
*/
// stop and wait for thread to exit/join here
eina_thread_join(pd->thread);
efl_del(pd->fd.in_handler);
efl_del(pd->fd.out_handler);
efl_del(pd->ctrl.in_handler);
efl_del(pd->ctrl.out_handler);
close(pd->fd.in);
close(pd->fd.out);
close(pd->ctrl.in);
close(pd->ctrl.out);
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
pd->ctrl.in_handler = NULL;
pd->ctrl.out_handler = NULL;
pd->fd.in = -1;
pd->fd.out = -1;
pd->ctrl.in = -1;
pd->ctrl.out = -1;
free(pd->thdat);
}
free(pd->event_cb);
pd->event_cb = NULL;
efl_destructor(efl_super(obj, MY_CLASS));
}
EOLIAN static void
_efl_thread_efl_object_parent_set(Eo *obj, Efl_Thread_Data *pd, Efl_Object *parent)
{
efl_parent_set(efl_super(obj, MY_CLASS), parent);
pd->loop = efl_provider_find(parent, EFL_LOOP_CLASS);
}
EOLIAN static Eina_Bool
_efl_thread_efl_task_run(Eo *obj, Efl_Thread_Data *pd)
{
Eina_Thread_Priority pri;
Thread_Data *thdat;
const char *name;
int pipe_to_thread[2];
int pipe_from_thread[2];
unsigned int argc, i, num;
Efl_Callback_Array_Item_Full *it;
thdat = calloc(1, sizeof(Thread_Data));
if (!thdat) return EINA_FALSE;
thdat->fd.in = -1;
thdat->fd.out = -1;
thdat->ctrl.in = -1;
thdat->ctrl.out = -1;
if (pipe(pipe_to_thread) != 0)
{
ERR("Can't create to_thread pipe");
free(thdat);
return EINA_FALSE;
}
if (pipe(pipe_from_thread) != 0)
{
ERR("Can't create from_thread pipe");
close(pipe_to_thread[0]);
close(pipe_to_thread[1]);
free(thdat);
return EINA_FALSE;
}
thdat->fd.in = pipe_from_thread[1]; // write - input to parent
thdat->fd.out = pipe_to_thread [0]; // read - output from parent
pd->fd.in = pipe_to_thread [1]; // write - input to child
pd->fd.out = pipe_from_thread[0]; // read - output from child
eina_file_close_on_exec(pd->fd.in, EINA_TRUE);
eina_file_close_on_exec(pd->fd.out, EINA_TRUE);
eina_file_close_on_exec(thdat->fd.in, EINA_TRUE);
eina_file_close_on_exec(thdat->fd.out, EINA_TRUE);
fcntl(pd->fd.in, F_SETFL, O_NONBLOCK);
fcntl(pd->fd.out, F_SETFL, O_NONBLOCK);
fcntl(thdat->fd.in, F_SETFL, O_NONBLOCK);
fcntl(thdat->fd.out, F_SETFL, O_NONBLOCK);
pd->fd.in_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, pd->fd.in),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_WRITE, _cb_thread_parent_in, obj));
pd->fd.out_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, pd->fd.out),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_READ, _cb_thread_parent_out, obj));
if (pd->read_listeners > 0)
efl_loop_handler_active_set(pd->fd.out_handler, EFL_LOOP_HANDLER_FLAGS_READ);
if (pipe(pipe_to_thread) != 0)
{
ERR("Can't create to_thread control pipe");
efl_del(pd->fd.in_handler);
efl_del(pd->fd.out_handler);
close(thdat->fd.in);
close(thdat->fd.out);
close(pd->fd.in);
close(pd->fd.out);
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
pd->fd.in = -1;
pd->fd.out = -1;
free(thdat);
return EINA_FALSE;
}
if (pipe(pipe_from_thread) != 0)
{
ERR("Can't create from_thread control pipe");
efl_del(pd->fd.in_handler);
efl_del(pd->fd.out_handler);
close(pipe_to_thread[0]);
close(pipe_to_thread[1]);
close(thdat->fd.in);
close(thdat->fd.out);
close(pd->fd.in);
close(pd->fd.out);
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
pd->fd.in = -1;
pd->fd.out = -1;
free(thdat);
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->ctrl.in = pipe_to_thread [1]; // write - input to child
pd->ctrl.out = pipe_from_thread[0]; // read - output from child
// yes - these are blocking because we write and read very little
eina_file_close_on_exec(pd->ctrl.in, EINA_TRUE);
eina_file_close_on_exec(pd->ctrl.out, EINA_TRUE);
eina_file_close_on_exec(thdat->ctrl.in, EINA_TRUE);
eina_file_close_on_exec(thdat->ctrl.out, EINA_TRUE);
pd->ctrl.in_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, pd->ctrl.in));
pd->ctrl.out_handler =
efl_add(EFL_LOOP_HANDLER_CLASS, obj,
efl_loop_handler_fd_set(efl_added, pd->ctrl.out),
efl_event_callback_add
(efl_added, EFL_LOOP_HANDLER_EVENT_READ, _cb_thread_parent_ctrl_out, obj),
efl_loop_handler_active_set
(efl_added, EFL_LOOP_HANDLER_FLAGS_READ));
switch (efl_task_priority_get(obj))
{
case EFL_TASK_PRIORITY_BACKGROUND:
pri = EINA_THREAD_IDLE;
break;
case EFL_TASK_PRIORITY_HIGH:
case EFL_TASK_PRIORITY_ULTRA:
pri = EINA_THREAD_URGENT;
break;
case EFL_TASK_PRIORITY_LOW:
pri = EINA_THREAD_BACKGROUND;
break;
case EFL_TASK_PRIORITY_NORMAL:
default:
pri = EINA_THREAD_NORMAL;
break;
}
name = efl_name_get(obj);
if (name) thdat->name = eina_stringshare_add(name);
argc = efl_task_arg_count_get(obj);
if (argc > 0)
{
thdat->args.argc = argc;
thdat->args.argv = malloc(argc * sizeof(char *));
if (thdat->args.argv)
{
for (i = 0; i < argc; i++)
{
const char *argv = efl_task_arg_value_get(obj, i);
if (argv)
thdat->args.argv[i] = eina_stringshare_add(argv);
else
thdat->args.argv[i] = NULL;
}
}
// XXX: if malloc fails?
}
if (pd->event_cb)
{
num = 0;
for (it = pd->event_cb; it->func; it++) num++;
thdat->event_cb = malloc((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
if (thdat->event_cb)
memcpy(thdat->event_cb, pd->event_cb,
(num + 1) * sizeof(Efl_Callback_Array_Item_Full));
// XXX: if malloc fails?
}
// env data - ignore as other end will share same env
if (!eina_thread_create(&(pd->thread), pri, -1, _efl_thread_main, thdat))
{
for (i = 0; i < thdat->args.argc; i++)
eina_stringshare_del(thdat->args.argv[i]);
free(thdat->args.argv);
efl_del(pd->fd.in_handler);
efl_del(pd->fd.out_handler);
efl_del(pd->ctrl.in_handler);
efl_del(pd->ctrl.out_handler);
close(pd->fd.in);
close(pd->fd.out);
close(pd->ctrl.in);
close(pd->ctrl.out);
close(thdat->fd.in);
close(thdat->fd.out);
close(thdat->ctrl.in);
close(thdat->ctrl.out);
free(thdat);
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
pd->ctrl.in_handler = NULL;
pd->ctrl.out_handler = NULL;
pd->fd.in = -1;
pd->fd.out = -1;
pd->ctrl.in = -1;
pd->ctrl.out = -1;
return EINA_FALSE;
}
pd->thdat = thdat;
return EINA_TRUE;
}
EOLIAN static void
_efl_thread_efl_task_end(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd)
{
if (pd->end_sent) return;
if (pd->thdat)
{
Control_Data cmd;
pd->end_sent = EINA_TRUE;
cmd.command = CMD_EXIT;
cmd.data = 0;
write(pd->ctrl.in, &cmd, sizeof(Control_Data));
}
}
EOLIAN static Eina_Error
_efl_thread_efl_io_closer_close(Eo *obj, Efl_Thread_Data *pd)
{
if (!pd->thdat) return 0;
EINA_SAFETY_ON_TRUE_RETURN_VAL(efl_io_closer_closed_get(obj), EBADF);
efl_io_writer_can_write_set(obj, EINA_FALSE);
efl_io_reader_can_read_set(obj, EINA_FALSE);
efl_io_reader_eos_set(obj, EINA_TRUE);
if (pd->fd.in >= 0) close(pd->fd.in);
if (pd->fd.out >= 0) close(pd->fd.out);
if (pd->fd.in_handler) efl_del(pd->fd.in_handler);
if (pd->fd.out_handler) efl_del(pd->fd.out_handler);
pd->fd.in = -1;
pd->fd.out = -1;
pd->fd.in_handler = NULL;
pd->fd.out_handler = NULL;
return 0;
}
EOLIAN static Eina_Bool
_efl_thread_efl_io_closer_closed_get(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd)
{
if ((pd->fd.in == -1) && (pd->fd.out == -1)) return EINA_TRUE;
return EINA_FALSE;
}
EOLIAN static Eina_Error
_efl_thread_efl_io_reader_read(Eo *obj, Efl_Thread_Data *pd, Eina_Rw_Slice *rw_slice)
{
ssize_t r;
errno = 0;
if (pd->fd.out == -1) goto err;
do
{
errno = 0;
r = read(pd->fd.out, rw_slice->mem, rw_slice->len);
if (r == -1)
{
if (errno == EINTR) continue;
goto err;
}
}
while (r == -1);
rw_slice->len = r;
if (r == 0)
{
efl_io_reader_can_read_set(obj, EINA_FALSE);
efl_io_reader_eos_set(obj, EINA_TRUE);
close(pd->fd.out);
pd->fd.out = -1;
efl_del(pd->fd.out_handler);
pd->fd.out_handler = NULL;
_thread_exit_eval(obj, pd);
return EPIPE;
}
return 0;
err:
if ((pd->fd.out != -1) && (errno != EAGAIN))
{
close(pd->fd.out);
pd->fd.out = -1;
efl_del(pd->fd.out_handler);
pd->fd.out_handler = NULL;
}
rw_slice->len = 0;
rw_slice->mem = NULL;
efl_io_reader_can_read_set(obj, EINA_FALSE);
_thread_exit_eval(obj, pd);
return EINVAL;
}
EOLIAN static void
_efl_thread_efl_io_reader_can_read_set(Eo *obj, Efl_Thread_Data *pd, Eina_Bool can_read)
{
Eina_Bool old = efl_io_reader_can_read_get(obj);
if (old == can_read) return;
pd->fd.can_read = can_read;
if (!pd->fd.out_handler) return;
if (can_read)
efl_loop_handler_active_set(pd->fd.out_handler, 0);
else
efl_loop_handler_active_set(pd->fd.out_handler,
EFL_LOOP_HANDLER_FLAGS_READ);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_CAN_READ_CHANGED, NULL);
}
EOLIAN static Eina_Bool
_efl_thread_efl_io_reader_can_read_get(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd)
{
return pd->fd.can_read;
}
EOLIAN static void
_efl_thread_efl_io_reader_eos_set(Eo *obj, Efl_Thread_Data *pd, Eina_Bool is_eos)
{
Eina_Bool old = efl_io_reader_eos_get(obj);
if (old == is_eos) return;
pd->fd.eos_read = is_eos;
if (!is_eos) return;
if (pd->fd.out_handler)
efl_loop_handler_active_set(pd->fd.out_handler, 0);
efl_event_callback_call(obj, EFL_IO_READER_EVENT_EOS, NULL);
}
EOLIAN static Eina_Bool
_efl_thread_efl_io_reader_eos_get(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd)
{
return pd->fd.eos_read;
}
EOLIAN static Eina_Error
_efl_thread_efl_io_writer_write(Eo *obj, Efl_Thread_Data *pd, Eina_Slice *slice, Eina_Slice *remaining)
{
ssize_t r;
errno = 0;
if (pd->fd.in == -1) goto err;
do
{
errno = 0;
r = write(pd->fd.in, slice->mem, slice->len);
if (r == -1)
{
if (errno == EINTR) continue;
goto err;
}
}
while (r == -1);
if (remaining)
{
remaining->len = slice->len - r;
remaining->bytes = slice->bytes + r;
}
slice->len = r;
if ((slice) && (slice->len > 0))
efl_io_writer_can_write_set(obj, EINA_FALSE);
if (r == 0)
{
close(pd->fd.in);
pd->fd.in = -1;
efl_del(pd->fd.in_handler);
pd->fd.in_handler = NULL;
_thread_exit_eval(obj, pd);
return EPIPE;
}
return 0;
err:
if ((pd->fd.in != -1) && (errno != EAGAIN))
{
close(pd->fd.in);
pd->fd.in = -1;
efl_del(pd->fd.in_handler);
pd->fd.in_handler = NULL;
}
if (remaining) *remaining = *slice;
slice->len = 0;
slice->mem = NULL;
efl_io_writer_can_write_set(obj, EINA_FALSE);
_thread_exit_eval(obj, pd);
return EINVAL;
}
EOLIAN static void
_efl_thread_efl_io_writer_can_write_set(Eo *obj, Efl_Thread_Data *pd, Eina_Bool can_write)
{
Eina_Bool old = efl_io_writer_can_write_get(obj);
if (old == can_write) return;
pd->fd.can_write = can_write;
if (can_write)
efl_loop_handler_active_set(pd->fd.in_handler, 0);
else
efl_loop_handler_active_set(pd->fd.in_handler,
EFL_LOOP_HANDLER_FLAGS_WRITE);
efl_event_callback_call(obj, EFL_IO_WRITER_EVENT_CAN_WRITE_CHANGED, NULL);
}
EOLIAN static Eina_Bool
_efl_thread_efl_io_writer_can_write_get(Eo *obj EINA_UNUSED, Efl_Thread_Data *pd)
{
return pd->fd.can_write;
}
//////////////////////////////////////////////////////////////////////////
#include "efl_thread.eo.c"

View File

@ -8,5 +8,15 @@ class Efl.Thread (Efl.Task)
implements {
Efl.Object.constructor;
Efl.Object.destructor;
Efl.Object.parent { set; }
Efl.Task.run;
Efl.Task.end;
Efl.Io.Closer.close;
Efl.Io.Closer.closed { get; }
Efl.Io.Reader.read;
Efl.Io.Reader.can_read { get; set; }
Efl.Io.Reader.eos { get; set; }
Efl.Io.Writer.write;
Efl.Io.Writer.can_write { get; set; }
}
}

View File

@ -3195,7 +3195,7 @@ _ecore_evas_animator_fallback(void *data)
static void
_check_animator_event_catcher_add(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Ecore_Evas *ee = data;
int i;
@ -3229,7 +3229,7 @@ _check_animator_event_catcher_add(void *data, const Efl_Event *event)
static void
_check_animator_event_catcher_del(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Ecore_Evas *ee = data;
int i;

View File

@ -71,6 +71,8 @@ struct _Eina_Vpath_Interface_User
*/
EAPI void __eina_promise_cancel_all(void);
EAPI void __eina_promise_cancel_data(void *data);
/**
* Make the app specific paths accessable as virtual path
*

View File

@ -566,6 +566,27 @@ __eina_promise_cancel_all(void)
eina_lock_release(&_pending_futures_lock);
}
EAPI void
__eina_promise_cancel_data(void *data)
{
Eina_List *del = NULL, *l;
Eina_Future *f;
eina_lock_take(&_pending_futures_lock);
EINA_LIST_FOREACH(_pending_futures, l, f)
{
if (f->data == data)
{
del = eina_list_append(del, f);
}
}
EINA_LIST_FREE(del, f)
{
_eina_future_cancel(f, ECANCELED);
}
eina_lock_release(&_pending_futures_lock);
}
Eina_Bool
eina_promise_shutdown(void)
{

View File

@ -2975,9 +2975,10 @@ _efl_ui_text_efl_canvas_group_group_member_add(Eo *obj, Efl_Ui_Text_Data *sd, Ev
static void
_cb_added(void *data EINA_UNUSED, const Efl_Event *ev)
{
const Efl_Callback_Array_Item *event = ev->info;
const Efl_Callback_Array_Item_Full *event = ev->info;
EFL_UI_TEXT_DATA_GET(ev->object, sd);
// XXX: BUG - not walking the array until a NULL entry
if (event->desc == EFL_UI_TEXT_EVENT_VALIDATE)
sd->validators++;
}
@ -2985,9 +2986,10 @@ _cb_added(void *data EINA_UNUSED, const Efl_Event *ev)
static void
_cb_deleted(void *data EINA_UNUSED, const Efl_Event *ev)
{
const Efl_Callback_Array_Item *event = ev->info;
const Efl_Callback_Array_Item_Full *event = ev->info;
EFL_UI_TEXT_DATA_GET(ev->object, sd);
// XXX: BUG - not walking the array until a NULL entry
if (event->desc == EFL_UI_TEXT_EVENT_VALIDATE)
sd->validators--;
return;

View File

@ -1904,7 +1904,7 @@ _elm_win_evas_device_changed(void *data,
static void
_win_event_add_cb(void *data, const Efl_Event *ev)
{
const Efl_Callback_Array_Item *array = ev->info;
const Efl_Callback_Array_Item_Full *array = ev->info;
Efl_Ui_Win_Data *sd = data;
Efl_Ui_Win *win = ev->object;
int i;
@ -2035,7 +2035,7 @@ _win_event_add_cb(void *data, const Efl_Event *ev)
static void
_win_event_del_cb(void *data, const Efl_Event *ev)
{
const Efl_Callback_Array_Item *array = ev->info;
const Efl_Callback_Array_Item_Full *array = ev->info;
Efl_Ui_Win_Data *sd = data;
Efl_Ui_Win *win = ev->object;
int i;
@ -2177,7 +2177,7 @@ _win_paused(void *data, const Efl_Event *ev)
_paused_windows++;
if (_elm_win_count == _paused_windows)
efl_event_callback_call(efl_loop_get(ev->object), EFL_LOOP_EVENT_PAUSE, NULL);
efl_event_callback_call(efl_loop_get(ev->object), EFL_APP_EVENT_PAUSE, NULL);
}
EFL_CALLBACKS_ARRAY_DEFINE(_elm_win_tracking,
@ -2205,7 +2205,7 @@ _elm_win_resume(void *data, const Efl_Event *ev)
sd->paused = EINA_FALSE;
if (_elm_win_count == _paused_windows)
efl_event_callback_call(efl_loop_get(ev->object), EFL_LOOP_EVENT_RESUME, NULL);
efl_event_callback_call(efl_loop_get(ev->object), EFL_APP_EVENT_RESUME, NULL);
_paused_windows--;
}
@ -2831,7 +2831,7 @@ _efl_ui_win_efl_canvas_group_group_del(Eo *obj, Efl_Ui_Win_Data *sd)
_elm_win_state_eval_queue();
if (_elm_win_count == _paused_windows)
efl_event_callback_call(efl_loop_get(obj), EFL_LOOP_EVENT_PAUSE, NULL);
efl_event_callback_call(efl_loop_get(obj), EFL_APP_EVENT_PAUSE, NULL);
if (sd->ee)
{
@ -5474,7 +5474,7 @@ _efl_ui_win_efl_object_finalize(Eo *obj, Efl_Ui_Win_Data *sd)
obj = _elm_win_finalize_internal(obj, sd, sd->name, sd->type);
if (!obj) return NULL;
obj = efl_finalize(efl_super(obj, MY_CLASS));
if (obj && resume) efl_event_callback_call(efl_loop_get(obj), EFL_LOOP_EVENT_RESUME, NULL);
if (obj && resume) efl_event_callback_call(efl_loop_get(obj), EFL_APP_EVENT_RESUME, NULL);
return obj;
}

View File

@ -4061,9 +4061,10 @@ elm_entry_add(Evas_Object *parent)
static void
_cb_added(void *data EINA_UNUSED, const Efl_Event *ev)
{
const Efl_Callback_Array_Item *event = ev->info;
const Efl_Callback_Array_Item_Full *event = ev->info;
ELM_ENTRY_DATA_GET(ev->object, sd);
// XXX: BUG - not walking the array until a NULL entry
if (event->desc == ELM_ENTRY_EVENT_VALIDATE)
sd->validators++;
}
@ -4071,9 +4072,10 @@ _cb_added(void *data EINA_UNUSED, const Efl_Event *ev)
static void
_cb_deleted(void *data EINA_UNUSED, const Efl_Event *ev)
{
const Efl_Callback_Array_Item *event = ev->info;
const Efl_Callback_Array_Item_Full *event = ev->info;
ELM_ENTRY_DATA_GET(ev->object, sd);
// XXX: BUG - not walking the array until a NULL entry
if (event->desc == ELM_ENTRY_EVENT_VALIDATE)
sd->validators--;
return;

View File

@ -927,8 +927,8 @@ static void (*qre_terminate)(void *data,
EFL_CALLBACKS_ARRAY_DEFINE(_qre_main_ex,
{ EFL_LOOP_EVENT_ARGUMENTS, qre_main },
{ EFL_LOOP_EVENT_PAUSE, qre_pause },
{ EFL_LOOP_EVENT_RESUME, qre_resume },
{ EFL_APP_EVENT_PAUSE, qre_pause },
{ EFL_APP_EVENT_RESUME, qre_resume },
{ EFL_EVENT_DEL, qre_terminate });
EAPI Eina_Bool
@ -1304,12 +1304,12 @@ elm_policy_set(unsigned int policy,
{
if (value == ELM_POLICY_EXIT_WINDOWS_DEL)
{
efl_event_callback_add(efl_main_loop_get(), EFL_LOOP_EVENT_TERMINATE,
efl_event_callback_add(efl_main_loop_get(), EFL_APP_EVENT_TERMINATE,
_on_terminate, NULL);
}
else
{
efl_event_callback_del(efl_main_loop_get(), EFL_LOOP_EVENT_TERMINATE,
efl_event_callback_del(efl_main_loop_get(), EFL_APP_EVENT_TERMINATE,
_on_terminate, NULL);
}
}

View File

@ -241,10 +241,25 @@ typedef short Efl_Callback_Priority;
*/
typedef struct _Efl_Callback_Array_Item
{
const Efl_Event_Description *desc; /**< The event description. */
Efl_Event_Cb func; /**< The callback function. */
const Efl_Event_Description *desc; /**< The event description. */
Efl_Event_Cb func; /**< The callback function. */
} Efl_Callback_Array_Item;
/**
* @struct _Efl_Callback_Array_Item_Full
* @brief An item provided by EFL_EVENT_CALLBACK_ADD/EFL_EVENT_CALLBACK_DEL.
*
* See also EFL_EVENT_CALLBACK_ADD EFL_EVENT_CALLBACK_DEL.
*/
typedef struct _Efl_Callback_Array_Item_Full
{
const Efl_Event_Description *desc; /**< The event description. */
Efl_Callback_Priority priority; /** < The priorit of the event */
Efl_Event_Cb func; /**< The callback function. */
void *user_data; /**< The user data pointer to be passed to the func */
} Efl_Callback_Array_Item_Full;
/**
* @brief Add a callback for an event with a specific priority.
*

View File

@ -1228,7 +1228,8 @@ _efl_object_event_callback_priority_add(Eo *obj, Efl_Object_Data *pd,
Efl_Event_Cb func,
const void *user_data)
{
const Efl_Callback_Array_Item arr[] = { {desc, func}, {NULL, NULL}};
const Efl_Callback_Array_Item_Full arr[] =
{ {desc, priority, func, (void *)user_data}, {NULL, 0, NULL, NULL}};
Eo_Callback_Description *cb = _eo_callback_new();
// very unlikely so improve l1 instr cache by using goto
@ -1265,7 +1266,7 @@ EOAPI EFL_FUNC_BODYV(efl_event_callback_priority_add,
static void
_efl_object_event_callback_clean(Eo *obj, Efl_Object_Data *pd,
const Efl_Callback_Array_Item *array,
const Efl_Callback_Array_Item_Full *array,
Eo_Callback_Description **cb)
{
(*cb)->delete_me = EINA_TRUE;
@ -1295,7 +1296,8 @@ _efl_object_event_callback_del(Eo *obj, Efl_Object_Data *pd,
((*cb)->items.item.func == func) &&
((*cb)->func_data == user_data))
{
const Efl_Callback_Array_Item arr[] = { {desc, func}, {NULL, NULL}};
const Efl_Callback_Array_Item_Full arr[] =
{ {desc, (*cb)->priority, func, (*cb)->func_data}, {NULL, 0, NULL, NULL}};
_efl_object_event_callback_clean(obj, pd, arr, cb);
return EINA_TRUE;
@ -1318,9 +1320,9 @@ _efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
const void *user_data)
{
Eo_Callback_Description *cb = _eo_callback_new();
#if defined(EFL_EVENT_SPECIAL_SKIP) || defined(EO_DEBUG)
const Efl_Callback_Array_Item *it;
#endif
unsigned int num, i;
Efl_Callback_Array_Item_Full *ev_array;
#ifdef EO_DEBUG
const Efl_Callback_Array_Item *prev;
#endif
@ -1363,7 +1365,21 @@ _efl_object_event_callback_array_priority_add(Eo *obj, Efl_Object_Data *pd,
}
#endif
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, (void *)array);
num = 0;
for (it = cb->items.item_array; it->func; it++) num++;
ev_array = alloca((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
for (i = 0, it = cb->items.item_array; it->func; it++, i++)
{
ev_array[i].desc = cb->items.item_array[i].desc;
ev_array[i].priority = cb->priority;
ev_array[i].func = cb->items.item_array[i].func;
ev_array[i].user_data = cb->func_data;
}
ev_array[i].desc = NULL;
ev_array[i].priority = 0;
ev_array[i].func = NULL;
ev_array[i].user_data = NULL;
efl_event_callback_call(obj, EFL_EVENT_CALLBACK_ADD, ev_array);
return EINA_TRUE;
@ -1384,17 +1400,35 @@ _efl_object_event_callback_array_del(Eo *obj, Efl_Object_Data *pd,
const void *user_data)
{
Eo_Callback_Description **cb;
unsigned int i;
unsigned int j;
for (cb = pd->callbacks, i = 0;
i < pd->callbacks_count;
cb++, i++)
for (cb = pd->callbacks, j = 0;
j < pd->callbacks_count;
cb++, j++)
{
if (!(*cb)->delete_me &&
((*cb)->items.item_array == array) &&
((*cb)->func_data == user_data))
{
_efl_object_event_callback_clean(obj, pd, array, cb);
const Efl_Callback_Array_Item *it;
unsigned int num, i;
Efl_Callback_Array_Item_Full *ev_array;
num = 0;
for (it = (*cb)->items.item_array; it->func; it++) num++;
ev_array = alloca((num + 1) * sizeof(Efl_Callback_Array_Item_Full));
for (i = 0, it = (*cb)->items.item_array; it->func; it++, i++)
{
ev_array[i].desc = (*cb)->items.item_array[i].desc;
ev_array[i].priority = (*cb)->priority;
ev_array[i].func = (*cb)->items.item_array[i].func;
ev_array[i].user_data = (*cb)->func_data;
}
ev_array[i].desc = NULL;
ev_array[i].priority = 0;
ev_array[i].func = NULL;
ev_array[i].user_data = NULL;
_efl_object_event_callback_clean(obj, pd, ev_array, cb);
return EINA_TRUE;
}
}

View File

@ -700,7 +700,7 @@ _animator_repeater(void *data, const Efl_Event *event)
static void
_check_event_catcher_add(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Evas_Object_Protected_Data *obj = data;
Evas_Callback_Type type = EVAS_CALLBACK_LAST;
int i;
@ -728,7 +728,7 @@ _check_event_catcher_add(void *data, const Efl_Event *event)
static void
_check_event_catcher_del(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *array = event->info;
const Efl_Callback_Array_Item_Full *array = event->info;
Evas_Object_Protected_Data *obj = data;
int i;

View File

@ -896,11 +896,11 @@ START_TEST(ecore_test_efl_app_version)
ecore_init();
loop = efl_loop_main_get(EFL_LOOP_CLASS);
loop = efl_app_loop_main_get(EFL_APP_CLASS);
fail_if(!efl_isa(loop, EFL_LOOP_CLASS));
efl_build_version_set(EFL_VERSION_MAJOR, EFL_VERSION_MINOR, 0, 0, NULL, EFL_BUILD_ID);
ver = efl_loop_app_efl_version_get(loop);
ver = efl_app_build_efl_version_get(loop);
fail_if(!ver);
fail_if(ver->major != EFL_VERSION_MAJOR);
fail_if(ver->minor != EFL_VERSION_MINOR);
@ -909,7 +909,7 @@ START_TEST(ecore_test_efl_app_version)
fail_if(ver->flavor);
fail_if(!eina_streq(ver->build_id, EFL_BUILD_ID));
ver = efl_loop_efl_version_get(loop);
ver = efl_app_efl_version_get(loop);
fail_if(!ver);
fail_if(ver->major != EFL_VERSION_MAJOR);
fail_if(ver->minor != EFL_VERSION_MINOR);

View File

@ -32,10 +32,10 @@ START_TEST(efl_ui_test_init)
_efl_startup_time = ecore_time_unix_get();
_EFL_APP_VERSION_SET();
fail_if(!ecore_init());
efl_event_callback_add(efl_app_main_loop_get(efl_app_get()), EFL_LOOP_EVENT_ARGUMENTS, efl_main, NULL);
efl_event_callback_add(efl_app_get(), EFL_LOOP_EVENT_ARGUMENTS, efl_main, NULL);
fail_if(!ecore_init_ex(argc, argv));
__EFL_MAIN_CONSTRUCTOR;
ret__ = efl_loop_begin(efl_app_main_loop_get(efl_app_get()));
ret__ = efl_loop_begin(efl_app_get());
real__ = efl_loop_exit_code_process(ret__);
__EFL_MAIN_DESTRUCTOR;
ecore_shutdown_ex();

View File

@ -32,7 +32,7 @@ void
_cb_added(void *data EINA_UNUSED, const Efl_Event *event)
{
Simple_Public_Data *pd = efl_data_scope_get(event->object, MY_CLASS);
const Efl_Callback_Array_Item *callback_array = event->info;
const Efl_Callback_Array_Item_Full *callback_array = event->info;
if (callback_array->desc != EV_A_CHANGED)
return;
@ -46,7 +46,7 @@ void
_cb_deled(void *data EINA_UNUSED, const Efl_Event *event)
{
Simple_Public_Data *pd = efl_data_scope_get(event->object, MY_CLASS);
const Efl_Callback_Array_Item *callback_array = event->info;
const Efl_Callback_Array_Item_Full *callback_array = event->info;
if (callback_array->desc != EV_A_CHANGED)
return;

View File

@ -181,11 +181,9 @@ _eo_signals_efl_del_cb(void *_data EINA_UNUSED, const Efl_Event *event EINA_UNUS
void
_eo_signals_cb_added_deled(void *data, const Efl_Event *event)
{
const Efl_Callback_Array_Item *callback_array = event->info;
const Efl_Callback_Array_Item *(*callback_data)(void) = data;
const Efl_Callback_Array_Item_Full *callback_array = event->info;
fail_if((callback_data() != callback_array) &&
(callback_array->func != _eo_signals_cb_added_deled));
fail_if(callback_array->func != _eo_signals_cb_added_deled);
}
EFL_CALLBACKS_ARRAY_DEFINE(_eo_signals_callbacks,