forked from enlightenment/efl
Eina: Add Eina_Promise/Eina_Future.
This commit adds a new promise/future API which aims to replace efl_future.
This commit is contained in:
parent
27cba99045
commit
d30c0d4f03
|
@ -10,6 +10,7 @@ lib/eina/eina_config.h
|
|||
|
||||
installed_einaheadersdir = $(includedir)/eina-@VMAJ@/eina
|
||||
dist_installed_einaheaders_DATA = \
|
||||
lib/eina/eina_promise.h \
|
||||
lib/eina/eina_safety_checks.h \
|
||||
lib/eina/eina_error.h \
|
||||
lib/eina/eina_debug.h \
|
||||
|
@ -150,6 +151,8 @@ lib/eina/eina_mempool.c \
|
|||
lib/eina/eina_mmap.c \
|
||||
lib/eina/eina_module.c \
|
||||
lib/eina/eina_prefix.c \
|
||||
lib/eina/eina_promise.c \
|
||||
lib/eina/eina_promise_private.h \
|
||||
lib/eina/eina_quad.c \
|
||||
lib/eina/eina_quadtree.c \
|
||||
lib/eina/eina_rbtree.c \
|
||||
|
|
|
@ -251,6 +251,7 @@ ecore_init(void)
|
|||
if (getenv("ECORE_FPS_DEBUG")) _ecore_fps_debug = 1;
|
||||
if (_ecore_fps_debug) _ecore_fps_debug_init();
|
||||
if (!ecore_mempool_init()) goto shutdown_mempool;
|
||||
if (!_ecore_event_init()) goto shutdown_mempool;
|
||||
_ecore_main_loop_init();
|
||||
|
||||
vpath = efl_add(EFL_VPATH_CORE_CLASS, NULL);
|
||||
|
|
|
@ -48,6 +48,15 @@ struct _Ecore_Event
|
|||
};
|
||||
GENERIC_ALLOC_SIZE_DECLARE(Ecore_Event);
|
||||
|
||||
typedef struct _Ecore_Future_Schedule_Entry
|
||||
{
|
||||
Eina_Future_Schedule_Entry base;
|
||||
Eina_Future_Scheduler_Cb cb;
|
||||
Eina_Future *future;
|
||||
Ecore_Event *event;
|
||||
Eina_Value value;
|
||||
} Ecore_Future_Schedule_Entry;
|
||||
|
||||
static int events_num = 0;
|
||||
static Ecore_Event *events = NULL;
|
||||
static Ecore_Event *event_current = NULL;
|
||||
|
@ -68,6 +77,10 @@ static int event_filters_delete_me = 0;
|
|||
static int event_id_max = ECORE_EVENT_COUNT;
|
||||
static int ecore_raw_event_type = ECORE_EVENT_NONE;
|
||||
static void *ecore_raw_event_event = NULL;
|
||||
static Ecore_Event_Handler *future_handler = NULL;
|
||||
static int ECORE_EV_FUTURE_ID = -1;
|
||||
static Eina_Mempool *mp_future_schedule_entry = NULL;
|
||||
static Eina_Bool shutting_down = EINA_FALSE;
|
||||
|
||||
static void _ecore_event_purge_deleted(void);
|
||||
static void *_ecore_event_del(Ecore_Event *event);
|
||||
|
@ -268,6 +281,100 @@ _ecore_event_handler_del(Ecore_Event_Handler *event_handler)
|
|||
return event_handler->data;
|
||||
}
|
||||
|
||||
static Eina_Bool
|
||||
ecore_future_dispatched(void *data EINA_UNUSED, int type EINA_UNUSED, void *event)
|
||||
{
|
||||
Ecore_Future_Schedule_Entry *entry = event;
|
||||
entry->event = NULL;
|
||||
entry->cb(entry->future, entry->value);
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
ecore_future_free(void *user_data, void *func_data EINA_UNUSED)
|
||||
{
|
||||
Ecore_Future_Schedule_Entry *entry = user_data;
|
||||
/*
|
||||
In case entry->event is not NULL, it means
|
||||
that ecore is shutting down. In this case,
|
||||
we must cancel the future otherwise Eina may
|
||||
try to use it and lead to crashes.
|
||||
*/
|
||||
if (entry->event)
|
||||
{
|
||||
eina_future_cancel(entry->future);
|
||||
eina_value_flush(&entry->value);
|
||||
}
|
||||
eina_mempool_free(mp_future_schedule_entry, entry);
|
||||
}
|
||||
|
||||
static Eina_Future_Schedule_Entry *
|
||||
ecore_future_schedule(Eina_Future_Scheduler *sched, Eina_Future_Scheduler_Cb cb, Eina_Future *future, Eina_Value value)
|
||||
{
|
||||
Ecore_Future_Schedule_Entry *entry = eina_mempool_malloc(mp_future_schedule_entry,
|
||||
sizeof(Ecore_Future_Schedule_Entry));
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(entry, NULL);
|
||||
entry->base.scheduler = sched;
|
||||
entry->cb = cb;
|
||||
entry->future = future;
|
||||
entry->value = value;
|
||||
entry->event = ecore_event_add(ECORE_EV_FUTURE_ID, entry, ecore_future_free, entry);
|
||||
EINA_SAFETY_ON_NULL_GOTO(entry->event, err);
|
||||
return &entry->base;
|
||||
|
||||
err:
|
||||
eina_mempool_free(mp_future_schedule_entry, entry);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
ecore_future_recall(Eina_Future_Schedule_Entry *s_entry)
|
||||
{
|
||||
if (shutting_down) return;
|
||||
Ecore_Future_Schedule_Entry *entry = (Ecore_Future_Schedule_Entry *)s_entry;
|
||||
EINA_SAFETY_ON_NULL_RETURN(entry->event);
|
||||
ecore_event_del(entry->event);
|
||||
eina_value_flush(&entry->value);
|
||||
entry->event = NULL;
|
||||
}
|
||||
|
||||
static Eina_Future_Scheduler ecore_future_scheduler = {
|
||||
.schedule = ecore_future_schedule,
|
||||
.recall = ecore_future_recall,
|
||||
};
|
||||
|
||||
Eina_Future_Scheduler *
|
||||
_ecore_event_future_scheduler_get(void)
|
||||
{
|
||||
return &ecore_future_scheduler;
|
||||
}
|
||||
|
||||
Eina_Bool
|
||||
_ecore_event_init(void)
|
||||
{
|
||||
const char *choice = getenv("EINA_MEMPOOL");
|
||||
if ((!choice) || (!choice[0])) choice = "chained_mempool";
|
||||
|
||||
shutting_down = EINA_FALSE;
|
||||
ECORE_EV_FUTURE_ID = ecore_event_type_new();
|
||||
future_handler = ecore_event_handler_add(ECORE_EV_FUTURE_ID, ecore_future_dispatched, NULL);
|
||||
EINA_SAFETY_ON_NULL_GOTO(future_handler, err_handler);
|
||||
//FIXME: Is 512 too high?
|
||||
mp_future_schedule_entry = eina_mempool_add(choice, "Ecore_Future_Event",
|
||||
NULL, sizeof(Ecore_Future_Schedule_Entry),
|
||||
512);
|
||||
EINA_SAFETY_ON_NULL_GOTO(mp_future_schedule_entry, err_pool);
|
||||
|
||||
return EINA_TRUE;
|
||||
|
||||
err_pool:
|
||||
ecore_event_handler_del(future_handler);
|
||||
future_handler = NULL;
|
||||
err_handler:
|
||||
ECORE_EV_FUTURE_ID = -1;
|
||||
return EINA_FALSE;
|
||||
}
|
||||
|
||||
void
|
||||
_ecore_event_shutdown(void)
|
||||
{
|
||||
|
@ -275,6 +382,9 @@ _ecore_event_shutdown(void)
|
|||
Ecore_Event_Handler *eh;
|
||||
Ecore_Event_Filter *ef;
|
||||
|
||||
shutting_down = EINA_TRUE;
|
||||
ecore_event_handler_del(future_handler);
|
||||
future_handler = NULL;
|
||||
while (events) _ecore_event_del(events);
|
||||
event_current = NULL;
|
||||
for (i = 0; i < event_handlers_num; i++)
|
||||
|
@ -301,6 +411,7 @@ _ecore_event_shutdown(void)
|
|||
event_filters_delete_me = 0;
|
||||
event_filter_current = NULL;
|
||||
event_filter_event_current = NULL;
|
||||
ECORE_EV_FUTURE_ID = -1;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
@ -3286,5 +3286,12 @@ _efl_loop_efl_version_get(Eo *obj EINA_UNUSED, Efl_Loop_Data *pd EINA_UNUSED)
|
|||
return &version;
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Future_Scheduler *
|
||||
_efl_loop_future_scheduler_get(Eo *obj EINA_UNUSED,
|
||||
Efl_Loop_Data *pd EINA_UNUSED)
|
||||
{
|
||||
return _ecore_event_future_scheduler_get();
|
||||
}
|
||||
|
||||
|
||||
#include "efl_loop.eo.c"
|
||||
|
|
|
@ -187,6 +187,10 @@ void _ecore_idle_enterer_call(Eo *loop);
|
|||
|
||||
void _ecore_idle_exiter_call(Eo *loop);
|
||||
|
||||
|
||||
Eina_Future_Scheduler *_ecore_event_future_scheduler_get(void);
|
||||
|
||||
Eina_Bool _ecore_event_init(void);
|
||||
void _ecore_event_shutdown(void);
|
||||
int _ecore_event_exist(void);
|
||||
Ecore_Event *_ecore_event_add(int type,
|
||||
|
@ -382,6 +386,9 @@ void ecore_loop_promise_register(Efl_Loop *l, Efl_Promise *p);
|
|||
void ecore_loop_promise_unregister(Efl_Loop *l, Efl_Promise *p);
|
||||
void ecore_loop_promise_fulfill(Efl_Promise *p);
|
||||
|
||||
Eina_Bool efl_promise2_init(void);
|
||||
void efl_promise2_shutdown(void);
|
||||
|
||||
// access to direct input cb
|
||||
#define ECORE_EVAS_INTERNAL
|
||||
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import efl_types;
|
||||
import eina_types;
|
||||
|
||||
struct Efl.Loop.Arguments {
|
||||
[[EFL loop arguments data structure]]
|
||||
|
@ -69,6 +70,18 @@ class Efl.Loop (Efl.Object)
|
|||
@in exit_code: ubyte; [[Returned value by begin()]]
|
||||
}
|
||||
}
|
||||
@property future_scheduler {
|
||||
[[Gets the Eina_Future_Scheduler for a given mainloop.
|
||||
|
||||
The Eina_Future_Scheduler returned by this function
|
||||
should be used for creating promises (eina_promise_new())
|
||||
so then can properly schedule resolve/reject events.
|
||||
]]
|
||||
get {}
|
||||
values {
|
||||
scheduler: ptr(Eina.Future.Scheduler); [[The scheduler.]]
|
||||
}
|
||||
}
|
||||
job {
|
||||
[[Will execute that promise in the near future.]]
|
||||
params {
|
||||
|
|
|
@ -273,6 +273,7 @@ extern "C" {
|
|||
#include <eina_freeq.h>
|
||||
#include <eina_slstr.h>
|
||||
#include <eina_debug.h>
|
||||
#include <eina_promise.h>
|
||||
|
||||
#undef EAPI
|
||||
#define EAPI
|
||||
|
|
|
@ -159,6 +159,7 @@ EAPI Eina_Inlist *_eina_tracking = NULL;
|
|||
S(file);
|
||||
S(safepointer);
|
||||
S(slstr);
|
||||
S(promise);
|
||||
#undef S
|
||||
|
||||
struct eina_desc_setup
|
||||
|
@ -205,6 +206,7 @@ static const struct eina_desc_setup _eina_desc_setup[] = {
|
|||
S(file),
|
||||
S(safepointer),
|
||||
S(slstr),
|
||||
S(promise),
|
||||
#undef S
|
||||
};
|
||||
static const size_t _eina_desc_setup_len = sizeof(_eina_desc_setup) /
|
||||
|
@ -305,7 +307,6 @@ eina_init(void)
|
|||
eina_cpu_count_internal();
|
||||
|
||||
eina_log_timing(_eina_log_dom, EINA_LOG_STATE_STOP, EINA_LOG_STATE_INIT);
|
||||
|
||||
_eina_main_count = 1;
|
||||
eina_evlog("-eina_init", NULL, 0.0, NULL);
|
||||
return 1;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,38 @@
|
|||
#ifndef __EINA_PROMISE_PRIVATE_H__
|
||||
#define __EINA_PROMISE_PRIVATE_H__
|
||||
|
||||
#define ERROR_DISPATCH(_cbs, _ret, _value, _data) \
|
||||
do { \
|
||||
Eina_Error ERROR_DISPATCH__err; \
|
||||
if (!(_cbs)->error) (_ret) = (_value); \
|
||||
else \
|
||||
{ \
|
||||
eina_value_get(&(_value), &ERROR_DISPATCH__err); \
|
||||
(_ret) = (_cbs)->error((_data), ERROR_DISPATCH__err); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define EASY_FUTURE_DISPATCH(_ret, _value, _dead_future, _cbs, _data) \
|
||||
do { \
|
||||
if ((_value).type == EINA_VALUE_TYPE_ERROR) ERROR_DISPATCH((_cbs), (_ret), (_value), (_data)); \
|
||||
else \
|
||||
{ \
|
||||
if ((!(_cbs)->success_type) || ((_cbs)->success_type && (_value).type == (_cbs)->success_type)) \
|
||||
{ \
|
||||
if (!(_cbs)->success) (_ret) = (_value); /* pass thru */ \
|
||||
else (_ret) = (_cbs)->success((_data), (_value)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
Eina_Value EASY_FUTURE_DISPATCH__err = EINA_VALUE_EMPTY; \
|
||||
ERR("Future %p, success cb: %p data: %p, expected success_type %p (%s), got %p (%s)", \
|
||||
_dead_future, (_cbs)->success, (_data), \
|
||||
(_cbs)->success_type, eina_value_type_name_get((_cbs)->success_type), \
|
||||
(_value).type, (_value).type ? eina_value_type_name_get((_value).type) : NULL); \
|
||||
if (eina_value_setup(&EASY_FUTURE_DISPATCH__err, EINA_VALUE_TYPE_ERROR)) eina_value_set(&EASY_FUTURE_DISPATCH__err, EINVAL); \
|
||||
ERROR_DISPATCH((_cbs), (_ret), EASY_FUTURE_DISPATCH__err, (_data)); \
|
||||
} \
|
||||
} \
|
||||
if ((_cbs)->free) (_cbs)->free((_data), _dead_future); \
|
||||
} while(0)
|
||||
#endif
|
|
@ -62,3 +62,7 @@ struct @extern Eina.Rw_Slice {
|
|||
}
|
||||
|
||||
struct @extern Eina.Value.Type; [[Eina value type]]
|
||||
|
||||
struct @extern Eina.Future.Scheduler; [[This struct is used as a bridge between Eina and the future scheduler.
|
||||
By using the provided functions Eina can schedule futures resolutions,
|
||||
rejections and cancelations to a safe context.]]
|
Loading…
Reference in New Issue