Home | History | Annotate | Download | only in threading
      1 // Copyright 2016 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/thread_task_runner_handle.h"
      6 
      7 #include <utility>
      8 
      9 #include "base/bind.h"
     10 #include "base/lazy_instance.h"
     11 #include "base/logging.h"
     12 #include "base/memory/ptr_util.h"
     13 #include "base/run_loop.h"
     14 #include "base/threading/sequenced_task_runner_handle.h"
     15 #include "base/threading/thread_local.h"
     16 
     17 namespace base {
     18 
     19 namespace {
     20 
     21 base::LazyInstance<base::ThreadLocalPointer<ThreadTaskRunnerHandle>>::Leaky
     22     thread_task_runner_tls = LAZY_INSTANCE_INITIALIZER;
     23 
     24 }  // namespace
     25 
     26 // static
     27 scoped_refptr<SingleThreadTaskRunner> ThreadTaskRunnerHandle::Get() {
     28   ThreadTaskRunnerHandle* current = thread_task_runner_tls.Pointer()->Get();
     29   CHECK(current) << "Error: This caller requires a single-threaded context "
     30                     "(i.e. the current task needs to run from a "
     31                     "SingleThreadTaskRunner).";
     32   return current->task_runner_;
     33 }
     34 
     35 // static
     36 bool ThreadTaskRunnerHandle::IsSet() {
     37   return !!thread_task_runner_tls.Pointer()->Get();
     38 }
     39 
     40 // static
     41 ScopedClosureRunner ThreadTaskRunnerHandle::OverrideForTesting(
     42     scoped_refptr<SingleThreadTaskRunner> overriding_task_runner) {
     43   // OverrideForTesting() is not compatible with a SequencedTaskRunnerHandle
     44   // being set (but SequencedTaskRunnerHandle::IsSet() includes
     45   // ThreadTaskRunnerHandle::IsSet() so that's discounted as the only valid
     46   // excuse for it to be true). Sadly this means that tests that merely need a
     47   // SequencedTaskRunnerHandle on their main thread can be forced to use a
     48   // ThreadTaskRunnerHandle if they're also using test task runners (that
     49   // OverrideForTesting() when running their tasks from said main thread). To
     50   // solve this: sequence_task_runner_handle.cc and thread_task_runner_handle.cc
     51   // would have to be merged into a single impl file and share TLS state. This
     52   // was deemed unecessary for now as most tests should use higher level
     53   // constructs and not have to instantiate task runner handles on their own.
     54   DCHECK(!SequencedTaskRunnerHandle::IsSet() || IsSet());
     55 
     56   if (!IsSet()) {
     57     auto top_level_ttrh = std::make_unique<ThreadTaskRunnerHandle>(
     58         std::move(overriding_task_runner));
     59     return ScopedClosureRunner(base::BindOnce(
     60         [](std::unique_ptr<ThreadTaskRunnerHandle> ttrh_to_release) {},
     61         std::move(top_level_ttrh)));
     62   }
     63 
     64   ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
     65   // Swap the two (and below bind |overriding_task_runner|, which is now the
     66   // previous one, as the |task_runner_to_restore|).
     67   ttrh->task_runner_.swap(overriding_task_runner);
     68 
     69   auto no_running_during_override =
     70       std::make_unique<RunLoop::ScopedDisallowRunningForTesting>();
     71 
     72   return ScopedClosureRunner(base::BindOnce(
     73       [](scoped_refptr<SingleThreadTaskRunner> task_runner_to_restore,
     74          SingleThreadTaskRunner* expected_task_runner_before_restore,
     75          std::unique_ptr<RunLoop::ScopedDisallowRunningForTesting>
     76              no_running_during_override) {
     77         ThreadTaskRunnerHandle* ttrh = thread_task_runner_tls.Pointer()->Get();
     78 
     79         DCHECK_EQ(expected_task_runner_before_restore, ttrh->task_runner_.get())
     80             << "Nested overrides must expire their ScopedClosureRunners "
     81                "in LIFO order.";
     82 
     83         ttrh->task_runner_.swap(task_runner_to_restore);
     84       },
     85       std::move(overriding_task_runner),
     86       base::Unretained(ttrh->task_runner_.get()),
     87       std::move(no_running_during_override)));
     88 }
     89 
     90 ThreadTaskRunnerHandle::ThreadTaskRunnerHandle(
     91     scoped_refptr<SingleThreadTaskRunner> task_runner)
     92     : task_runner_(std::move(task_runner)) {
     93   DCHECK(task_runner_->BelongsToCurrentThread());
     94   // No SequencedTaskRunnerHandle (which includes ThreadTaskRunnerHandles)
     95   // should already be set for this thread.
     96   DCHECK(!SequencedTaskRunnerHandle::IsSet());
     97   thread_task_runner_tls.Pointer()->Set(this);
     98 }
     99 
    100 ThreadTaskRunnerHandle::~ThreadTaskRunnerHandle() {
    101   DCHECK(task_runner_->BelongsToCurrentThread());
    102   DCHECK_EQ(thread_task_runner_tls.Pointer()->Get(), this);
    103   thread_task_runner_tls.Pointer()->Set(nullptr);
    104 }
    105 
    106 }  // namespace base
    107