Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(6314)

Unified Diff: base/run_loop.cc

Issue 2818533003: Make nesting/running states a RunLoop rather than a MessageLoop concept. (Closed)
Patch Set: still need to check MessageLoop::current() in Mojo's RunLoopNestingObserver::GetForThread() Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/run_loop.h ('k') | base/run_loop_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
}
« no previous file with comments | « base/run_loop.h ('k') | base/run_loop_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698