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