• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 The Chromium Authors
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/task/common/scoped_defer_task_posting.h"
6 
7 #include "base/compiler_specific.h"
8 
9 namespace base {
10 
11 namespace {
12 
13 // Holds a thread-local pointer to the current scope or null when no
14 // scope is active.
15 constinit thread_local ScopedDeferTaskPosting* scoped_defer_task_posting =
16     nullptr;
17 
18 }  // namespace
19 
20 // static
PostOrDefer(scoped_refptr<SequencedTaskRunner> task_runner,const Location & from_here,OnceClosure task,base::TimeDelta delay)21 void ScopedDeferTaskPosting::PostOrDefer(
22     scoped_refptr<SequencedTaskRunner> task_runner,
23     const Location& from_here,
24     OnceClosure task,
25     base::TimeDelta delay) {
26   ScopedDeferTaskPosting* scope = Get();
27   if (scope) {
28     scope->DeferTaskPosting(std::move(task_runner), from_here, std::move(task),
29                             delay);
30     return;
31   }
32 
33   task_runner->PostDelayedTask(from_here, std::move(task), delay);
34 }
35 
36 // static
Get()37 ScopedDeferTaskPosting* ScopedDeferTaskPosting::Get() {
38   // Workaround false-positive MSAN use-of-uninitialized-value on
39   // thread_local storage for loaded libraries:
40   // https://github.com/google/sanitizers/issues/1265
41   MSAN_UNPOISON(&scoped_defer_task_posting, sizeof(ScopedDeferTaskPosting*));
42 
43   return scoped_defer_task_posting;
44 }
45 
46 // static
Set(ScopedDeferTaskPosting * scope)47 bool ScopedDeferTaskPosting::Set(ScopedDeferTaskPosting* scope) {
48   // We can post a task from within a ScheduleWork in some tests, so we can
49   // get nested scopes. In this case ignore all except the top one.
50   if (Get() && scope)
51     return false;
52   scoped_defer_task_posting = scope;
53   return true;
54 }
55 
56 // static
IsPresent()57 bool ScopedDeferTaskPosting::IsPresent() {
58   return !!Get();
59 }
60 
ScopedDeferTaskPosting()61 ScopedDeferTaskPosting::ScopedDeferTaskPosting() {
62   top_level_scope_ = Set(this);
63 }
64 
~ScopedDeferTaskPosting()65 ScopedDeferTaskPosting::~ScopedDeferTaskPosting() {
66   if (!top_level_scope_) {
67     DCHECK(deferred_tasks_.empty());
68     return;
69   }
70   Set(nullptr);
71   for (DeferredTask& deferred_task : deferred_tasks_) {
72     deferred_task.task_runner->PostDelayedTask(deferred_task.from_here,
73                                                std::move(deferred_task.task),
74                                                deferred_task.delay);
75   }
76 }
77 
DeferredTask(scoped_refptr<SequencedTaskRunner> task_runner,Location from_here,OnceClosure task,base::TimeDelta delay)78 ScopedDeferTaskPosting::DeferredTask::DeferredTask(
79     scoped_refptr<SequencedTaskRunner> task_runner,
80     Location from_here,
81     OnceClosure task,
82     base::TimeDelta delay)
83     : task_runner(std::move(task_runner)),
84       from_here(from_here),
85       task(std::move(task)),
86       delay(delay) {}
87 
88 ScopedDeferTaskPosting::DeferredTask::DeferredTask(DeferredTask&&) = default;
89 
90 ScopedDeferTaskPosting::DeferredTask::~DeferredTask() = default;
91 
DeferTaskPosting(scoped_refptr<SequencedTaskRunner> task_runner,const Location & from_here,OnceClosure task,base::TimeDelta delay)92 void ScopedDeferTaskPosting::DeferTaskPosting(
93     scoped_refptr<SequencedTaskRunner> task_runner,
94     const Location& from_here,
95     OnceClosure task,
96     base::TimeDelta delay) {
97   deferred_tasks_.push_back(
98       {std::move(task_runner), from_here, std::move(task), delay});
99 }
100 
101 }  // namespace base
102