Index: base/run_loop.cc |
diff --git a/base/run_loop.cc b/base/run_loop.cc |
index 6de1707b8f6885e9b2eb2e9be5882311f2752de5..87128c99d16087d03067af47f477f0628d21497f 100644 |
--- a/base/run_loop.cc |
+++ b/base/run_loop.cc |
@@ -5,8 +5,11 @@ |
#include "base/run_loop.h" |
#include "base/bind.h" |
+#include "base/callback.h" |
#include "base/lazy_instance.h" |
+#include "base/single_thread_task_runner.h" |
#include "base/threading/thread_local.h" |
+#include "base/threading/thread_task_runner_handle.h" |
#include "base/tracked_objects.h" |
#include "build/build_config.h" |
@@ -17,6 +20,17 @@ namespace { |
LazyInstance<ThreadLocalPointer<RunLoop::Delegate>>::Leaky tls_delegate = |
LAZY_INSTANCE_INITIALIZER; |
+// Runs |closure| immediately if this is called on |task_runner|, otherwise |
+// forwards |closure| to it. |
+void ProxyToTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner, |
+ OnceClosure closure) { |
+ if (task_runner->RunsTasksInCurrentSequence()) { |
+ std::move(closure).Run(); |
+ return; |
+ } |
+ task_runner->PostTask(FROM_HERE, std::move(closure)); |
+} |
+ |
} // namespace |
RunLoop::Delegate::Delegate() { |
@@ -63,9 +77,13 @@ RunLoop::Delegate::Client* RunLoop::RegisterDelegateForCurrentThread( |
return &delegate->client_interface_; |
} |
-RunLoop::RunLoop() : delegate_(tls_delegate.Get().Get()), weak_factory_(this) { |
+RunLoop::RunLoop() |
+ : delegate_(tls_delegate.Get().Get()), |
+ origin_task_runner_(ThreadTaskRunnerHandle::Get()), |
+ weak_factory_(this) { |
// A RunLoop::Delegate must be bound to this thread prior to using RunLoop. |
DCHECK(delegate_); |
+ DCHECK(origin_task_runner_); |
} |
RunLoop::~RunLoop() { |
@@ -108,7 +126,16 @@ void RunLoop::RunUntilIdle() { |
} |
void RunLoop::Quit() { |
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
+ // Thread-safe. |
+ |
+ // This can only be hit if run_loop->Quit() is called directly (QuitClosure() |
+ // proxies through ProxyToTaskRunner() as it can only deref its WeakPtr on |
+ // |origin_task_runner_|). |
+ if (!origin_task_runner_->RunsTasksInCurrentSequence()) { |
+ origin_task_runner_->PostTask(FROM_HERE, |
+ base::Bind(&RunLoop::Quit, Unretained(this))); |
+ return; |
+ } |
quit_called_ = true; |
if (running_ && delegate_->active_run_loops_.top() == this) { |
@@ -118,20 +145,41 @@ void RunLoop::Quit() { |
} |
void RunLoop::QuitWhenIdle() { |
- DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
+ // Thread-safe. |
+ |
+ // This can only be hit if run_loop->QuitWhenIdle() is called directly |
+ // (QuitWhenIdleClosure() proxies through ProxyToTaskRunner() as it can only |
+ // deref its WeakPtr on |origin_task_runner_|). |
+ if (!origin_task_runner_->RunsTasksInCurrentSequence()) { |
+ origin_task_runner_->PostTask( |
+ FROM_HERE, base::Bind(&RunLoop::QuitWhenIdle, Unretained(this))); |
+ return; |
+ } |
+ |
quit_when_idle_received_ = true; |
} |
base::Closure RunLoop::QuitClosure() { |
// TODO(gab): Fix bad usage and enable this check, http://crbug.com/715235. |
// DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
- return base::Bind(&RunLoop::Quit, weak_factory_.GetWeakPtr()); |
+ |
+ // Need to use ProxyToTaskRunner() as WeakPtrs vended from |
+ // |weak_factory_| may only be accessed on |origin_task_runner_|. |
+ // TODO(gab): It feels wrong that QuitClosure() is bound to a WeakPtr. |
+ return base::Bind(&ProxyToTaskRunner, origin_task_runner_, |
+ 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_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
- return base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr()); |
+ |
+ // Need to use ProxyToTaskRunner() as WeakPtrs vended from |
+ // |weak_factory_| may only be accessed on |origin_task_runner_|. |
+ // TODO(gab): It feels wrong that QuitWhenIdleClosure() is bound to a WeakPtr. |
+ return base::Bind( |
+ &ProxyToTaskRunner, origin_task_runner_, |
+ base::Bind(&RunLoop::QuitWhenIdle, weak_factory_.GetWeakPtr())); |
} |
// static |
@@ -175,8 +223,10 @@ void RunLoop::DisallowNestingOnCurrentThread() { |
bool RunLoop::BeforeRun() { |
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); |
+#if DCHECK_IS_ON() |
DCHECK(!run_called_); |
run_called_ = true; |
+#endif // DCHECK_IS_ON() |
// Allow Quit to be called before Run. |
if (quit_called_) |