| Index: base/run_loop.cc
|
| diff --git a/base/run_loop.cc b/base/run_loop.cc
|
| index b7df5b23d8d72f737c5c6f468c508ec12ade8fd9..b87688d547b348b6fd2fc4aa8583153b7a123aa8 100644
|
| --- a/base/run_loop.cc
|
| +++ b/base/run_loop.cc
|
| @@ -4,12 +4,9 @@
|
|
|
| #include "base/run_loop.h"
|
|
|
| -#include <stack>
|
| -
|
| #include "base/bind.h"
|
| #include "base/lazy_instance.h"
|
| -#include "base/observer_list.h"
|
| -#include "base/threading/thread_local_storage.h"
|
| +#include "base/threading/thread_local.h"
|
| #include "base/tracked_objects.h"
|
| #include "build/build_config.h"
|
|
|
| @@ -17,74 +14,58 @@ namespace base {
|
|
|
| namespace {
|
|
|
| -class ThreadLocalRunLoopState {
|
| - public:
|
| - // A vector-based stack is more memory efficient than the default deque-based
|
| - // stack as the active RunLoop stack isn't expected to ever have more than a
|
| - // few entries.
|
| - using RunLoopStack = std::stack<RunLoop*, std::vector<RunLoop*>>;
|
| -
|
| - ThreadLocalRunLoopState()
|
| - : slot_(&ThreadLocalRunLoopState::OnTLSDestruction) {}
|
| -
|
| - ~ThreadLocalRunLoopState() = delete;
|
| -
|
| - RunLoopStack& GetActiveRunLoops() {
|
| - return GetOrCreateInternalState()->active_run_loops;
|
| - }
|
| -
|
| - ObserverList<RunLoop::NestingObserver>& GetNestingObservers() {
|
| - InternalState* state = GetOrCreateInternalState();
|
| - CHECK(state->allow_nesting);
|
| - return state->nesting_observers;
|
| - }
|
| -
|
| - bool IsNestingAllowed() { return GetOrCreateInternalState()->allow_nesting; }
|
| +LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate =
|
| + LAZY_INSTANCE_INITIALIZER;
|
|
|
| - void DisallowNesting() { GetOrCreateInternalState()->allow_nesting = false; }
|
| +} // namespace
|
|
|
| - void Reset() {
|
| - InternalState* state = static_cast<InternalState*>(slot_.Get());
|
| - if (state) {
|
| - slot_.Set(nullptr);
|
| - delete state;
|
| - }
|
| - }
|
| +RunLoop::Delegate::Delegate() {
|
| + // The Delegate can be created on another thread. It is only bound in
|
| + // RegisterDelegateForCurrentThread().
|
| + DETACH_FROM_THREAD(bound_thread_checker_);
|
| +}
|
|
|
| - private:
|
| - struct InternalState {
|
| - bool allow_nesting = true;
|
| - RunLoopStack active_run_loops;
|
| - ObserverList<RunLoop::NestingObserver> nesting_observers;
|
| - };
|
| +RunLoop::Delegate::~Delegate() {
|
| + DCHECK_CALLED_ON_VALID_THREAD(bound_thread_checker_);
|
| + // A RunLoop::Delegate may be destroyed before it is bound, if so it may still
|
| + // be on its creation thread (e.g. a Thread that fails to start) and
|
| + // shouldn't disrupt that thread's state.
|
| + if (bound_)
|
| + tls_delegate.Get().Set(nullptr);
|
| +}
|
|
|
| - static void OnTLSDestruction(void* internal_state) {
|
| - delete static_cast<InternalState*>(internal_state);
|
| - }
|
| +RunLoop* RunLoop::Delegate::Client::GetTopMostRunLoop() const {
|
| + DCHECK_CALLED_ON_VALID_THREAD(outer_->bound_thread_checker_);
|
| + DCHECK(outer_->bound_);
|
| + return outer_->active_run_loops_.empty() ? nullptr
|
| + : outer_->active_run_loops_.top();
|
| +}
|
|
|
| - InternalState* GetOrCreateInternalState() {
|
| - InternalState* state = static_cast<InternalState*>(slot_.Get());
|
| - if (!state) {
|
| - state = new InternalState;
|
| - slot_.Set(static_cast<void*>(state));
|
| - }
|
| - return state;
|
| - }
|
| +bool RunLoop::Delegate::Client::IsNested() const {
|
| + DCHECK_CALLED_ON_VALID_THREAD(outer_->bound_thread_checker_);
|
| + DCHECK(outer_->bound_);
|
| + return outer_->active_run_loops_.size() > 1;
|
| +}
|
|
|
| - ThreadLocalStorage::Slot slot_;
|
| +RunLoop::Delegate::Client::Client(Delegate* outer) : outer_(outer) {}
|
|
|
| - DISALLOW_COPY_AND_ASSIGN(ThreadLocalRunLoopState);
|
| -};
|
| +RunLoop::Delegate::Client* RunLoop::RegisterDelegateForCurrentThread(
|
| + Delegate* delegate) {
|
| + // Bind |delegate| to this thread.
|
| + DCHECK(!delegate->bound_);
|
| + DCHECK_CALLED_ON_VALID_THREAD(delegate->bound_thread_checker_);
|
|
|
| -LazyInstance<ThreadLocalRunLoopState>::Leaky tls_run_loop_state =
|
| - LAZY_INSTANCE_INITIALIZER;
|
| + // There can only be one RunLoop::Delegate per thread.
|
| + DCHECK(!tls_delegate.Get().Get());
|
| + tls_delegate.Get().Set(delegate);
|
| + delegate->bound_ = true;
|
|
|
| -} // namespace
|
| + return &delegate->client_interface_;
|
| +}
|
|
|
| -RunLoop::RunLoop()
|
| - : loop_(MessageLoop::current()),
|
| - weak_factory_(this) {
|
| - DCHECK(loop_);
|
| +RunLoop::RunLoop() : delegate_(tls_delegate.Get().Get()), weak_factory_(this) {
|
| + // A RunLoop::Delegate must be bound to this thread prior to using RunLoop.
|
| + DCHECK(delegate_);
|
| }
|
|
|
| RunLoop::~RunLoop() {
|
| @@ -102,7 +83,7 @@ void RunLoop::Run() {
|
| // any.
|
| tracked_objects::TaskStopwatch stopwatch;
|
| stopwatch.Start();
|
| - loop_->RunHandler();
|
| + delegate_->Run();
|
| stopwatch.Stop();
|
|
|
| AfterRun();
|
| @@ -119,9 +100,9 @@ void RunLoop::Quit() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
|
|
| quit_called_ = true;
|
| - if (running_ && loop_->run_loop_ == this) {
|
| + if (running_ && delegate_->active_run_loops_.top() == this) {
|
| // This is the inner-most RunLoop, so quit now.
|
| - loop_->QuitNow();
|
| + delegate_->Quit();
|
| }
|
| }
|
|
|
| @@ -143,38 +124,41 @@ base::Closure RunLoop::QuitWhenIdleClosure() {
|
| }
|
|
|
| // static
|
| -void RunLoop::ResetTLSState() {
|
| - tls_run_loop_state.Get().Reset();
|
| -}
|
| -
|
| -// static
|
| bool RunLoop::IsRunningOnCurrentThread() {
|
| - return !tls_run_loop_state.Get().GetActiveRunLoops().empty();
|
| + Delegate* delegate = tls_delegate.Get().Get();
|
| + return delegate && !delegate->active_run_loops_.empty();
|
| }
|
|
|
| // static
|
| bool RunLoop::IsNestedOnCurrentThread() {
|
| - return tls_run_loop_state.Get().GetActiveRunLoops().size() > 1;
|
| + Delegate* delegate = tls_delegate.Get().Get();
|
| + return delegate && delegate->active_run_loops_.size() > 1;
|
| }
|
|
|
| // static
|
| void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
|
| - tls_run_loop_state.Get().GetNestingObservers().AddObserver(observer);
|
| + Delegate* delegate = tls_delegate.Get().Get();
|
| + DCHECK(delegate);
|
| + CHECK(delegate->allow_nesting_);
|
| + delegate->nesting_observers_.AddObserver(observer);
|
| }
|
|
|
| // static
|
| void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
|
| - tls_run_loop_state.Get().GetNestingObservers().RemoveObserver(observer);
|
| + Delegate* delegate = tls_delegate.Get().Get();
|
| + DCHECK(delegate);
|
| + CHECK(delegate->allow_nesting_);
|
| + delegate->nesting_observers_.RemoveObserver(observer);
|
| }
|
|
|
| // static
|
| bool RunLoop::IsNestingAllowedOnCurrentThread() {
|
| - return tls_run_loop_state.Get().IsNestingAllowed();
|
| + return tls_delegate.Get().Get()->allow_nesting_;
|
| }
|
|
|
| // static
|
| void RunLoop::DisallowNestingOnCurrentThread() {
|
| - tls_run_loop_state.Get().DisallowNesting();
|
| + tls_delegate.Get().Get()->allow_nesting_ = false;
|
| }
|
|
|
| bool RunLoop::BeforeRun() {
|
| @@ -187,19 +171,14 @@ bool RunLoop::BeforeRun() {
|
| if (quit_called_)
|
| return false;
|
|
|
| - auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
|
| - active_run_loops.push(this);
|
| -
|
| - const bool is_nested = active_run_loops.size() > 1;
|
| + auto& active_run_loops_ = delegate_->active_run_loops_;
|
| + active_run_loops_.push(this);
|
|
|
| - // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
|
| - // further. http://crbug.com/703346
|
| - loop_->run_loop_ = this;
|
| - loop_->is_nested_ = is_nested;
|
| + const bool is_nested = active_run_loops_.size() > 1;
|
|
|
| if (is_nested) {
|
| - CHECK(tls_run_loop_state.Get().IsNestingAllowed());
|
| - for (auto& observer : tls_run_loop_state.Get().GetNestingObservers())
|
| + CHECK(delegate_->allow_nesting_);
|
| + for (auto& observer : delegate_->nesting_observers_)
|
| observer.OnBeginNestedRunLoop();
|
| }
|
|
|
| @@ -212,18 +191,16 @@ void RunLoop::AfterRun() {
|
|
|
| running_ = false;
|
|
|
| - auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
|
| - DCHECK_EQ(active_run_loops.top(), this);
|
| - active_run_loops.pop();
|
| + auto& active_run_loops_ = delegate_->active_run_loops_;
|
| + DCHECK_EQ(active_run_loops_.top(), this);
|
| + active_run_loops_.pop();
|
|
|
| RunLoop* previous_run_loop =
|
| - active_run_loops.empty() ? nullptr : active_run_loops.top();
|
| - loop_->run_loop_ = previous_run_loop;
|
| - loop_->is_nested_ = active_run_loops.size() > 1;
|
| + active_run_loops_.empty() ? nullptr : active_run_loops_.top();
|
|
|
| // Execute deferred QuitNow, if any:
|
| if (previous_run_loop && previous_run_loop->quit_called_)
|
| - loop_->QuitNow();
|
| + delegate_->Quit();
|
| }
|
|
|
| } // namespace base
|
|
|