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 |