Fix the terminate routine to avoid deadlock in ewk_shutdown 41/106741/3
authorYoungcheol Kang <ychul.kang@samsung.com>
Thu, 22 Dec 2016 16:12:55 +0000 (01:12 +0900)
committerYoungcheol Kang <ychul.kang@samsung.com>
Fri, 23 Dec 2016 00:43:33 +0000 (09:43 +0900)
If ewk_shutdown is called when renderer thread works,
the deadlock happens while exiting the web application.

In order to prevent this deadlock problem, crosswalk don't
terminate the web application directly, it terminate
the web application using ewk_view_page_close API.

By using ewk_view_page_close API, crosswalk can receive
the callback that renderer thread was terminated.
After then crosswalk call the ewk_shutdown.

Bug: http://suprem.sec.samsung.net/jira/browse/TSAM-11982

Change-Id: I0d6279be0a03835ab58e2bf21443dcbba286f823
Signed-off-by: Youngcheol Kang <ychul.kang@samsung.com>
runtime/browser/runtime_process.cc
runtime/browser/web_application.cc
runtime/browser/web_application.h

index b115546..0f015fe 100755 (executable)
@@ -154,6 +154,7 @@ int real_main(int argc, char* argv[]) {
   }
 #endif
   ewk_shutdown();
+  elm_shutdown();
   elm_exit();
 
   return EXIT_SUCCESS;
index fabbd02..bdb6d76 100755 (executable)
@@ -173,8 +173,17 @@ static void InitializeNotificationCallback(Ewk_Context* ewk_context,
 
 static Eina_Bool ExitAppIdlerCallback(void* data) {
   WebApplication* app = static_cast<WebApplication*>(data);
-  if (app)
-    app->Terminate();
+
+  if (app) {
+    std::list<WebView*> vstack = app->view_stack();
+    auto it = vstack.begin();
+
+    for (; it != vstack.end(); ++it) {
+      vstack.front()->SetVisibility(false);
+      ewk_view_page_close((*it)->evas_object());
+    }
+  }
+
   return ECORE_CALLBACK_CANCEL;
 }
 
@@ -238,6 +247,7 @@ WebApplication::WebApplication(
       ewk_context_(
           ewk_context_new_with_injected_bundle_path(INJECTED_BUNDLE_PATH)),
       has_ownership_of_ewk_context_(true),
+      is_terminated_by_callback_(false),
       window_(window),
       appid_(app_data->app_id()),
       app_data_(app_data),
@@ -255,6 +265,7 @@ WebApplication::WebApplication(
       verbose_mode_(false),
       ewk_context_(context),
       has_ownership_of_ewk_context_(false),
+      is_terminated_by_callback_(false),
       window_(window),
       appid_(app_data->app_id()),
       app_data_(app_data),
@@ -567,6 +578,7 @@ void WebApplication::Suspend() {
 }
 
 void WebApplication::Terminate() {
+  is_terminated_by_callback_ = false;
   if (terminator_) {
     terminator_();
   } else {
@@ -586,28 +598,35 @@ void WebApplication::OnCreatedNewWebView(WebView* /*view*/, WebView* new_view) {
 }
 
 void WebApplication::RemoveWebViewFromStack(WebView* view) {
-  if (view_stack_.size() == 0) return;
+  if (view_stack_.size() == 0) {
+    if (is_terminated_by_callback_) {
+      Terminate();
+    } else {
+      return;
+    }
+  }
 
   WebView* current = view_stack_.front();
   if (current == view) {
-    // In order to prevent the crash issue due to the callback
-    // which occur after destroying WebApplication class,
-    // we have to set the 'SetEventListener' to NULL.
-    view->SetEventListener(NULL);
     view_stack_.pop_front();
   } else {
     auto found = std::find(view_stack_.begin(), view_stack_.end(), view);
     if (found != view_stack_.end()) {
-      // In order to prevent the crash issue due to the callback
-      // which occur after destroying WebApplication class,
-      // we have to set the 'SetEventListener' to NULL.
-      view->SetEventListener(NULL);
       view_stack_.erase(found);
     }
   }
 
   if (view_stack_.size() == 0) {
-    Terminate();
+    if (is_terminated_by_callback_) {
+      // In order to prevent the crash issue due to the callback
+      // which occur after destroying WebApplication class,
+      // we have to set the 'SetEventListener' to NULL.
+      view->SetEventListener(NULL);
+      Terminate();
+    } else {
+      ewk_view_page_close(view->evas_object());
+      return;
+    }
   } else if (current != view_stack_.front()) {
     view_stack_.front()->SetVisibility(true);
     window_->SetContent(view_stack_.front()->evas_object());
@@ -623,6 +642,7 @@ void WebApplication::RemoveWebViewFromStack(WebView* view) {
 }
 
 void WebApplication::OnClosedWebView(WebView* view) {
+    is_terminated_by_callback_ = true;
     RemoveWebViewFromStack(view);
 }
 
index 915287d..89ffdaa 100755 (executable)
@@ -57,6 +57,7 @@ class WebApplication : public WebView::EventListener {
     terminator_ = terminator;
   }
   bool launched() const { return launched_; }
+  std::list<WebView*> view_stack() const { return view_stack_; }
 
   virtual void OnCreatedNewWebView(WebView* view, WebView* new_view);
   virtual void OnClosedWebView(WebView* view);
@@ -121,6 +122,7 @@ class WebApplication : public WebView::EventListener {
   bool lang_changed_mode_;
   Ewk_Context* ewk_context_;
   bool has_ownership_of_ewk_context_;
+  bool is_terminated_by_callback_;
   NativeWindow* window_;
   std::string appid_;
   std::string app_data_path_;