*/
typedef void (*Ecore_Cb) (void *data);
+ /**
+ * @typedef Ecore_Data_Cb Ecore_Data_Cb
+ * A callback which is used to return data to the main function
+ */
+ typedef void *(*Ecore_Data_Cb) (void *data);
+
/**
- * @brief Call callback in the main loop.
+ * @brief Call callback asynchronously in the main loop.
+ * @since 1.1.0
*
* @param callback The callback to call in the main loop
* @param data The data to give to that call back
* in the thread, it is owned by the main loop and you callback should take
* care of freeing it if necessary.
*/
- EAPI void ecore_main_loop_thread_safe_call(Ecore_Cb callback, void *data);
+ EAPI void ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data);
+
+ /**
+ * @brief Call callback synchronously in the main loop.
+ * @since 1.1.0
+ *
+ * @param callback The callback to call in the main loop
+ * @param data The data to give to that call back
+ * @return the value returned by the callback in the main loop
+ *
+ * For all call that need to happen in the main loop (most EFL functions do),
+ * this helper function provide the infrastructure needed to do it safely
+ * by avoind dead lock, race condition and properly wake up the main loop.
+ *
+ * Remember this function will block until the callback is executed in the
+ * main loop. It can take time and you have no guaranty about the timeline.
+ */
+ EAPI void *ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data);
/**
* @}
typedef struct _Ecore_Event_Signal_Power Ecore_Event_Signal_Power; /**< Power signal event */
typedef struct _Ecore_Event_Signal_Realtime Ecore_Event_Signal_Realtime; /**< Realtime signal event */
- /**
- * @typedef Ecore_Data_Cb Ecore_Data_Cb
- * A callback which is used to return data to the main function
- */
- typedef void *(*Ecore_Data_Cb) (void *data);
-
/**
* @typedef Ecore_Filter_Cb
* A callback used for filtering events from the main loop.
typedef struct _Ecore_Safe_Call Ecore_Safe_Call;
struct _Ecore_Safe_Call
{
- Ecore_Cb cb;
+ union {
+ Ecore_Cb async;
+ Ecore_Data_Cb sync;
+ } cb;
void *data;
+
+ Eina_Lock m;
+ Eina_Condition c;
+
+ Eina_Bool sync : 1;
};
+static void _ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order);
+static void _thread_safe_cleanup(void *data);
static void _thread_callback(void *data, void *buffer, unsigned int nbyte);
static Eina_List *_thread_cb = NULL;
static Ecore_Pipe *_thread_call = NULL;
* @}
*/
+static int wakeup = 42;
+
EAPI void
-ecore_main_loop_thread_safe_call(Ecore_Cb callback, void *data)
+ecore_main_loop_thread_safe_call_async(Ecore_Cb callback, void *data)
{
Ecore_Safe_Call *order;
- int wakeup = 42;
- Eina_Bool count;
+
+ if (!callback) return ;
if (eina_main_loop_is())
{
order = malloc(sizeof (Ecore_Safe_Call));
if (!order) return ;
- order->cb = callback;
+ order->cb.async = callback;
order->data = data;
+ order->sync = EINA_FALSE;
- eina_lock_take(&_thread_safety);
+ _ecore_main_loop_thread_safe_call(order);
+}
- count = _thread_cb ? 0 : 1;
- _thread_cb = eina_list_append(_thread_cb, order);
- if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
+EAPI void *
+ecore_main_loop_thread_safe_call_sync(Ecore_Data_Cb callback, void *data)
+{
+ Ecore_Safe_Call *order;
+ void *ret;
- eina_lock_release(&_thread_safety);
+ if (!callback) return NULL;
+
+ if (eina_main_loop_is())
+ {
+ return callback(data);
+ }
+
+ order = malloc(sizeof (Ecore_Safe_Call));
+ if (!order) return NULL;
+
+ order->cb.sync = callback;
+ order->data = data;
+ eina_lock_new(&order->m);
+ eina_condition_new(&order->c, &order->m);
+ order->sync = EINA_TRUE;
+
+ _ecore_main_loop_thread_safe_call(order);
+
+ eina_lock_take(&order->m);
+ eina_condition_wait(&order->c);
+ eina_lock_release(&order->m);
+
+ ret = order->data;
+
+ order->sync = EINA_FALSE;
+ order->cb.async = _thread_safe_cleanup;
+ order->data = order;
+
+ _ecore_main_loop_thread_safe_call(order);
+
+ return ret;
}
EAPI void
#endif
+static void
+_ecore_main_loop_thread_safe_call(Ecore_Safe_Call *order)
+{
+ Eina_Bool count;
+
+ eina_lock_take(&_thread_safety);
+
+ count = _thread_cb ? 0 : 1;
+ _thread_cb = eina_list_append(_thread_cb, order);
+ if (count) ecore_pipe_write(_thread_call, &wakeup, sizeof (int));
+
+ eina_lock_release(&_thread_safety);
+}
+
+static void
+_thread_safe_cleanup(void *data)
+{
+ Ecore_Safe_Call *call = data;
+
+ eina_condition_free(&call->c);
+ eina_lock_free(&call->m);
+}
+
static void
_thread_callback(void *data __UNUSED__,
void *buffer __UNUSED__,
EINA_LIST_FREE(callback, call)
{
- call->cb(call->data);
- free(call);
+ if (call->sync)
+ {
+ call->data = call->cb.sync(call->data);
+ eina_condition_broadcast(&call->c);
+ }
+ else
+ {
+ call->cb.async(call->data);
+ free(call);
+ }
}
}