1// Copyright 2015 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/threading/sequenced_task_runner_handle.h"
6
7#include <utility>
8
9#include "base/lazy_instance.h"
10#include "base/logging.h"
11#include "base/threading/sequenced_worker_pool.h"
12#include "base/threading/thread_local.h"
13#include "base/threading/thread_task_runner_handle.h"
14
15namespace base {
16
17namespace {
18
19base::LazyInstance<base::ThreadLocalPointer<SequencedTaskRunnerHandle>>::Leaky
20    lazy_tls_ptr = LAZY_INSTANCE_INITIALIZER;
21
22}  // namespace
23
24// static
25scoped_refptr<SequencedTaskRunner> SequencedTaskRunnerHandle::Get() {
26  // Return the registered SequencedTaskRunner, if any.
27  const SequencedTaskRunnerHandle* handle = lazy_tls_ptr.Pointer()->Get();
28  if (handle) {
29    // Various modes of setting SequencedTaskRunnerHandle don't combine.
30    DCHECK(!base::ThreadTaskRunnerHandle::IsSet());
31    DCHECK(!SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread());
32    return handle->task_runner_;
33  }
34
35  // Return the SequencedTaskRunner obtained from SequencedWorkerPool, if any.
36  scoped_refptr<base::SequencedTaskRunner> task_runner =
37      SequencedWorkerPool::GetSequencedTaskRunnerForCurrentThread();
38  if (task_runner) {
39    DCHECK(!base::ThreadTaskRunnerHandle::IsSet());
40    return task_runner;
41  }
42
43  // Return the SingleThreadTaskRunner for the current thread otherwise.
44  return base::ThreadTaskRunnerHandle::Get();
45}
46
47// static
48bool SequencedTaskRunnerHandle::IsSet() {
49  return lazy_tls_ptr.Pointer()->Get() ||
50         SequencedWorkerPool::GetWorkerPoolForCurrentThread() ||
51         base::ThreadTaskRunnerHandle::IsSet();
52}
53
54SequencedTaskRunnerHandle::SequencedTaskRunnerHandle(
55    scoped_refptr<SequencedTaskRunner> task_runner)
56    : task_runner_(std::move(task_runner)) {
57  DCHECK(task_runner_->RunsTasksOnCurrentThread());
58  DCHECK(!SequencedTaskRunnerHandle::IsSet());
59  lazy_tls_ptr.Pointer()->Set(this);
60}
61
62SequencedTaskRunnerHandle::~SequencedTaskRunnerHandle() {
63  DCHECK(task_runner_->RunsTasksOnCurrentThread());
64  DCHECK_EQ(lazy_tls_ptr.Pointer()->Get(), this);
65  lazy_tls_ptr.Pointer()->Set(nullptr);
66}
67
68}  // namespace base
69