raster pushed a commit to branch master.

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

commit 1bdd9e4dd15fc27da43b50fd29bfb1b0b30ef6bd
Author: Carsten Haitzler (Rasterman) <ras...@rasterman.com>
Date:   Tue Feb 27 21:19:17 2018 +0900

    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/
---
 src/Makefile_Ecore.am                 |   9 +-
 src/lib/ecore/Ecore_Eo.h              |   4 +
 src/lib/ecore/ecore.c                 |  10 +-
 src/lib/ecore/ecore_exe.c             |   2 +-
 src/lib/ecore/ecore_main.c            |   8 +-
 src/lib/ecore/ecore_private.h         |  17 +-
 src/lib/ecore/ecore_signal.c          |   9 +-
 src/lib/ecore/ecore_timer.c           |   4 +-
 src/lib/ecore/efl_app.c               | 415 +++++++++++++++
 src/lib/ecore/efl_app.eo              |  57 +++
 src/lib/ecore/efl_appthread.c         | 245 +++++++++
 src/lib/ecore/efl_appthread.eo        |  22 +
 src/lib/ecore/efl_exe.c               |  28 +-
 src/lib/ecore/efl_general.h           |   6 +-
 src/lib/ecore/efl_loop.c              |  94 +---
 src/lib/ecore/efl_loop.eo             |  36 +-
 src/lib/ecore/efl_loop_fd.c           |   4 +-
 src/lib/ecore/efl_loop_handler.c      |   2 +-
 src/lib/ecore/efl_task.c              |  11 +-
 src/lib/ecore/efl_thread.c            | 917 ++++++++++++++++++++++++++++++++++
 src/lib/ecore/efl_thread.eo           |  10 +
 src/lib/ecore_evas/ecore_evas.c       |   4 +-
 src/lib/eina/eina_internal.h          |   2 +
 src/lib/eina/eina_promise.c           |  21 +
 src/lib/elementary/efl_ui_text.c      |   6 +-
 src/lib/elementary/efl_ui_win.c       |  12 +-
 src/lib/elementary/elm_entry.c        |   6 +-
 src/lib/elementary/elm_main.c         |   8 +-
 src/lib/eo/Eo.h                       |  19 +-
 src/lib/eo/eo_base_class.c            |  56 ++-
 src/lib/evas/canvas/evas_callbacks.c  |   4 +-
 src/tests/ecore/ecore_test_ecore.c    |   6 +-
 src/tests/elementary/efl_ui_suite.c   |   4 +-
 src/tests/eo/signals/signals_simple.c |   4 +-
 src/tests/eo/suite/eo_test_general.c  |   6 +-
 35 files changed, 1882 insertions(+), 186 deletions(-)

diff --git a/src/Makefile_Ecore.am b/src/Makefile_Ecore.am
index 28a46d374d..630977846d 100644
--- a/src/Makefile_Ecore.am
+++ b/src/Makefile_Ecore.am
@@ -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 \
diff --git a/src/lib/ecore/Ecore_Eo.h b/src/lib/ecore/Ecore_Eo.h
index f5ce92d805..be4df7e377 100644
--- a/src/lib/ecore/Ecore_Eo.h
+++ b/src/lib/ecore/Ecore_Eo.h
@@ -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;
 
diff --git a/src/lib/ecore/ecore.c b/src/lib/ecore/ecore.c
index d911bc4e23..754b826314 100644
--- a/src/lib/ecore/ecore.c
+++ b/src/lib/ecore/ecore.c
@@ -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();
 
diff --git a/src/lib/ecore/ecore_exe.c b/src/lib/ecore/ecore_exe.c
index 908f677539..781dea60bd 100644
--- a/src/lib/ecore/ecore_exe.c
+++ b/src/lib/ecore/ecore_exe.c
@@ -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)
diff --git a/src/lib/ecore/ecore_main.c b/src/lib/ecore/ecore_main.c
index bc3c6c84a9..ebd572bb65 100644
--- a/src/lib/ecore/ecore_main.c
+++ b/src/lib/ecore/ecore_main.c
@@ -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)
      {
diff --git a/src/lib/ecore/ecore_private.h b/src/lib/ecore/ecore_private.h
index 7ff80f57c3..7e44bf4acb 100644
--- a/src/lib/ecore/ecore_private.h
+++ b/src/lib/ecore/ecore_private.h
@@ -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);
 
diff --git a/src/lib/ecore/ecore_signal.c b/src/lib/ecore/ecore_signal.c
index 98934e63b3..616f22b4ee 100644
--- a/src/lib/ecore/ecore_signal.c
+++ b/src/lib/ecore/ecore_signal.c
@@ -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
diff --git a/src/lib/ecore/ecore_timer.c b/src/lib/ecore/ecore_timer.c
index 6ef4ab254c..7805f79de2 100644
--- a/src/lib/ecore/ecore_timer.c
+++ b/src/lib/ecore/ecore_timer.c
@@ -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++)
diff --git a/src/lib/ecore/efl_app.c b/src/lib/ecore/efl_app.c
new file mode 100644
index 0000000000..b6e2b1f29d
--- /dev/null
+++ b/src/lib/ecore/efl_app.c
@@ -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"
diff --git a/src/lib/ecore/efl_app.eo b/src/lib/ecore/efl_app.eo
new file mode 100644
index 0000000000..97e08957e2
--- /dev/null
+++ b/src/lib/ecore/efl_app.eo
@@ -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; }
+   }
+}
diff --git a/src/lib/ecore/efl_appthread.c b/src/lib/ecore/efl_appthread.c
new file mode 100644
index 0000000000..93de9c0917
--- /dev/null
+++ b/src/lib/ecore/efl_appthread.c
@@ -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"
diff --git a/src/lib/ecore/efl_appthread.eo b/src/lib/ecore/efl_appthread.eo
new file mode 100644
index 0000000000..2f5021a720
--- /dev/null
+++ b/src/lib/ecore/efl_appthread.eo
@@ -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; }
+   }
+}
diff --git a/src/lib/ecore/efl_exe.c b/src/lib/ecore/efl_exe.c
index ed9c53c583..1443bbf071 100644
--- a/src/lib/ecore/efl_exe.c
+++ b/src/lib/ecore/efl_exe.c
@@ -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);
 }
diff --git a/src/lib/ecore/efl_general.h b/src/lib/ecore/efl_general.h
index 256f1065a4..222c799c2c 100644
--- a/src/lib/ecore/efl_general.h
+++ b/src/lib/ecore/efl_general.h
@@ -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__;                                                 \
diff --git a/src/lib/ecore/efl_loop.c b/src/lib/ecore/efl_loop.c
index 74a12deb50..0ccee1706f 100644
--- a/src/lib/ecore/efl_loop.c
+++ b/src/lib/ecore/efl_loop.c
@@ -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] =
+
+EOLIAN static Eina_Bool
+_efl_loop_efl_task_run(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED)
 {
-   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
+   Eina_Value *ret;
+   int real;
 
-EOLIAN static void
-_efl_loop_efl_task_priority_set(Eo *obj, Efl_Loop_Data *pd EINA_UNUSED, 
Efl_Task_Priority priority)
-{
-   efl_task_priority_set(efl_super(obj, EFL_LOOP_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
+   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 *
diff --git a/src/lib/ecore/efl_loop.eo b/src/lib/ecore/efl_loop.eo
index e6c1229772..1ecdd68538 100644
--- a/src/lib/ecore/efl_loop.eo
+++ b/src/lib/ecore/efl_loop.eo
@@ -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;
    }
 }
diff --git a/src/lib/ecore/efl_loop_fd.c b/src/lib/ecore/efl_loop_fd.c
index 87cb58c41a..e6ec21d7b9 100644
--- a/src/lib/ecore/efl_loop_fd.c
+++ b/src/lib/ecore/efl_loop_fd.c
@@ -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;
diff --git a/src/lib/ecore/efl_loop_handler.c b/src/lib/ecore/efl_loop_handler.c
index 39d05359dd..34e03a9cc4 100644
--- a/src/lib/ecore/efl_loop_handler.c
+++ b/src/lib/ecore/efl_loop_handler.c
@@ -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;
 
diff --git a/src/lib/ecore/efl_task.c b/src/lib/ecore/efl_task.c
index 18927e843e..9a727743ed 100644
--- a/src/lib/ecore/efl_task.c
+++ b/src/lib/ecore/efl_task.c
@@ -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)
diff --git a/src/lib/ecore/efl_thread.c b/src/lib/ecore/efl_thread.c
new file mode 100644
index 0000000000..ffd4f4756f
--- /dev/null
+++ b/src/lib/ecore/efl_thread.c
@@ -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"
diff --git a/src/lib/ecore/efl_thread.eo b/src/lib/ecore/efl_thread.eo
index 63b7292131..214c0fd07f 100644
--- a/src/lib/ecore/efl_thread.eo
+++ b/src/lib/ecore/efl_thread.eo
@@ -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; }
    }
 }
diff --git a/src/lib/ecore_evas/ecore_evas.c b/src/lib/ecore_evas/ecore_evas.c
index 67ab7e9fd0..4348da8084 100644
--- a/src/lib/ecore_evas/ecore_evas.c
+++ b/src/lib/ecore_evas/ecore_evas.c
@@ -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;
 
diff --git a/src/lib/eina/eina_internal.h b/src/lib/eina/eina_internal.h
index 9324118c91..83e6f5da61 100644
--- a/src/lib/eina/eina_internal.h
+++ b/src/lib/eina/eina_internal.h
@@ -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
  *
diff --git a/src/lib/eina/eina_promise.c b/src/lib/eina/eina_promise.c
index c3b488d223..93e091bd9e 100644
--- a/src/lib/eina/eina_promise.c
+++ b/src/lib/eina/eina_promise.c
@@ -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)
 {
diff --git a/src/lib/elementary/efl_ui_text.c b/src/lib/elementary/efl_ui_text.c
index 98dda2afea..b8fa0ea20e 100644
--- a/src/lib/elementary/efl_ui_text.c
+++ b/src/lib/elementary/efl_ui_text.c
@@ -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;
diff --git a/src/lib/elementary/efl_ui_win.c b/src/lib/elementary/efl_ui_win.c
index f9f9723d8e..0059cfb9b0 100644
--- a/src/lib/elementary/efl_ui_win.c
+++ b/src/lib/elementary/efl_ui_win.c
@@ -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;
 }
 
diff --git a/src/lib/elementary/elm_entry.c b/src/lib/elementary/elm_entry.c
index 0b61f24124..eff0bbfa65 100644
--- a/src/lib/elementary/elm_entry.c
+++ b/src/lib/elementary/elm_entry.c
@@ -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;
diff --git a/src/lib/elementary/elm_main.c b/src/lib/elementary/elm_main.c
index 646b2ee474..82efe0a3c7 100644
--- a/src/lib/elementary/elm_main.c
+++ b/src/lib/elementary/elm_main.c
@@ -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);
           }
      }
diff --git a/src/lib/eo/Eo.h b/src/lib/eo/Eo.h
index 441b3789fc..7c20daaccb 100644
--- a/src/lib/eo/Eo.h
+++ b/src/lib/eo/Eo.h
@@ -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.
  *
diff --git a/src/lib/eo/eo_base_class.c b/src/lib/eo/eo_base_class.c
index ca38e7b171..f1eff91f3e 100644
--- a/src/lib/eo/eo_base_class.c
+++ b/src/lib/eo/eo_base_class.c
@@ -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;
           }
      }
diff --git a/src/lib/evas/canvas/evas_callbacks.c 
b/src/lib/evas/canvas/evas_callbacks.c
index 4f63c2323d..8896dea691 100644
--- a/src/lib/evas/canvas/evas_callbacks.c
+++ b/src/lib/evas/canvas/evas_callbacks.c
@@ -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;
 
diff --git a/src/tests/ecore/ecore_test_ecore.c 
b/src/tests/ecore/ecore_test_ecore.c
index 492c2aa033..6fd95738f4 100644
--- a/src/tests/ecore/ecore_test_ecore.c
+++ b/src/tests/ecore/ecore_test_ecore.c
@@ -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);
diff --git a/src/tests/elementary/efl_ui_suite.c 
b/src/tests/elementary/efl_ui_suite.c
index 629bb10faa..d2269b68a7 100644
--- a/src/tests/elementary/efl_ui_suite.c
+++ b/src/tests/elementary/efl_ui_suite.c
@@ -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();
diff --git a/src/tests/eo/signals/signals_simple.c 
b/src/tests/eo/signals/signals_simple.c
index 9449c3f8c0..0e016dc550 100644
--- a/src/tests/eo/signals/signals_simple.c
+++ b/src/tests/eo/signals/signals_simple.c
@@ -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;
diff --git a/src/tests/eo/suite/eo_test_general.c 
b/src/tests/eo/suite/eo_test_general.c
index e475889e95..18684f1ad2 100644
--- a/src/tests/eo/suite/eo_test_general.c
+++ b/src/tests/eo/suite/eo_test_general.c
@@ -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,

-- 


Reply via email to