Chromium Code Reviews| Index: ipc/mojo/scoped_ipc_support.cc |
| diff --git a/ipc/mojo/scoped_ipc_support.cc b/ipc/mojo/scoped_ipc_support.cc |
| index fafc9c2614b8a7dc51d03d7ee6bbb51f1d62c2c5..bb07240c7cf8b6848c7e64b6b01c283f789e3839 100644 |
| --- a/ipc/mojo/scoped_ipc_support.cc |
| +++ b/ipc/mojo/scoped_ipc_support.cc |
| @@ -7,6 +7,7 @@ |
| #include "base/bind.h" |
| #include "base/lazy_instance.h" |
| #include "base/logging.h" |
| +#include "base/memory/weak_ptr.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/synchronization/condition_variable.h" |
| #include "base/synchronization/lock.h" |
| @@ -22,80 +23,149 @@ class IPCSupportInitializer : public mojo::embedder::ProcessDelegate { |
| public: |
| IPCSupportInitializer() |
| : init_count_(0), |
| - shutting_down_(false) { |
| - } |
| - |
| - ~IPCSupportInitializer() override {} |
| + shutting_down_(false), |
| + was_shut_down_(false), |
| + observer_(nullptr), |
| + weak_factory_(this) {} |
| - void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner) { |
| - base::AutoLock locker(lock_); |
| - DCHECK((init_count_ == 0 && !io_thread_task_runner_) || |
| - io_thread_task_runner_ == io_thread_task_runner); |
| - |
| - if (shutting_down_) { |
| - // If reinitialized before a pending shutdown task is executed, we |
| - // effectively cancel the shutdown task. |
| - DCHECK(init_count_ == 1); |
| - shutting_down_ = false; |
| - return; |
| - } |
| + ~IPCSupportInitializer() override { DCHECK(!observer_); } |
| - init_count_++; |
| - if (init_count_ == 1) { |
| - io_thread_task_runner_ = io_thread_task_runner; |
| - mojo::embedder::InitIPCSupport(mojo::embedder::ProcessType::NONE, |
| - io_thread_task_runner_, |
| - this, io_thread_task_runner_, |
| - mojo::embedder::ScopedPlatformHandle()); |
| - } |
| - } |
| + void Init(scoped_refptr<base::TaskRunner> io_thread_task_runner); |
| + void ShutDown(); |
| - void ShutDown() { |
| - base::AutoLock locker(lock_); |
| - DCHECK(init_count_ > 0); |
| - DCHECK(!shutting_down_); |
| + // Forces the initializer to shut down even if scopers are still holding it. |
| + void ForceShutdown(); |
| - if (init_count_ > 1) { |
| - init_count_--; |
| - return; |
| + private: |
| + // This watches for destruction of the MessageLoop that IPCSupportInitializer |
| + // uses for IO, and guarantees that the initializer is shut down if it still |
| + // exists when the loop is being destroyed. |
| + class MessageLoopObserver : public base::MessageLoop::DestructionObserver { |
| + public: |
| + MessageLoopObserver(base::WeakPtr<IPCSupportInitializer> weak_initializer) |
| + : weak_initializer_(weak_initializer) {} |
| + |
| + ~MessageLoopObserver() override { |
| + base::MessageLoop::current()->RemoveDestructionObserver(this); |
| } |
| - shutting_down_ = true; |
| - if (base::MessageLoop::current() && |
| - base::MessageLoop::current()->task_runner() == io_thread_task_runner_) { |
| - base::AutoUnlock unlocker_(lock_); |
| - ShutDownOnIOThread(); |
| - } else { |
| - io_thread_task_runner_->PostTask( |
| - FROM_HERE, |
| - base::Bind(&IPCSupportInitializer::ShutDownOnIOThread, |
| - base::Unretained(this))); |
| + private: |
| + // base::MessageLoop::DestructionObserver: |
| + void WillDestroyCurrentMessageLoop() override { |
| + if (weak_initializer_) |
|
jam
2015/05/11 15:53:25
you can only check a weak pointer on the thread wh
Ken Rockot(use gerrit already)
2015/05/11 16:11:53
Fixed.
|
| + weak_initializer_->ForceShutdown(); |
| } |
| - } |
| - private: |
| - void ShutDownOnIOThread() { |
| - base::AutoLock locker(lock_); |
| - if (shutting_down_) { |
| - DCHECK(init_count_ == 1); |
| - mojo::embedder::ShutdownIPCSupportOnIOThread(); |
| - init_count_ = 0; |
| - shutting_down_ = false; |
| - io_thread_task_runner_ = nullptr; |
| - } |
| - } |
| + base::WeakPtr<IPCSupportInitializer> weak_initializer_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver); |
| + }; |
| + void ShutDownOnIOThread(); |
| + |
| + // mojo::embedder::ProcessDelegate: |
| void OnShutdownComplete() override {} |
| + static void WatchMessageLoopOnIOThread(MessageLoopObserver* observer); |
| + |
| base::Lock lock_; |
| size_t init_count_; |
| bool shutting_down_; |
| + // This is used to track whether shutdown has occurred yet, since we can be |
| + // shut down by either the scoper or IO MessageLoop destruction. |
| + bool was_shut_down_; |
| + |
| + // The message loop destruction observer we have watching our IO loop. This |
| + // is created on the initializer's own thread but is used and destroyed on the |
| + // IO thread. |
| + MessageLoopObserver* observer_; |
| + |
| scoped_refptr<base::TaskRunner> io_thread_task_runner_; |
| + base::WeakPtrFactory<IPCSupportInitializer> weak_factory_; |
| + |
| DISALLOW_COPY_AND_ASSIGN(IPCSupportInitializer); |
| }; |
| +void IPCSupportInitializer::Init( |
| + scoped_refptr<base::TaskRunner> io_thread_task_runner) { |
| + base::AutoLock locker(lock_); |
| + DCHECK((init_count_ == 0 && !io_thread_task_runner_) || |
| + io_thread_task_runner_ == io_thread_task_runner); |
| + |
| + if (shutting_down_) { |
| + // If reinitialized before a pending shutdown task is executed, we |
| + // effectively cancel the shutdown task. |
| + DCHECK(init_count_ == 1); |
| + shutting_down_ = false; |
| + return; |
| + } |
| + |
| + init_count_++; |
| + if (init_count_ == 1) { |
| + was_shut_down_ = false; |
| + observer_ = new MessageLoopObserver(weak_factory_.GetWeakPtr()); |
| + io_thread_task_runner_ = io_thread_task_runner; |
| + io_thread_task_runner_->PostTask( |
| + FROM_HERE, base::Bind(&WatchMessageLoopOnIOThread, observer_)); |
| + mojo::embedder::InitIPCSupport( |
| + mojo::embedder::ProcessType::NONE, io_thread_task_runner_, this, |
| + io_thread_task_runner_, mojo::embedder::ScopedPlatformHandle()); |
| + } |
| +} |
| + |
| +void IPCSupportInitializer::ShutDown() { |
| + { |
| + base::AutoLock locker(lock_); |
| + if (shutting_down_ || was_shut_down_) |
| + return; |
| + DCHECK(init_count_ > 0); |
| + if (init_count_ > 1) { |
| + init_count_--; |
| + return; |
| + } |
| + } |
| + ForceShutdown(); |
| +} |
| + |
| +void IPCSupportInitializer::ForceShutdown() { |
| + base::AutoLock locker(lock_); |
| + if (shutting_down_ || was_shut_down_) |
| + return; |
| + shutting_down_ = true; |
| + if (base::MessageLoop::current() && |
| + base::MessageLoop::current()->task_runner() == io_thread_task_runner_) { |
| + base::AutoUnlock unlocker_(lock_); |
| + ShutDownOnIOThread(); |
| + } else { |
| + io_thread_task_runner_->PostTask( |
| + FROM_HERE, base::Bind(&IPCSupportInitializer::ShutDownOnIOThread, |
| + base::Unretained(this))); |
| + } |
| +} |
| + |
| +void IPCSupportInitializer::ShutDownOnIOThread() { |
| + base::AutoLock locker(lock_); |
| + if (shutting_down_ && !was_shut_down_) { |
| + mojo::embedder::ShutdownIPCSupportOnIOThread(); |
| + init_count_ = 0; |
| + shutting_down_ = false; |
| + io_thread_task_runner_ = nullptr; |
| + was_shut_down_ = true; |
| + if (observer_) { |
| + delete observer_; |
| + observer_ = nullptr; |
| + } |
| + } |
| +} |
| + |
| +// static |
| +void IPCSupportInitializer::WatchMessageLoopOnIOThread( |
| + MessageLoopObserver* observer) { |
| + base::MessageLoop::current()->AddDestructionObserver(observer); |
| +} |
| + |
| base::LazyInstance<IPCSupportInitializer>::Leaky ipc_support_initializer; |
| } // namespace |