xref: /aosp_15_r20/external/cronet/base/task/deferred_sequenced_task_runner.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2013 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/deferred_sequenced_task_runner.h"
6 #include "base/task/common/scoped_defer_task_posting.h"
7 
8 #include <utility>
9 
10 #include "base/check.h"
11 #include "base/functional/bind.h"
12 
13 namespace base {
14 
DeferredTask()15 DeferredSequencedTaskRunner::DeferredTask::DeferredTask()
16     : is_non_nestable(false) {
17 }
18 
19 DeferredSequencedTaskRunner::DeferredTask::DeferredTask(DeferredTask&& other) =
20     default;
21 
22 DeferredSequencedTaskRunner::DeferredTask::~DeferredTask() = default;
23 
24 DeferredSequencedTaskRunner::DeferredTask&
25 DeferredSequencedTaskRunner::DeferredTask::operator=(DeferredTask&& other) =
26     default;
27 
DeferredSequencedTaskRunner(scoped_refptr<SequencedTaskRunner> target_task_runner)28 DeferredSequencedTaskRunner::DeferredSequencedTaskRunner(
29     scoped_refptr<SequencedTaskRunner> target_task_runner)
30     : created_thread_id_(PlatformThread::CurrentId()),
31       target_task_runner_(std::move(target_task_runner)) {
32 #if DCHECK_IS_ON()
33   AutoLock lock(lock_);
34   DCHECK(target_task_runner_);
35 #endif
36   task_runner_atomic_ptr_.store(target_task_runner_.get(),
37                                 std::memory_order_release);
38 }
39 
DeferredSequencedTaskRunner()40 DeferredSequencedTaskRunner::DeferredSequencedTaskRunner()
41     : created_thread_id_(PlatformThread::CurrentId()) {}
42 
PostDelayedTask(const Location & from_here,OnceClosure task,TimeDelta delay)43 bool DeferredSequencedTaskRunner::PostDelayedTask(const Location& from_here,
44                                                   OnceClosure task,
45                                                   TimeDelta delay) {
46   // Do not process new PostTasks while we are handling a PostTask (tracing
47   // has to do this) as it can lead to a deadlock and defer it instead.
48   ScopedDeferTaskPosting disallow_task_posting;
49 
50   AutoLock lock(lock_);
51   if (started_) {
52     DCHECK(deferred_tasks_queue_.empty());
53     return target_task_runner_->PostDelayedTask(from_here, std::move(task),
54                                                 delay);
55   }
56 
57   QueueDeferredTask(from_here, std::move(task), delay,
58                     false /* is_non_nestable */);
59   return true;
60 }
61 
RunsTasksInCurrentSequence() const62 bool DeferredSequencedTaskRunner::RunsTasksInCurrentSequence() const {
63   // task_runner_atomic_ptr_ cannot change once it has been initialized, so it's
64   // safe to access it without lock.
65   SequencedTaskRunner* task_runner_ptr =
66       task_runner_atomic_ptr_.load(std::memory_order_acquire);
67   if (task_runner_ptr) {
68     return task_runner_ptr->RunsTasksInCurrentSequence();
69   }
70 
71   return created_thread_id_ == PlatformThread::CurrentId();
72 }
73 
PostNonNestableDelayedTask(const Location & from_here,OnceClosure task,TimeDelta delay)74 bool DeferredSequencedTaskRunner::PostNonNestableDelayedTask(
75     const Location& from_here,
76     OnceClosure task,
77     TimeDelta delay) {
78   AutoLock lock(lock_);
79   if (started_) {
80     DCHECK(deferred_tasks_queue_.empty());
81     return target_task_runner_->PostNonNestableDelayedTask(
82         from_here, std::move(task), delay);
83   }
84   QueueDeferredTask(from_here, std::move(task), delay,
85                     true /* is_non_nestable */);
86   return true;
87 }
88 
Start()89 void DeferredSequencedTaskRunner::Start() {
90   AutoLock lock(lock_);
91   StartImpl();
92 }
93 
StartWithTaskRunner(scoped_refptr<SequencedTaskRunner> target_task_runner)94 void DeferredSequencedTaskRunner::StartWithTaskRunner(
95     scoped_refptr<SequencedTaskRunner> target_task_runner) {
96   AutoLock lock(lock_);
97   DCHECK(!target_task_runner_);
98   DCHECK(target_task_runner);
99   target_task_runner_ = std::move(target_task_runner);
100   task_runner_atomic_ptr_.store(target_task_runner_.get(),
101                                 std::memory_order_release);
102   StartImpl();
103 }
104 
Started() const105 bool DeferredSequencedTaskRunner::Started() const {
106   AutoLock lock(lock_);
107   return started_;
108 }
109 
110 DeferredSequencedTaskRunner::~DeferredSequencedTaskRunner() = default;
111 
QueueDeferredTask(const Location & from_here,OnceClosure task,TimeDelta delay,bool is_non_nestable)112 void DeferredSequencedTaskRunner::QueueDeferredTask(const Location& from_here,
113                                                     OnceClosure task,
114                                                     TimeDelta delay,
115                                                     bool is_non_nestable) {
116   lock_.AssertAcquired();
117 
118   // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
119   // for details.
120   CHECK(task);
121 
122   DeferredTask deferred_task;
123   deferred_task.posted_from = from_here;
124   deferred_task.task = std::move(task);
125   deferred_task.delay = delay;
126   deferred_task.is_non_nestable = is_non_nestable;
127   deferred_tasks_queue_.push_back(std::move(deferred_task));
128 }
129 
StartImpl()130 void DeferredSequencedTaskRunner::StartImpl() {
131   lock_.AssertAcquired();  // Callers should have grabbed the lock.
132   DCHECK(!started_);
133   started_ = true;
134   DCHECK(target_task_runner_);
135   for (auto& task : deferred_tasks_queue_) {
136     if (task.is_non_nestable) {
137       target_task_runner_->PostNonNestableDelayedTask(
138           task.posted_from, std::move(task.task), task.delay);
139     } else {
140       target_task_runner_->PostDelayedTask(task.posted_from,
141                                            std::move(task.task), task.delay);
142     }
143   }
144   deferred_tasks_queue_.clear();
145 }
146 
147 }  // namespace base
148