When running in single-process mode wait for the render thread to stop before shutting down the context (issue #570).

git-svn-id: https://chromiumembedded.googlecode.com/svn/trunk@978 5089003a-bbd8-11dd-ad1f-f1f9622dbc98
This commit is contained in:
Marshall Greenblatt 2013-01-06 16:39:25 +00:00
parent 10ed5d699f
commit a463095bd9
3 changed files with 46 additions and 2 deletions

View File

@ -13,13 +13,16 @@
#include "libcef/browser/thread_util.h" #include "libcef/browser/thread_util.h"
#include "libcef/browser/trace_subscriber.h" #include "libcef/browser/trace_subscriber.h"
#include "libcef/common/main_delegate.h" #include "libcef/common/main_delegate.h"
#include "libcef/renderer/content_renderer_client.h"
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/file_util.h" #include "base/file_util.h"
#include "base/synchronization/waitable_event.h" #include "base/synchronization/waitable_event.h"
#include "base/threading/platform_thread.h"
#include "content/public/app/content_main.h" #include "content/public/app/content_main.h"
#include "content/public/app/content_main_runner.h" #include "content/public/app/content_main_runner.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/content_switches.h" #include "content/public/common/content_switches.h"
#include "ui/base/ui_base_switches.h" #include "ui/base/ui_base_switches.h"
@ -341,6 +344,14 @@ void CefContext::FinishShutdownOnUIThread(
} }
void CefContext::FinalizeShutdown() { void CefContext::FinalizeShutdown() {
if (content::RenderProcessHost::run_renderer_in_process()) {
// When running in single-process mode wait for the render thread to stop
// before continuing shutdown. Spin instead of using base::WaitableEvent
// because calling Wait() is not allowed on the UI thread.
while (!CefContentRendererClient::Get()->IsRenderThreadShutdownComplete())
base::PlatformThread::YieldCurrentThread();
}
// Shut down the browser runner or UI thread. // Shut down the browser runner or UI thread.
main_delegate_->ShutdownBrowser(); main_delegate_->ShutdownBrowser();

View File

@ -30,6 +30,7 @@ MSVC_POP_WARNING();
#include "base/path_service.h" #include "base/path_service.h"
#include "base/string_number_conversions.h" #include "base/string_number_conversions.h"
#include "content/common/child_thread.h" #include "content/common/child_thread.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view.h"
#include "ipc/ipc_sync_channel.h" #include "ipc/ipc_sync_channel.h"
@ -208,7 +209,8 @@ struct CefContentRendererClient::SchemeInfo {
CefContentRendererClient::CefContentRendererClient() CefContentRendererClient::CefContentRendererClient()
: devtools_agent_count_(0), : devtools_agent_count_(0),
uncaught_exception_stack_size_(0) { uncaught_exception_stack_size_(0),
render_thread_shutdown_complete_(false) {
} }
CefContentRendererClient::~CefContentRendererClient() { CefContentRendererClient::~CefContentRendererClient() {
@ -411,6 +413,12 @@ void CefContentRendererClient::RemoveWorkerTaskRunner(int worker_id) {
worker_task_runner_map_.erase(it); worker_task_runner_map_.erase(it);
} }
bool CefContentRendererClient::IsRenderThreadShutdownComplete() {
DCHECK(content::RenderProcessHost::run_renderer_in_process());
base::AutoLock lock_scope(render_thread_shutdown_lock_);
return render_thread_shutdown_complete_;
}
void CefContentRendererClient::RenderThreadStarted() { void CefContentRendererClient::RenderThreadStarted() {
render_task_runner_ = base::MessageLoopProxy::current(); render_task_runner_ = base::MessageLoopProxy::current();
observer_.reset(new CefRenderProcessObserver()); observer_.reset(new CefRenderProcessObserver());
@ -419,6 +427,12 @@ void CefContentRendererClient::RenderThreadStarted() {
thread->AddObserver(observer_.get()); thread->AddObserver(observer_.get());
thread->GetChannel()->AddFilter(new CefRenderMessageFilter); thread->GetChannel()->AddFilter(new CefRenderMessageFilter);
if (content::RenderProcessHost::run_renderer_in_process()) {
// When running in single-process mode register as a destruction observer
// on the render thread's MessageLoop.
MessageLoop::current()->AddDestructionObserver(this);
}
// Note that under Linux, the media library will normally already have // Note that under Linux, the media library will normally already have
// been initialized by the Zygote before this instance became a Renderer. // been initialized by the Zygote before this instance became a Renderer.
FilePath media_path; FilePath media_path;
@ -592,3 +606,9 @@ void CefContentRendererClient::WillReleaseScriptContext(
CefV8ReleaseContext(context); CefV8ReleaseContext(context);
} }
void CefContentRendererClient::WillDestroyCurrentMessageLoop() {
DCHECK(content::RenderProcessHost::run_renderer_in_process());
base::AutoLock lock_scope(render_thread_shutdown_lock_);
render_thread_shutdown_complete_ = true;
}

View File

@ -16,6 +16,7 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h" #include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "base/sequenced_task_runner.h" #include "base/sequenced_task_runner.h"
#include "content/public/renderer/content_renderer_client.h" #include "content/public/renderer/content_renderer_client.h"
@ -23,7 +24,8 @@ class CefRenderProcessObserver;
class CefWebWorkerScriptObserver; class CefWebWorkerScriptObserver;
struct Cef_CrossOriginWhiteListEntry_Params; struct Cef_CrossOriginWhiteListEntry_Params;
class CefContentRendererClient : public content::ContentRendererClient { class CefContentRendererClient : public content::ContentRendererClient,
public MessageLoop::DestructionObserver {
public: public:
CefContentRendererClient(); CefContentRendererClient();
virtual ~CefContentRendererClient(); virtual ~CefContentRendererClient();
@ -72,6 +74,9 @@ class CefContentRendererClient : public content::ContentRendererClient {
// Remove the task runner associated with the specified worker ID. // Remove the task runner associated with the specified worker ID.
void RemoveWorkerTaskRunner(int worker_id); void RemoveWorkerTaskRunner(int worker_id);
// Used in single-process mode to test when the RenderThread has stopped.
bool IsRenderThreadShutdownComplete();
private: private:
// ContentRendererClient implementation. // ContentRendererClient implementation.
virtual void RenderThreadStarted() OVERRIDE; virtual void RenderThreadStarted() OVERRIDE;
@ -89,6 +94,9 @@ class CefContentRendererClient : public content::ContentRendererClient {
v8::Handle<v8::Context> context, v8::Handle<v8::Context> context,
int world_id) OVERRIDE; int world_id) OVERRIDE;
// MessageLoop::DestructionObserver implementation.
virtual void WillDestroyCurrentMessageLoop() OVERRIDE;
scoped_refptr<base::SequencedTaskRunner> render_task_runner_; scoped_refptr<base::SequencedTaskRunner> render_task_runner_;
scoped_ptr<CefRenderProcessObserver> observer_; scoped_ptr<CefRenderProcessObserver> observer_;
scoped_ptr<CefWebWorkerScriptObserver> worker_script_observer_; scoped_ptr<CefWebWorkerScriptObserver> worker_script_observer_;
@ -115,6 +123,11 @@ class CefContentRendererClient : public content::ContentRendererClient {
WorkerTaskRunnerMap; WorkerTaskRunnerMap;
WorkerTaskRunnerMap worker_task_runner_map_; WorkerTaskRunnerMap worker_task_runner_map_;
base::Lock worker_task_runner_lock_; base::Lock worker_task_runner_lock_;
// Used in single-process mode to test when the RenderThread has stopped.
// Access must be protected by |render_thread_shutdown_lock_|.
bool render_thread_shutdown_complete_;
base::Lock render_thread_shutdown_lock_;
}; };
#endif // CEF_LIBCEF_RENDERER_CONTENT_RENDERER_CLIENT_H_ #endif // CEF_LIBCEF_RENDERER_CONTENT_RENDERER_CLIENT_H_