cedric pushed a commit to branch master.

commit 4d15a0f50f8680de22ea6ced009d666e9ae6be3f
Author: Cedric Bail <[email protected]>
Date:   Thu May 30 15:42:56 2013 +0900

    evas: add infra to block the main loop from evas.
    
    PS: later on, I think we should just move evas to use Ecore infra
    directly to create jobs and sync with the main loop.
---
 src/lib/evas/canvas/evas_async_events.c | 142 +++++++++++++++++++++++++++++++-
 src/lib/evas/include/evas_private.h     |   3 +
 2 files changed, 144 insertions(+), 1 deletion(-)

diff --git a/src/lib/evas/canvas/evas_async_events.c 
b/src/lib/evas/canvas/evas_async_events.c
index 2bab528..c6e9c0e 100644
--- a/src/lib/evas/canvas/evas_async_events.c
+++ b/src/lib/evas/canvas/evas_async_events.c
@@ -12,7 +12,6 @@
 #include "evas_private.h"
 
 typedef struct _Evas_Event_Async       Evas_Event_Async;
-
 struct _Evas_Event_Async
 {
    const void              *target;
@@ -21,6 +20,28 @@ struct _Evas_Event_Async
    Evas_Callback_Type       type;
 };
 
+typedef struct _Evas_Safe_Call Evas_Safe_Call;
+struct _Evas_Safe_Call
+{
+   Eina_Condition c;
+   Eina_Lock      m;
+
+   int            current_id;
+};
+
+static Eina_Lock _thread_mutex;
+static Eina_Condition _thread_cond;
+
+static Eina_Lock _thread_feedback_mutex;
+static Eina_Condition _thread_feedback_cond;
+
+static int _thread_loop = 0;
+
+static Eina_Lock _thread_id_lock;
+static int _thread_id = -1;
+static int _thread_id_max = 0;
+static int _thread_id_update = 0;
+
 static int _fd_write = -1;
 static int _fd_read = -1;
 static pid_t _fd_pid = 0;
@@ -81,6 +102,14 @@ evas_async_events_init(void)
    eina_lock_new(&async_lock);
    eina_inarray_step_set(&async_queue, sizeof (Eina_Inarray), sizeof 
(Evas_Event_Async), 16);
 
+   eina_lock_new(&_thread_mutex);
+   eina_condition_new(&_thread_cond, &_thread_mutex);
+
+   eina_lock_new(&_thread_feedback_mutex);
+   eina_condition_new(&_thread_feedback_cond, &_thread_feedback_mutex);
+
+   eina_lock_new(&_thread_id_lock);
+
    return _init_evas_event;
 }
 
@@ -90,6 +119,12 @@ evas_async_events_shutdown(void)
    _init_evas_event--;
    if (_init_evas_event > 0) return _init_evas_event;
 
+   eina_condition_free(&_thread_cond);
+   eina_lock_free(&_thread_mutex);
+   eina_condition_free(&_thread_feedback_cond);
+   eina_lock_free(&_thread_feedback_mutex);
+   eina_lock_free(&_thread_id_lock);
+
    eina_lock_free(&async_lock);
    eina_inarray_flush(&async_queue);
    free(async_queue_cache);
@@ -284,3 +319,108 @@ evas_async_events_put(const void *target, 
Evas_Callback_Type type, void *event_i
 
    return ret;
 }
+
+static void
+_evas_thread_main_loop_lock(void *target EINA_UNUSED,
+                            Evas_Callback_Type type EINA_UNUSED,
+                            void *event_info)
+{
+   Evas_Safe_Call *call = event_info;
+
+   eina_lock_take(&_thread_mutex);
+
+   eina_lock_take(&call->m);
+   _thread_id = call->current_id;
+   eina_condition_broadcast(&call->c);
+   eina_lock_release(&call->m);
+
+   while (_thread_id_update != _thread_id)
+     eina_condition_wait(&_thread_cond);
+   eina_lock_release(&_thread_mutex);
+
+   eina_main_loop_define();
+
+   eina_lock_take(&_thread_feedback_mutex);
+
+   _thread_id = -1;
+
+   eina_condition_broadcast(&_thread_feedback_cond);
+   eina_lock_release(&_thread_feedback_mutex);
+
+   eina_condition_free(&call->c);
+   eina_lock_free(&call->m);
+   free(call);
+}                           
+
+EAPI int
+evas_thread_main_loop_begin(void)
+{
+   Evas_Safe_Call *order;
+
+   if (eina_main_loop_is())
+     {
+        return ++_thread_loop;
+     }
+
+   order = malloc(sizeof (Evas_Safe_Call));
+   if (!order) return -1;
+
+   eina_lock_take(&_thread_id_lock);
+   order->current_id = ++_thread_id_max;
+   if (order->current_id < 0)
+     {
+        _thread_id_max = 0;
+        order->current_id = ++_thread_id_max;
+     }
+   eina_lock_release(&_thread_id_lock);
+
+   eina_lock_new(&order->m);
+   eina_condition_new(&order->c, &order->m);
+
+   evas_async_events_put(NULL, 0, order, _evas_thread_main_loop_lock);
+
+   eina_lock_take(&order->m);
+   while (order->current_id != _thread_id)
+     eina_condition_wait(&order->c);
+   eina_lock_release(&order->m);
+
+   eina_main_loop_define();
+
+   _thread_loop = 1;
+
+   return _thread_loop;
+}
+
+EAPI int
+evas_thread_main_loop_end(void)
+{
+   int current_id;
+
+   if (_thread_loop == 0)
+     abort();
+
+   /* until we unlock the main loop, this thread has the main loop id */
+   if (!eina_main_loop_is())
+     {
+        ERR("Not in a locked thread !");
+        return -1;
+     }
+
+   _thread_loop--;
+   if (_thread_loop > 0)
+     return _thread_loop;
+
+   current_id = _thread_id;
+
+   eina_lock_take(&_thread_mutex);
+   _thread_id_update = _thread_id;
+   eina_condition_broadcast(&_thread_cond);
+   eina_lock_release(&_thread_mutex);
+
+   eina_lock_take(&_thread_feedback_mutex);
+   while (current_id == _thread_id && _thread_id != -1)
+     eina_condition_wait(&_thread_feedback_cond);
+   eina_lock_release(&_thread_feedback_mutex);
+
+   return 0;
+}
diff --git a/src/lib/evas/include/evas_private.h 
b/src/lib/evas/include/evas_private.h
index 9b0dc12..d05d19b 100644
--- a/src/lib/evas/include/evas_private.h
+++ b/src/lib/evas/include/evas_private.h
@@ -1205,6 +1205,9 @@ int evas_async_events_init(void);
 int evas_async_events_shutdown(void);
 int evas_async_target_del(const void *target);
 
+EAPI int evas_thread_main_loop_begin(void);
+EAPI int evas_thread_main_loop_end(void);
+
 void _evas_preload_thread_init(void);
 void _evas_preload_thread_shutdown(void);
 Evas_Preload_Pthread *evas_preload_thread_run(void (*func_heavy)(void *data),

-- 

------------------------------------------------------------------------------
How ServiceNow helps IT people transform IT departments:
1. A cloud service to automate IT design, transition and operations
2. Dashboards that offer high-level views of enterprise services
3. A single system of record for all IT processes
http://p.sf.net/sfu/servicenow-d2d-j

Reply via email to