diff --git a/libcef/cef_context.cc b/libcef/cef_context.cc index f43f0acc1..52149c47a 100644 --- a/libcef/cef_context.cc +++ b/libcef/cef_context.cc @@ -129,6 +129,21 @@ void IOT_VisitUrlCookies(const GURL& url, bool includeHttpOnly, IOT_VisitCookies(cookie_monster, list, visitor); } +// Used in multi-threaded message loop mode to observe shutdown of the UI +// thread. +class DestructionObserver : public MessageLoop::DestructionObserver +{ +public: + DestructionObserver(base::WaitableEvent *event) : event_(event) {} + virtual void WillDestroyCurrentMessageLoop() { + MessageLoop::current()->RemoveDestructionObserver(this); + event_->Signal(); + delete this; + } +private: + base::WaitableEvent *event_; +}; + } // anonymous bool CefInitialize(const CefSettings& settings) @@ -475,23 +490,31 @@ void CefContext::Shutdown() shutting_down_ = true; if(settings_.multi_threaded_message_loop) { - // Event that will be used to signal when shutdown is complete. Start in + // Events that will be used to signal when shutdown is complete. Start in // non-signaled mode so that the event will block. - base::WaitableEvent event(false, false); + base::WaitableEvent browser_shutdown_event(false, false); + base::WaitableEvent uithread_shutdown_event(false, false); // Finish shutdown on the UI thread. CefThread::PostTask(CefThread::UI, FROM_HERE, - NewRunnableMethod(this, &CefContext::UIT_FinishShutdown, &event)); + NewRunnableMethod(this, &CefContext::UIT_FinishShutdown, + &browser_shutdown_event, &uithread_shutdown_event)); - // Block until shutdown is complete. - event.Wait(); + // Block until browser shutdown is complete. + browser_shutdown_event.Wait(); + + // Delete the process to destroy the child threads. + process_ = NULL; + + // Block until UI thread shutdown is complete. + uithread_shutdown_event.Wait(); } else { // Finish shutdown on the current thread, which should be the UI thread. - UIT_FinishShutdown(NULL); - } + UIT_FinishShutdown(NULL, NULL); - // Delete the process to destroy the child threads. - process_ = NULL; + // Delete the process to destroy the child threads. + process_ = NULL; + } } bool CefContext::AddBrowser(CefRefPtr browser) @@ -562,7 +585,8 @@ CefRefPtr CefContext::GetBrowserByID(int id) return NULL; } -void CefContext::UIT_FinishShutdown(base::WaitableEvent* event) +void CefContext::UIT_FinishShutdown(base::WaitableEvent* browser_shutdown_event, + base::WaitableEvent* uithread_shutdown_event) { DCHECK(CefThread::CurrentlyOn(CefThread::UI)); @@ -583,6 +607,13 @@ void CefContext::UIT_FinishShutdown(base::WaitableEvent* event) (*it)->UIT_DestroyBrowser(); } - if(event) - event->Signal(); + if (uithread_shutdown_event) { + // The destruction observer will signal the UI thread shutdown event when + // the UI thread has been destroyed. + MessageLoop::current()->AddDestructionObserver( + new DestructionObserver(uithread_shutdown_event)); + + // Signal the browser shutdown event now. + browser_shutdown_event->Signal(); + } } diff --git a/libcef/cef_context.h b/libcef/cef_context.h index a8e9c4d7a..3fec9c089 100644 --- a/libcef/cef_context.h +++ b/libcef/cef_context.h @@ -75,7 +75,8 @@ public: private: // Performs shutdown actions that need to occur on the UI thread before any // threads are destroyed. - void UIT_FinishShutdown(base::WaitableEvent* event); + void UIT_FinishShutdown(base::WaitableEvent* browser_shutdown_event, + base::WaitableEvent* uithread_shutdown_event); // Track context state. bool initialized_; diff --git a/libcef/webwidget_host_win.cc b/libcef/webwidget_host_win.cc index 8d69f954a..fbe5ea7b5 100644 --- a/libcef/webwidget_host_win.cc +++ b/libcef/webwidget_host_win.cc @@ -1040,7 +1040,7 @@ void WebWidgetHost::UpdateInputMethod(HWND view) WebWidgetHost* host = FromWindow(view); - if (!host->input_method_is_active_) + if (!host || !host->input_method_is_active_) return; if (!host->webwidget_ || !CefThread::CurrentlyOn(CefThread::UI))