| Index: base/run_loop.cc
|
| diff --git a/base/run_loop.cc b/base/run_loop.cc
|
| index 4c19d3589fd7e6f893a7a02f91d2c5a2371720ec..b7df5b23d8d72f737c5c6f468c508ec12ade8fd9 100644
|
| --- a/base/run_loop.cc
|
| +++ b/base/run_loop.cc
|
| @@ -4,29 +4,97 @@
|
|
|
| #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/tracked_objects.h"
|
| #include "build/build_config.h"
|
|
|
| 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; }
|
| +
|
| + void DisallowNesting() { GetOrCreateInternalState()->allow_nesting = false; }
|
| +
|
| + void Reset() {
|
| + InternalState* state = static_cast<InternalState*>(slot_.Get());
|
| + if (state) {
|
| + slot_.Set(nullptr);
|
| + delete state;
|
| + }
|
| + }
|
| +
|
| + private:
|
| + struct InternalState {
|
| + bool allow_nesting = true;
|
| + RunLoopStack active_run_loops;
|
| + ObserverList<RunLoop::NestingObserver> nesting_observers;
|
| + };
|
| +
|
| + static void OnTLSDestruction(void* internal_state) {
|
| + delete static_cast<InternalState*>(internal_state);
|
| + }
|
| +
|
| + InternalState* GetOrCreateInternalState() {
|
| + InternalState* state = static_cast<InternalState*>(slot_.Get());
|
| + if (!state) {
|
| + state = new InternalState;
|
| + slot_.Set(static_cast<void*>(state));
|
| + }
|
| + return state;
|
| + }
|
| +
|
| + ThreadLocalStorage::Slot slot_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ThreadLocalRunLoopState);
|
| +};
|
| +
|
| +LazyInstance<ThreadLocalRunLoopState>::Leaky tls_run_loop_state =
|
| + LAZY_INSTANCE_INITIALIZER;
|
| +
|
| +} // namespace
|
| +
|
| RunLoop::RunLoop()
|
| : loop_(MessageLoop::current()),
|
| - previous_run_loop_(NULL),
|
| - run_depth_(0),
|
| - run_called_(false),
|
| - quit_called_(false),
|
| - running_(false),
|
| - quit_when_idle_received_(false),
|
| weak_factory_(this) {
|
| DCHECK(loop_);
|
| }
|
|
|
| RunLoop::~RunLoop() {
|
| + // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
|
| + // DCHECK(thread_checker_.CalledOnValidThread());
|
| }
|
|
|
| void RunLoop::Run() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| if (!BeforeRun())
|
| return;
|
|
|
| @@ -41,12 +109,15 @@ void RunLoop::Run() {
|
| }
|
|
|
| void RunLoop::RunUntilIdle() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| quit_when_idle_received_ = true;
|
| Run();
|
| }
|
|
|
| void RunLoop::Quit() {
|
| DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| quit_called_ = true;
|
| if (running_ && loop_->run_loop_ == this) {
|
| // This is the inner-most RunLoop, so quit now.
|
| @@ -60,14 +131,55 @@ void RunLoop::QuitWhenIdle() {
|
| }
|
|
|
| base::Closure RunLoop::QuitClosure() {
|
| + // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
|
| + // DCHECK(thread_checker_.CalledOnValidThread());
|
| return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr());
|
| }
|
|
|
| base::Closure RunLoop::QuitWhenIdleClosure() {
|
| + // TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235.
|
| + // DCHECK(thread_checker_.CalledOnValidThread());
|
| return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr());
|
| }
|
|
|
| +// static
|
| +void RunLoop::ResetTLSState() {
|
| + tls_run_loop_state.Get().Reset();
|
| +}
|
| +
|
| +// static
|
| +bool RunLoop::IsRunningOnCurrentThread() {
|
| + return !tls_run_loop_state.Get().GetActiveRunLoops().empty();
|
| +}
|
| +
|
| +// static
|
| +bool RunLoop::IsNestedOnCurrentThread() {
|
| + return tls_run_loop_state.Get().GetActiveRunLoops().size() > 1;
|
| +}
|
| +
|
| +// static
|
| +void RunLoop::AddNestingObserverOnCurrentThread(NestingObserver* observer) {
|
| + tls_run_loop_state.Get().GetNestingObservers().AddObserver(observer);
|
| +}
|
| +
|
| +// static
|
| +void RunLoop::RemoveNestingObserverOnCurrentThread(NestingObserver* observer) {
|
| + tls_run_loop_state.Get().GetNestingObservers().RemoveObserver(observer);
|
| +}
|
| +
|
| +// static
|
| +bool RunLoop::IsNestingAllowedOnCurrentThread() {
|
| + return tls_run_loop_state.Get().IsNestingAllowed();
|
| +}
|
| +
|
| +// static
|
| +void RunLoop::DisallowNestingOnCurrentThread() {
|
| + tls_run_loop_state.Get().DisallowNesting();
|
| +}
|
| +
|
| bool RunLoop::BeforeRun() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| DCHECK(!run_called_);
|
| run_called_ = true;
|
|
|
| @@ -75,26 +187,42 @@ bool RunLoop::BeforeRun() {
|
| if (quit_called_)
|
| return false;
|
|
|
| - // Push RunLoop stack:
|
| - previous_run_loop_ = loop_->run_loop_;
|
| - run_depth_ = previous_run_loop_? previous_run_loop_->run_depth_ + 1 : 1;
|
| + auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
|
| + active_run_loops.push(this);
|
| +
|
| + const bool is_nested = active_run_loops.size() > 1;
|
| +
|
| + // TODO(gab): Break the inter-dependency between MessageLoop and RunLoop
|
| + // further. http://crbug.com/703346
|
| loop_->run_loop_ = this;
|
| + loop_->is_nested_ = is_nested;
|
|
|
| - if (run_depth_ > 1)
|
| - loop_->NotifyBeginNestedLoop();
|
| + if (is_nested) {
|
| + CHECK(tls_run_loop_state.Get().IsNestingAllowed());
|
| + for (auto& observer : tls_run_loop_state.Get().GetNestingObservers())
|
| + observer.OnBeginNestedRunLoop();
|
| + }
|
|
|
| running_ = true;
|
| return true;
|
| }
|
|
|
| void RunLoop::AfterRun() {
|
| + DCHECK(thread_checker_.CalledOnValidThread());
|
| +
|
| running_ = false;
|
|
|
| - // Pop RunLoop stack:
|
| - loop_->run_loop_ = previous_run_loop_;
|
| + auto& active_run_loops = tls_run_loop_state.Get().GetActiveRunLoops();
|
| + 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;
|
|
|
| // Execute deferred QuitNow, if any:
|
| - if (previous_run_loop_ && previous_run_loop_->quit_called_)
|
| + if (previous_run_loop && previous_run_loop->quit_called_)
|
| loop_->QuitNow();
|
| }
|
|
|
|
|