forked from enlightenment/efl
eo: add infrastructure to attach an Eina_Future_Scheduler to any source of event.
Reviewed-by: Marcel Hollerbach <mail@marcel-hollerbach.de> Differential Revision: https://phab.enlightenment.org/D10480
This commit is contained in:
parent
2f1894d054
commit
474b1b2c2d
|
@ -317,6 +317,18 @@ EOAPI Eina_Bool efl_event_callback_priority_add(Eo *obj, const Efl_Event_Descrip
|
|||
*/
|
||||
EOAPI Eina_Bool efl_event_callback_del(Eo *obj, const Efl_Event_Description *desc, Efl_Event_Cb func, const void *user_data);
|
||||
|
||||
/**
|
||||
* @brief Get the Eina_Future scheduler that trigger them on a specific set of events on an object.
|
||||
*
|
||||
* @param[in] obj The object that the scheduler is attached to.
|
||||
* @param[in] array The events that when triggered on the object will trigger the Eina_Future.
|
||||
*
|
||||
* @return Return a scheduler that will trigger future exactly when the event are triggered.
|
||||
*
|
||||
* @note You must use EFL_SCHEDULER_ARRAY_DEFINE() to create the @p array.
|
||||
*/
|
||||
EOAPI Eina_Future_Scheduler *efl_event_future_scheduler_get(const Eo *obj, Efl_Callback_Array_Item *array);
|
||||
|
||||
/**
|
||||
* @brief Add an array of callbacks created by @ref EFL_CALLBACKS_ARRAY_DEFINE
|
||||
* for an event with a specific priority. The array need to be sorted with @ref
|
||||
|
@ -1899,7 +1911,6 @@ EOAPI void efl_wref_add(Eo *obj, Efl_Object **wref);
|
|||
*/
|
||||
EOAPI void efl_wref_del(Eo *obj, Efl_Object **wref);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Generic data with string key on an object.
|
||||
*
|
||||
|
@ -2183,6 +2194,32 @@ EAPI int efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_
|
|||
return internal; \
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for creating global scheduler arrays. The callback will be set by scheduler get.
|
||||
* Problems occur here in windows where you can't declare a static array with
|
||||
* external symbols in them. These addresses are only known at runtime.
|
||||
* This also allows for automatic sorting for better performance.
|
||||
*/
|
||||
#define EFL_SCHEDULER_ARRAY_DEFINE(Name, ...) \
|
||||
static Efl_Callback_Array_Item * \
|
||||
Name(void) \
|
||||
{ \
|
||||
const Efl_Event_Description *tmp[] = { __VA_ARGS__ }; \
|
||||
static Efl_Callback_Array_Item internal[EINA_C_ARRAY_LENGTH(tmp) + 1] = { { 0, 0 } }; \
|
||||
\
|
||||
if (internal[0].desc == NULL) \
|
||||
{ \
|
||||
unsigned int i; \
|
||||
\
|
||||
for (i = 0; i < EINA_C_ARRAY_LENGTH(tmp); i++) \
|
||||
internal[i].desc = tmp[i]; \
|
||||
\
|
||||
qsort(internal, EINA_C_ARRAY_LENGTH(internal) - 1, sizeof (internal[0]), \
|
||||
(int(*)(const void*,const void*)) efl_callbacks_cmp); \
|
||||
} \
|
||||
return internal; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @def efl_event_callback_add(obj, desc, cb, data)
|
||||
* Add a callback for an event.
|
||||
|
|
|
@ -2770,6 +2770,7 @@ efl_callbacks_cmp(const Efl_Callback_Array_Item *a, const Efl_Callback_Array_Ite
|
|||
else return -1;
|
||||
}
|
||||
|
||||
|
||||
#ifdef EO_DEBUG
|
||||
/* NOTE: cannot use ecore_time_get()! */
|
||||
static inline double
|
||||
|
|
|
@ -40,6 +40,7 @@ typedef struct
|
|||
Eina_Inlist *generic_data;
|
||||
Eo ***wrefs;
|
||||
Eina_Hash *providers;
|
||||
Eina_Hash *schedulers;
|
||||
} Efl_Object_Extension;
|
||||
|
||||
struct _Efl_Object_Data
|
||||
|
@ -155,7 +156,8 @@ _efl_object_extension_noneed(Efl_Object_Data *pd)
|
|||
(ext->generic_data) ||
|
||||
(ext->wrefs) ||
|
||||
(ext->composite_parent) ||
|
||||
(ext->providers)) return;
|
||||
(ext->providers) ||
|
||||
(ext->schedulers)) return;
|
||||
_efl_object_extension_free(pd->ext);
|
||||
pd->ext = NULL;
|
||||
}
|
||||
|
@ -171,6 +173,12 @@ _efl_object_invalidate(Eo *obj_id, Efl_Object_Data *pd)
|
|||
pd->ext->providers = NULL;
|
||||
_efl_object_extension_noneed(pd);
|
||||
}
|
||||
if (pd->ext && pd->ext->schedulers)
|
||||
{
|
||||
eina_hash_free(pd->ext->schedulers);
|
||||
pd->ext->schedulers = NULL;
|
||||
_efl_object_extension_noneed(pd);
|
||||
}
|
||||
|
||||
EO_OBJ_POINTER_RETURN(obj_id, obj);
|
||||
|
||||
|
@ -1183,6 +1191,7 @@ struct _Eo_Callback_Description
|
|||
|
||||
static Eina_Mempool *_eo_callback_mempool = NULL;
|
||||
static Eina_Mempool *_efl_pending_future_mempool = NULL;
|
||||
static Eina_Mempool *_efl_future_scheduler_entry_mempool = NULL;
|
||||
|
||||
static void
|
||||
_eo_callback_free(Eo_Callback_Description *cb)
|
||||
|
@ -1677,6 +1686,188 @@ EOAPI EFL_FUNC_BODYV(efl_event_callback_array_del,
|
|||
const Efl_Callback_Array_Item *array,
|
||||
const void *user_data);
|
||||
|
||||
typedef struct _Efl_Future_Scheduler Efl_Future_Scheduler;
|
||||
typedef struct _Efl_Future_Scheduler_Entry Efl_Future_Scheduler_Entry;
|
||||
|
||||
struct _Efl_Future_Scheduler
|
||||
{
|
||||
Eina_Future_Scheduler scheduler;
|
||||
|
||||
const Efl_Callback_Array_Item *array;
|
||||
const Eo *self;
|
||||
|
||||
Eina_List *futures;
|
||||
|
||||
Eina_Bool listener : 1;
|
||||
};
|
||||
|
||||
struct _Efl_Future_Scheduler_Entry
|
||||
{
|
||||
Eina_Future_Schedule_Entry base;
|
||||
Eina_Future_Scheduler_Cb cb;
|
||||
Eina_Future *future;
|
||||
Eina_Value value;
|
||||
};
|
||||
|
||||
static Eina_Trash *schedulers_trash = NULL;
|
||||
static unsigned char schedulers_count = 0;
|
||||
|
||||
static void
|
||||
_future_scheduler_cleanup(Efl_Object_Data *pd)
|
||||
{
|
||||
if (eina_hash_population(pd->ext->schedulers)) return ;
|
||||
|
||||
eina_hash_free(pd->ext->schedulers);
|
||||
pd->ext->schedulers = NULL;
|
||||
_efl_object_extension_noneed(pd);
|
||||
}
|
||||
|
||||
static void
|
||||
_futures_dispatch_cb(void *data, const Efl_Event *ev EINA_UNUSED)
|
||||
{
|
||||
Efl_Future_Scheduler *sched = data;
|
||||
Eina_List *entries = sched->futures;
|
||||
Efl_Future_Scheduler_Entry *entry;
|
||||
|
||||
sched->futures = NULL;
|
||||
|
||||
efl_event_callback_array_del((Eo *) sched->self, sched->array, sched);
|
||||
sched->listener = EINA_FALSE;
|
||||
|
||||
// Now trigger callbacks
|
||||
EINA_LIST_FREE(entries, entry)
|
||||
{
|
||||
entry->cb(entry->future, entry->value);
|
||||
eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_futures_cancel_cb(void *data)
|
||||
{
|
||||
Efl_Future_Scheduler *sched = data;
|
||||
Eina_List *entries = sched->futures;
|
||||
Efl_Future_Scheduler_Entry *entry;
|
||||
|
||||
efl_event_callback_array_del((Eo *) sched->self, sched->array, sched);
|
||||
sched->listener = EINA_FALSE;
|
||||
sched->futures = NULL;
|
||||
|
||||
EINA_LIST_FREE(entries, entry)
|
||||
{
|
||||
eina_future_cancel(entry->future);
|
||||
eina_value_flush(&entry->value);
|
||||
eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
|
||||
}
|
||||
|
||||
if (schedulers_count > 8)
|
||||
{
|
||||
free(sched);
|
||||
}
|
||||
else
|
||||
{
|
||||
eina_trash_push(&schedulers_trash, sched);
|
||||
schedulers_count++;
|
||||
}
|
||||
}
|
||||
|
||||
static Eina_Future_Schedule_Entry *
|
||||
_efl_event_future_scheduler(Eina_Future_Scheduler *s_sched,
|
||||
Eina_Future_Scheduler_Cb cb,
|
||||
Eina_Future *future,
|
||||
Eina_Value value)
|
||||
{
|
||||
Efl_Future_Scheduler *sched = (Efl_Future_Scheduler *)s_sched;
|
||||
Efl_Future_Scheduler_Entry *entry;
|
||||
|
||||
entry = eina_mempool_malloc(_efl_future_scheduler_entry_mempool, sizeof(*entry));
|
||||
EINA_SAFETY_ON_NULL_RETURN_VAL(entry, NULL);
|
||||
|
||||
entry->base.scheduler = &sched->scheduler;
|
||||
entry->cb = cb;
|
||||
entry->future = future;
|
||||
entry->value = value;
|
||||
|
||||
if (!sched->listener)
|
||||
{
|
||||
efl_event_callback_array_add((Eo *) sched->self, sched->array, sched);
|
||||
sched->listener = EINA_TRUE;
|
||||
}
|
||||
|
||||
sched->futures = eina_list_append(sched->futures, entry);
|
||||
return &entry->base;
|
||||
}
|
||||
|
||||
static void
|
||||
_efl_event_future_recall(Eina_Future_Schedule_Entry *s_entry)
|
||||
{
|
||||
Efl_Future_Scheduler_Entry *entry = (Efl_Future_Scheduler_Entry *)s_entry;
|
||||
Efl_Future_Scheduler *sched;
|
||||
Eina_List *lookup;
|
||||
|
||||
sched = (Efl_Future_Scheduler *) entry->base.scheduler;
|
||||
|
||||
lookup = eina_list_data_find_list(sched->futures, entry);
|
||||
if (!lookup) return;
|
||||
|
||||
sched->futures = eina_list_remove_list(sched->futures, lookup);
|
||||
if (!sched->futures)
|
||||
{
|
||||
Efl_Object_Data *pd = efl_data_scope_get(sched->self, EFL_OBJECT_CLASS);
|
||||
|
||||
_future_scheduler_cleanup(pd);
|
||||
}
|
||||
|
||||
eina_value_flush(&entry->value);
|
||||
eina_mempool_free(_efl_future_scheduler_entry_mempool, entry);
|
||||
}
|
||||
|
||||
EOLIAN static Eina_Future_Scheduler *
|
||||
_efl_object_event_future_scheduler_get(const Eo *obj, Efl_Object_Data *pd, Efl_Callback_Array_Item *array)
|
||||
{
|
||||
Efl_Object_Extension *ext;
|
||||
Efl_Future_Scheduler *sched;
|
||||
unsigned int i;
|
||||
|
||||
if (!array) return NULL;
|
||||
|
||||
ext = _efl_object_extension_need(pd);
|
||||
|
||||
// First lookup for an existing scheduler that match the provided array
|
||||
if (!ext->schedulers) ext->schedulers = eina_hash_pointer_new(_futures_cancel_cb);
|
||||
sched = eina_hash_find(ext->schedulers, &array);
|
||||
if (sched) return &sched->scheduler;
|
||||
|
||||
// Define all the callback in the array to point to our internal callback,
|
||||
// making the array ready to use.
|
||||
for (i = 0; array[i].desc; i++)
|
||||
array[i].func = _futures_dispatch_cb;
|
||||
|
||||
if (schedulers_count)
|
||||
{
|
||||
// Take one out of the trash for faster cycling
|
||||
sched = eina_trash_pop(&schedulers_trash);
|
||||
schedulers_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Need to allocate a new scheduler as none are on standby.
|
||||
sched = calloc(1, sizeof (Efl_Future_Scheduler));
|
||||
}
|
||||
sched->scheduler.schedule = _efl_event_future_scheduler;
|
||||
sched->scheduler.recall = _efl_event_future_recall;
|
||||
sched->array = array;
|
||||
sched->self = obj;
|
||||
|
||||
eina_hash_add(ext->schedulers, &array, sched);
|
||||
|
||||
return &sched->scheduler;
|
||||
}
|
||||
|
||||
EOAPI EFL_FUNC_BODYV_CONST(efl_event_future_scheduler_get,
|
||||
Eina_Future_Scheduler *, 0, EFL_FUNC_CALL(array),
|
||||
Efl_Callback_Array_Item *array);
|
||||
|
||||
static Eina_Bool
|
||||
_cb_desc_match(const Efl_Event_Description *a, const Efl_Event_Description *b, Eina_Bool legacy_compare)
|
||||
{
|
||||
|
@ -2396,12 +2587,17 @@ _efl_object_class_constructor(Efl_Class *klass EINA_UNUSED)
|
|||
eina_mempool_add("chained_mempool", NULL, NULL,
|
||||
sizeof(Efl_Future_Pending), 256);
|
||||
|
||||
_efl_future_scheduler_entry_mempool =
|
||||
eina_mempool_add("chained_mempool", NULL, NULL,
|
||||
sizeof(Efl_Future_Scheduler_Entry), 256);
|
||||
|
||||
_eo_nostep_alloc = !!getenv("EO_NOSTEP_ALLOC");
|
||||
}
|
||||
|
||||
EOLIAN static void
|
||||
_efl_object_class_destructor(Efl_Class *klass EINA_UNUSED)
|
||||
{
|
||||
eina_mempool_del(_efl_future_scheduler_entry_mempool);
|
||||
eina_mempool_del(_efl_pending_future_mempool);
|
||||
eina_mempool_del(_eo_callback_mempool);
|
||||
eina_hash_free(_legacy_events_hash);
|
||||
|
@ -2414,6 +2610,7 @@ _efl_object_class_destructor(Efl_Class *klass EINA_UNUSED)
|
|||
EFL_OBJECT_OP_FUNC(efl_event_callback_array_del, _efl_object_event_callback_array_del), \
|
||||
EFL_OBJECT_OP_FUNC(efl_event_callback_call, _efl_object_event_callback_call), \
|
||||
EFL_OBJECT_OP_FUNC(efl_event_callback_legacy_call, _efl_object_event_callback_legacy_call), \
|
||||
EFL_OBJECT_OP_FUNC(efl_event_future_scheduler_get, _efl_object_event_future_scheduler_get), \
|
||||
EFL_OBJECT_OP_FUNC(efl_dbg_info_get, _efl_object_dbg_info_get), \
|
||||
EFL_OBJECT_OP_FUNC(efl_wref_add, _efl_object_wref_add), \
|
||||
EFL_OBJECT_OP_FUNC(efl_wref_del, _efl_object_wref_del), \
|
||||
|
|
Loading…
Reference in New Issue