|  | // Copyright 2015 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/sequenced_task_runner_handle.h" | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/lazy_instance.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/threading/thread_local.h" | 
|  | #include "base/threading/thread_task_runner_handle.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | namespace { | 
|  |  | 
|  | LazyInstance<ThreadLocalPointer<SequencedTaskRunnerHandle>>::Leaky | 
|  | sequenced_task_runner_tls = LAZY_INSTANCE_INITIALIZER; | 
|  |  | 
|  | }  // namespace | 
|  |  | 
|  | // static | 
|  | scoped_refptr<SequencedTaskRunner> SequencedTaskRunnerHandle::Get() { | 
|  | // Return the registered SequencedTaskRunner, if any. | 
|  | const SequencedTaskRunnerHandle* handle = | 
|  | sequenced_task_runner_tls.Pointer()->Get(); | 
|  | if (handle) | 
|  | return handle->task_runner_; | 
|  |  | 
|  | // Note if you hit this: the problem is the lack of a sequenced context. The | 
|  | // ThreadTaskRunnerHandle is just the last attempt at finding such a context. | 
|  | CHECK(ThreadTaskRunnerHandle::IsSet()) | 
|  | << "Error: This caller requires a sequenced context (i.e. the " | 
|  | "current task needs to run from a SequencedTaskRunner)."; | 
|  | return ThreadTaskRunnerHandle::Get(); | 
|  | } | 
|  |  | 
|  | // static | 
|  | bool SequencedTaskRunnerHandle::IsSet() { | 
|  | return sequenced_task_runner_tls.Pointer()->Get() || | 
|  | ThreadTaskRunnerHandle::IsSet(); | 
|  | } | 
|  |  | 
|  | SequencedTaskRunnerHandle::SequencedTaskRunnerHandle( | 
|  | scoped_refptr<SequencedTaskRunner> task_runner) | 
|  | : task_runner_(std::move(task_runner)) { | 
|  | DCHECK(task_runner_->RunsTasksInCurrentSequence()); | 
|  | DCHECK(!SequencedTaskRunnerHandle::IsSet()); | 
|  | sequenced_task_runner_tls.Pointer()->Set(this); | 
|  | } | 
|  |  | 
|  | SequencedTaskRunnerHandle::~SequencedTaskRunnerHandle() { | 
|  | DCHECK(task_runner_->RunsTasksInCurrentSequence()); | 
|  | DCHECK_EQ(sequenced_task_runner_tls.Pointer()->Get(), this); | 
|  | sequenced_task_runner_tls.Pointer()->Set(nullptr); | 
|  | } | 
|  |  | 
|  | }  // namespace base |