| Index: content/child/child_thread_impl.cc
|
| diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
|
| index cc13a5bf0a566b683a331b7e35d361f45cf18fe7..08d41359df3584c6e54351701610b4d96c63849b 100644
|
| --- a/content/child/child_thread_impl.cc
|
| +++ b/content/child/child_thread_impl.cc
|
| @@ -59,6 +59,10 @@
|
| #include "ipc/ipc_sync_message_filter.h"
|
| #include "ipc/mojo/ipc_channel_mojo.h"
|
|
|
| +#if defined(OS_ANDROID)
|
| +#include "base/thread_task_runner_handle.h"
|
| +#endif
|
| +
|
| #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
|
| #include "third_party/tcmalloc/chromium/src/gperftools/heap-profiler.h"
|
| #endif
|
| @@ -161,40 +165,57 @@ class SuicideOnChannelErrorFilter : public IPC::MessageFilter {
|
| #endif // OS(POSIX)
|
|
|
| #if defined(OS_ANDROID)
|
| -ChildThreadImpl* g_child_thread = NULL;
|
| -bool g_child_thread_initialized = false;
|
| +// A class that allows for triggering a clean shutdown from another
|
| +// thread through draining the main thread's msg loop.
|
| +class QuitClosure {
|
| + public:
|
| + QuitClosure();
|
| + ~QuitClosure();
|
|
|
| -// A lock protects g_child_thread.
|
| -base::LazyInstance<base::Lock>::Leaky g_lazy_child_thread_lock =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| + void BindToMainThread();
|
| + void PostQuitFromNonMainThread();
|
|
|
| -// base::ConditionVariable has an explicit constructor that takes
|
| -// a base::Lock pointer as parameter. The base::DefaultLazyInstanceTraits
|
| -// doesn't handle the case. Thus, we need our own class here.
|
| -struct CondVarLazyInstanceTraits {
|
| - static const bool kRegisterOnExit = false;
|
| -#ifndef NDEBUG
|
| - static const bool kAllowedToAccessOnNonjoinableThread = true;
|
| -#endif
|
| + private:
|
| + static void PostClosure(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
|
| + base::Closure closure);
|
|
|
| - static base::ConditionVariable* New(void* instance) {
|
| - return new (instance) base::ConditionVariable(
|
| - g_lazy_child_thread_lock.Pointer());
|
| - }
|
| - static void Delete(base::ConditionVariable* instance) {
|
| - instance->~ConditionVariable();
|
| - }
|
| + base::Lock lock_;
|
| + base::ConditionVariable cond_var_;
|
| + base::Closure closure_;
|
| };
|
|
|
| -// A condition variable that synchronize threads initializing and waiting
|
| -// for g_child_thread.
|
| -base::LazyInstance<base::ConditionVariable, CondVarLazyInstanceTraits>
|
| - g_lazy_child_thread_cv = LAZY_INSTANCE_INITIALIZER;
|
| +QuitClosure::QuitClosure() : cond_var_(&lock_) {
|
| +}
|
|
|
| -void QuitMainThreadMessageLoop() {
|
| - base::MessageLoop::current()->Quit();
|
| +QuitClosure::~QuitClosure() {
|
| +}
|
| +
|
| +void QuitClosure::PostClosure(
|
| + const scoped_refptr<base::SingleThreadTaskRunner>& task_runner,
|
| + base::Closure closure) {
|
| + task_runner->PostTask(FROM_HERE, closure);
|
| +}
|
| +
|
| +void QuitClosure::BindToMainThread() {
|
| + base::AutoLock lock(lock_);
|
| + scoped_refptr<base::SingleThreadTaskRunner> task_runner(
|
| + base::ThreadTaskRunnerHandle::Get());
|
| + base::Closure quit_closure =
|
| + base::MessageLoop::current()->QuitWhenIdleClosure();
|
| + closure_ = base::Bind(&QuitClosure::PostClosure, task_runner, quit_closure);
|
| + cond_var_.Signal();
|
| +}
|
| +
|
| +void QuitClosure::PostQuitFromNonMainThread() {
|
| + base::AutoLock lock(lock_);
|
| + while (closure_.is_null())
|
| + cond_var_.Wait();
|
| +
|
| + closure_.Run();
|
| }
|
|
|
| +base::LazyInstance<QuitClosure> g_quit_closure = LAZY_INSTANCE_INITIALIZER;
|
| #endif
|
|
|
| } // namespace
|
| @@ -402,14 +423,7 @@ void ChildThreadImpl::Init(const Options& options) {
|
| base::TimeDelta::FromSeconds(connection_timeout));
|
|
|
| #if defined(OS_ANDROID)
|
| - {
|
| - base::AutoLock lock(g_lazy_child_thread_lock.Get());
|
| - g_child_thread = this;
|
| - g_child_thread_initialized = true;
|
| - }
|
| - // Signalling without locking is fine here because only
|
| - // one thread can wait on the condition variable.
|
| - g_lazy_child_thread_cv.Get().Signal();
|
| + g_quit_closure.Get().BindToMainThread();
|
| #endif
|
|
|
| #if defined(TCMALLOC_TRACE_MEMORY_SUPPORTED)
|
| @@ -435,13 +449,6 @@ ChildThreadImpl::~ChildThreadImpl() {
|
| // |thread_safe_sender_| is still valid.
|
| discardable_shared_memory_manager_.reset();
|
|
|
| -#if defined(OS_ANDROID)
|
| - {
|
| - base::AutoLock lock(g_lazy_child_thread_lock.Get());
|
| - g_child_thread = nullptr;
|
| - }
|
| -#endif
|
| -
|
| #ifdef IPC_MESSAGE_LOG_ENABLED
|
| IPC::Logging::GetInstance()->SetIPCSender(NULL);
|
| #endif
|
| @@ -636,20 +643,7 @@ ChildThreadImpl* ChildThreadImpl::current() {
|
| void ChildThreadImpl::ShutdownThread() {
|
| DCHECK(!ChildThreadImpl::current()) <<
|
| "this method should NOT be called from child thread itself";
|
| - {
|
| - base::AutoLock lock(g_lazy_child_thread_lock.Get());
|
| - while (!g_child_thread_initialized)
|
| - g_lazy_child_thread_cv.Get().Wait();
|
| -
|
| - // g_child_thread may already have been destructed while we didn't hold the
|
| - // lock.
|
| - if (!g_child_thread)
|
| - return;
|
| -
|
| - DCHECK_NE(base::MessageLoop::current(), g_child_thread->message_loop());
|
| - g_child_thread->message_loop()->PostTask(
|
| - FROM_HERE, base::Bind(&QuitMainThreadMessageLoop));
|
| - }
|
| + g_quit_closure.Get().PostQuitFromNonMainThread();
|
| }
|
| #endif
|
|
|
|
|