// Copyright 2016 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/threading/thread_task_runner_handle.h" #include #include #include "base/bind.h" #include "base/check_op.h" #include "base/dcheck_is_on.h" #include "base/lazy_instance.h" #include "base/run_loop.h" #include "base/threading/sequenced_task_runner_handle.h" #include "base/threading/thread_local.h" namespace base { namespace { base::LazyInstance>::Leaky thread_task_runner_tls = LAZY_INSTANCE_INITIALIZER; } // namespace // static const scoped_refptr& ThreadTaskRunnerHandle::Get() { const ThreadTaskRunnerHandle* current = thread_task_runner_tls.Pointer()->Get(); CHECK(current) << "Error: This caller requires a single-threaded context (i.e. the " "current task needs to run from a SingleThreadTaskRunner). If you're " "in a test refer to //docs/threading_and_tasks_testing.md." << (SequencedTaskRunnerHandle::IsSet() ? " Note: base::SequencedTaskRunnerHandle::Get() is set; " "consider using it if the current task can run from a " "SequencedTaskRunner." : ""); return current->task_runner_; } // static bool ThreadTaskRunnerHandle::IsSet() { return !!thread_task_runner_tls.Pointer()->Get(); } ThreadTaskRunnerHandle::ThreadTaskRunnerHandle( scoped_refptr task_runner) : task_runner_(std::move(task_runner)), sequenced_task_runner_handle_(task_runner_) { DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK(!thread_task_runner_tls.Pointer()->Get()); thread_task_runner_tls.Pointer()->Set(this); } ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() { DCHECK(task_runner_->BelongsToCurrentThread()); DCHECK_EQ(thread_task_runner_tls.Pointer()->Get(), this); thread_task_runner_tls.Pointer()->Set(nullptr); } ThreadTaskRunnerHandleOverride::ThreadTaskRunnerHandleOverride( scoped_refptr overriding_task_runner, bool allow_nested_runloop) { DCHECK(!SequencedTaskRunnerHandle::IsSet() || ThreadTaskRunnerHandle::IsSet()) << "ThreadTaskRunnerHandleOverride is not compatible with a " "SequencedTaskRunnerHandle already being set on this thread (except " "when it's set by the current ThreadTaskRunnerHandle)."; if (!ThreadTaskRunnerHandle::IsSet()) { top_level_thread_task_runner_handle_.emplace( std::move(overriding_task_runner)); return; } #if DCHECK_IS_ON() expected_task_runner_before_restore_ = overriding_task_runner.get(); #endif ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get(); ttrh->sequenced_task_runner_handle_.task_runner_ = overriding_task_runner; ttrh->task_runner_.swap(overriding_task_runner); // Due to the swap, now `ttrh->task_runner_` points to the overriding task // runner and `overriding_task_runner_` points to the previous task runner. task_runner_to_restore_ = std::move(overriding_task_runner); if (!allow_nested_runloop) { no_running_during_override_ = std::make_unique(); } } ThreadTaskRunnerHandleOverride::~ThreadTaskRunnerHandleOverride() { if (task_runner_to_restore_) { ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get(); #if DCHECK_IS_ON() DCHECK_EQ(expected_task_runner_before_restore_, ttrh->task_runner_.get()) << "Nested overrides must expire their ThreadTaskRunnerHandleOverride " "in LIFO order."; #endif ttrh->sequenced_task_runner_handle_.task_runner_ = task_runner_to_restore_; ttrh->task_runner_.swap(task_runner_to_restore_); } } } // namespace base