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 b115546cc2f6977067e1b243d6a1322a1f0d19e4..0f015fe0257da8cd5a80f7c38366761e890fb98c 100755 (executable)
@@ -154,6 +154,7 @@ int real_main(int argc, char* argv[]) {
   }
 #endif
   ewk_shutdown();
+  elm_shutdown();
   elm_exit();
 
   return EXIT_SUCCESS;
index fabbd02f328a3f3c6330b5fc92249abefec65cc9..bdb6d7698d95be46a32d361ce6c86c9fba5b6662 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 915287d44270f9df7778d35c21ec5ecfdcb35b60..89ffdaa39edb13d0135269e975f2c5a3f9bfb5e2 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_;