ecore: stabilize wayland event handling in multithread
authorBoram Park <boram1288.park@samsung.com>
Tue, 7 Nov 2017 07:35:28 +0000 (16:35 +0900)
committerJiyoun Park <jy0703.park@samsung.com>
Mon, 18 Dec 2017 23:17:02 +0000 (08:17 +0900)
Change-Id: I235b5b928f32ffb1c58662dca02754c3ed665523

src/lib/ecore/Ecore_Common.h
src/lib/ecore/ecore_glib.c
src/lib/ecore/ecore_main.c
src/lib/ecore/ecore_private.h

index 6102341..43f97d6 100644 (file)
@@ -229,6 +229,13 @@ EAPI void ecore_main_loop_select_func_set(Ecore_Select_Function func);
  */
 EAPI Ecore_Select_Function ecore_main_loop_select_func_get(void);
 
+//TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+typedef void (*Ecore_Awake_Cb)(void *data);
+
+EAPI Eina_Bool ecore_main_awake_handler_add(Ecore_Awake_Cb func, void *data);
+EAPI void ecore_main_awake_handler_del(Ecore_Awake_Cb func);
+//
+
 /**
  * Requests ecore to integrate GLib's main loop.
  *
index bcc4b30..edc5742 100644 (file)
@@ -168,6 +168,26 @@ _ecore_glib_select__locked(GMainContext   *ctx,
    maxfds = (ecore_fds >= glib_fds) ? ecore_fds : glib_fds;
    ret = _ecore_glib_select_original(maxfds, rfds, wfds, efds, timeout);
 
+   //TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+   /* If select() returns 0, we expact rfds doesn't contains any fds. But even if
+    * select() returns 0, rfds sometimes contains a wayland fd. It makes wrong
+    * behavior.
+    */
+   if (ret > 0)
+     _ecore_main_fdh_mark_active(rfds, wfds, efds);
+
+   /* Once exit from select(), _ecore_main_awake_handler_call() should be called here
+    * to call wl_display_cancel_read() or wl_display_read_events().
+    * If not, deadlock can occur when g_main_context_dispatch calls a user callback
+    * and a user callback calls wl_display_roundtrip which make read_count +2 in one
+    * thread. Moreover, if the main thread sleeps to wait for the some events in
+    * g_main_context_dispatch() or _ecore_idle_enterer_call() function, and if another
+    * thread calls prepare_read(), deadlock also can occur in main thread because main
+    * thread sleeps and it can't call read_event() or cancel_event().
+    */
+   _ecore_main_awake_handler_call();
+   //
+
    ret = _ecore_glib_context_poll_to
        (_ecore_glib_fds, reqfds, rfds, wfds, efds, ret);
 
index 8b7a322..0634eed 100644 (file)
@@ -194,6 +194,12 @@ static void _ecore_main_loop_clear(Eo *obj, Efl_Loop_Data *pd);
 
 // for legacy mainloop only and not other loops
 int in_main_loop = 0;
+
+//TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+static Eina_Bool need_fdh_mark_active = EINA_FALSE;
+static Eina_List *awake_funcs = NULL;
+//
+
 #ifndef USE_G_MAIN_LOOP
 static double t1 = 0.0;
 static double t2 = 0.0;
@@ -553,6 +559,58 @@ _ecore_main_fdh_epoll_mark_active(Eo *obj, Efl_Loop_Data *pd)
 }
 #endif
 
+//TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+int
+_ecore_main_fdh_mark_active(fd_set *rfds, fd_set *wfds, fd_set *exfds)
+{
+   Ecore_Fd_Handler *fdh;
+   Eina_List *l;
+   int ret = 0;
+
+   need_fdh_mark_active = EINA_FALSE;
+
+#ifdef HAVE_EPOLL
+   if (HAVE_EPOLL && epoll_fd >= 0)
+     ret = _ecore_main_fdh_epoll_mark_active();
+   else
+#endif
+     {
+        EINA_INLIST_FOREACH(fd_handlers, fdh)
+          {
+             if (!fdh->delete_me)
+               {
+                  if (FD_ISSET(fdh->fd, rfds))
+                    fdh->read_active = EINA_TRUE;
+                  if (FD_ISSET(fdh->fd, wfds))
+                    fdh->write_active = EINA_TRUE;
+                  if (FD_ISSET(fdh->fd, exfds))
+                    fdh->error_active = EINA_TRUE;
+                  _ecore_try_add_to_call_list(fdh);
+                  if (fdh->read_active || fdh->write_active || fdh->error_active)
+                    ret++;
+               }
+          }
+     }
+   EINA_LIST_FOREACH(file_fd_handlers, l, fdh)
+     {
+        if (!fdh->delete_me)
+          {
+             if (FD_ISSET(fdh->fd, rfds))
+               fdh->read_active = EINA_TRUE;
+             if (FD_ISSET(fdh->fd, wfds))
+               fdh->write_active = EINA_TRUE;
+             if (FD_ISSET(fdh->fd, exfds))
+               fdh->error_active = EINA_TRUE;
+             _ecore_try_add_to_call_list(fdh);
+             if (fdh->read_active || fdh->write_active || fdh->error_active)
+               ret++;
+          }
+     }
+
+   return ret;
+}
+//
+
 #ifdef USE_G_MAIN_LOOP
 static inline int
 _ecore_main_fdh_glib_mark_active(Eo *obj, Efl_Loop_Data *pd)
@@ -1258,6 +1316,57 @@ ecore_main_loop_select_func_get(void)
    return main_loop_select;
 }
 
+//TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+EAPI Eina_Bool
+ecore_main_awake_handler_add(Ecore_Awake_Cb func, void *data)
+{
+   Ecore_Awake_Handler *handler;
+
+   if (!func) return EINA_FALSE;
+
+   handler = calloc(1, sizeof *handler);
+   if (!handler) return EINA_FALSE;
+
+   handler->func = func;
+   handler->data = (void*)data;
+   awake_funcs = eina_list_append(awake_funcs, handler);
+
+   return EINA_TRUE;
+}
+
+EAPI void
+ecore_main_awake_handler_del(Ecore_Awake_Cb func)
+{
+   Ecore_Awake_Handler *handler;
+   Eina_List *l, *ll;
+
+   if (!func) return;
+
+   EINA_LIST_FOREACH_SAFE(awake_funcs, l, ll, handler)
+     {
+        if (handler->func != func)
+          continue;
+
+        awake_funcs = eina_list_remove(awake_funcs, handler);
+        free(handler);
+        break;
+     }
+}
+
+void
+_ecore_main_awake_handler_call(void)
+{
+   Ecore_Awake_Handler *handler;
+   Eina_List *l, *ll;
+
+   EINA_LIST_FOREACH_SAFE(awake_funcs, l, ll, handler)
+     {
+        if (handler->func)
+          handler->func(handler->data);
+     }
+}
+//
+
 Ecore_Fd_Handler *
 _ecore_main_fd_handler_add(Eo                    *obj,
                            Efl_Loop_Data         *pd,
@@ -1612,6 +1721,12 @@ _ecore_main_content_clear(Efl_Loop_Data *pd)
 
    pd->do_quit = 0;
 
+   //TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+   if (awake_funcs)
+     awake_funcs = eina_list_free(awake_funcs);
+   //
+
+
 #ifdef _WIN32
    while (pd->win32_handlers)
      {
@@ -1776,6 +1891,10 @@ _ecore_main_select(Eo *obj, Efl_Loop_Data *pd, double timeout)
      }
    if (_ecore_signal_count_get(obj, pd)) return -1;
 
+   //TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+   need_fdh_mark_active = EINA_TRUE;
+   //
+
    eina_evlog("<RUN", NULL, 0.0, NULL);
    eina_evlog("!SLEEP", NULL, 0.0, t ? "timeout" : "forever");
    if (obj == ML_OBJ)
@@ -1798,6 +1917,8 @@ _ecore_main_select(Eo *obj, Efl_Loop_Data *pd, double timeout)
      }
    if (ret > 0)
      {
+        //TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+        /*
 #ifdef HAVE_EPOLL
         if (pd->epoll_fd >= 0)
           _ecore_main_fdh_epoll_mark_active(obj, pd);
@@ -1831,6 +1952,14 @@ _ecore_main_select(Eo *obj, Efl_Loop_Data *pd, double timeout)
                   _ecore_try_add_to_call_list(obj, pd, fdh);
                }
           }
+        */
+        if (need_fdh_mark_active)
+          {
+             _ecore_main_fdh_mark_active(&rfds, &wfds, &exfds);
+             _ecore_main_awake_handler_call();
+          }
+        //
+
         _ecore_main_fd_handlers_cleanup(obj, pd);
 #ifdef _WIN32
         _ecore_main_win32_handlers_cleanup(obj, pd);
index d9a44ce..08e730f 100644 (file)
@@ -304,6 +304,19 @@ _ecore_main_win32_handler_del(Eo *obj,
                               Ecore_Win32_Handler *win32_handler);
 
 void       _ecore_main_content_clear(Efl_Loop_Data *pd);
+
+//TIZEN_ONLY: ecore: stabilize wayland event handling in multithread
+typedef struct _Ecore_Awake_Handler
+{
+   EINA_INLIST;
+   Ecore_Awake_Cb func;
+   void                *data;
+} Ecore_Awake_Handler;
+
+void _ecore_main_awake_handler_call(void);
+int _ecore_main_fdh_mark_active(fd_set *rfds, fd_set *wfds, fd_set *exfds);
+//
+
 void       _ecore_main_shutdown(void);
 
 #if defined (_WIN32) || defined (__lv2ppu__) || defined (HAVE_EXOTIC)