Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(20)

Side by Side Diff: base/timer/timer.cc

Issue 1433373003: Use SequenceChecker to allow Timer to run in SequencedWorkerPool (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Review nits Created 5 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/timer/timer.h ('k') | base/timer/timer_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "base/timer/timer.h" 5 #include "base/timer/timer.h"
6 6
7 #include <stddef.h> 7 #include <stddef.h>
8 8
9 #include "base/logging.h" 9 #include "base/logging.h"
10 #include "base/memory/ref_counted.h" 10 #include "base/memory/ref_counted.h"
11 #include "base/single_thread_task_runner.h" 11 #include "base/sequenced_task_runner.h"
12 #include "base/thread_task_runner_handle.h" 12 #include "base/threading/sequenced_task_runner_handle.h"
13 #include "base/threading/platform_thread.h"
14 13
15 namespace base { 14 namespace base {
16 15
17 // BaseTimerTaskInternal is a simple delegate for scheduling a callback to 16 // BaseTimerTaskInternal is a simple delegate for scheduling a callback to
18 // Timer in the thread's default task runner. It also handles the following 17 // Timer in the task runner. It also handles the following edge cases:
19 // edge cases:
20 // - deleted by the task runner. 18 // - deleted by the task runner.
21 // - abandoned (orphaned) by Timer. 19 // - abandoned (orphaned) by Timer.
22 class BaseTimerTaskInternal { 20 class BaseTimerTaskInternal {
23 public: 21 public:
24 explicit BaseTimerTaskInternal(Timer* timer) 22 explicit BaseTimerTaskInternal(Timer* timer)
25 : timer_(timer) { 23 : timer_(timer) {
26 } 24 }
27 25
28 ~BaseTimerTaskInternal() { 26 ~BaseTimerTaskInternal() {
29 // This task may be getting cleared because the task runner has been 27 // This task may be getting cleared because the task runner has been
(...skipping 24 matching lines...) Expand all
54 void Abandon() { 52 void Abandon() {
55 timer_ = NULL; 53 timer_ = NULL;
56 } 54 }
57 55
58 private: 56 private:
59 Timer* timer_; 57 Timer* timer_;
60 }; 58 };
61 59
62 Timer::Timer(bool retain_user_task, bool is_repeating) 60 Timer::Timer(bool retain_user_task, bool is_repeating)
63 : scheduled_task_(NULL), 61 : scheduled_task_(NULL),
64 thread_id_(0), 62 was_scheduled_(false),
65 is_repeating_(is_repeating), 63 is_repeating_(is_repeating),
66 retain_user_task_(retain_user_task), 64 retain_user_task_(retain_user_task),
67 is_running_(false) { 65 is_running_(false) {
66 // It is safe for the timer to be created on a different thread/sequence
67 // than the one from which the timer APIs are called. The first call to the
68 // checker's CalledOnValidSequencedThread() method will re-bind the checker,
69 // and later calls will verify that the same task runner is used.
70 origin_sequence_checker_.DetachFromSequence();
68 } 71 }
69 72
70 Timer::Timer(const tracked_objects::Location& posted_from, 73 Timer::Timer(const tracked_objects::Location& posted_from,
71 TimeDelta delay, 74 TimeDelta delay,
72 const base::Closure& user_task, 75 const base::Closure& user_task,
73 bool is_repeating) 76 bool is_repeating)
74 : scheduled_task_(NULL), 77 : scheduled_task_(NULL),
75 posted_from_(posted_from), 78 posted_from_(posted_from),
76 delay_(delay), 79 delay_(delay),
77 user_task_(user_task), 80 user_task_(user_task),
78 thread_id_(0), 81 was_scheduled_(false),
79 is_repeating_(is_repeating), 82 is_repeating_(is_repeating),
80 retain_user_task_(true), 83 retain_user_task_(true),
81 is_running_(false) { 84 is_running_(false) {
85 // See comment in other constructor.
86 origin_sequence_checker_.DetachFromSequence();
82 } 87 }
83 88
84 Timer::~Timer() { 89 Timer::~Timer() {
90 DCHECK(origin_sequence_checker_.CalledOnValidSequencedThread());
85 StopAndAbandon(); 91 StopAndAbandon();
86 } 92 }
87 93
88 bool Timer::IsRunning() const { 94 bool Timer::IsRunning() const {
89 return is_running_; 95 return is_running_;
90 } 96 }
91 97
92 TimeDelta Timer::GetCurrentDelay() const { 98 TimeDelta Timer::GetCurrentDelay() const {
93 return delay_; 99 return delay_;
94 } 100 }
95 101
96 void Timer::SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { 102 void Timer::SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
97 // Do not allow changing the task runner once something has been scheduled. 103 // Do not allow changing the task runner once something has been scheduled.
98 DCHECK_EQ(thread_id_, 0); 104 DCHECK(!was_scheduled_);
99 task_runner_.swap(task_runner); 105 destination_task_runner_ = std::move(task_runner);
100 } 106 }
101 107
102 void Timer::Start(const tracked_objects::Location& posted_from, 108 void Timer::Start(const tracked_objects::Location& posted_from,
103 TimeDelta delay, 109 TimeDelta delay,
104 const base::Closure& user_task) { 110 const base::Closure& user_task) {
105 SetTaskInfo(posted_from, delay, user_task); 111 SetTaskInfo(posted_from, delay, user_task);
106 Reset(); 112 Reset();
107 } 113 }
108 114
109 void Timer::Stop() { 115 void Timer::Stop() {
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 void Timer::SetTaskInfo(const tracked_objects::Location& posted_from, 148 void Timer::SetTaskInfo(const tracked_objects::Location& posted_from,
143 TimeDelta delay, 149 TimeDelta delay,
144 const base::Closure& user_task) { 150 const base::Closure& user_task) {
145 posted_from_ = posted_from; 151 posted_from_ = posted_from;
146 delay_ = delay; 152 delay_ = delay;
147 user_task_ = user_task; 153 user_task_ = user_task;
148 } 154 }
149 155
150 void Timer::PostNewScheduledTask(TimeDelta delay) { 156 void Timer::PostNewScheduledTask(TimeDelta delay) {
151 DCHECK(scheduled_task_ == NULL); 157 DCHECK(scheduled_task_ == NULL);
158 DCHECK(origin_sequence_checker_.CalledOnValidSequencedThread());
159 was_scheduled_ = true;
152 is_running_ = true; 160 is_running_ = true;
153 scheduled_task_ = new BaseTimerTaskInternal(this); 161 scheduled_task_ = new BaseTimerTaskInternal(this);
154 if (delay > TimeDelta::FromMicroseconds(0)) { 162 if (delay > TimeDelta::FromMicroseconds(0)) {
155 GetTaskRunner()->PostDelayedTask(posted_from_, 163 GetTaskRunner()->PostDelayedTask(posted_from_,
156 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)), 164 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)),
157 delay); 165 delay);
158 scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay; 166 scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay;
159 } else { 167 } else {
160 GetTaskRunner()->PostTask(posted_from_, 168 GetTaskRunner()->PostTask(posted_from_,
161 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_))); 169 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)));
162 scheduled_run_time_ = desired_run_time_ = TimeTicks(); 170 scheduled_run_time_ = desired_run_time_ = TimeTicks();
163 } 171 }
164 // Remember the thread ID that posts the first task -- this will be verified
165 // later when the task is abandoned to detect misuse from multiple threads.
166 if (!thread_id_) {
167 DCHECK(GetTaskRunner()->BelongsToCurrentThread());
168 thread_id_ = static_cast<int>(PlatformThread::CurrentId());
169 }
170 } 172 }
171 173
172 scoped_refptr<SingleThreadTaskRunner> Timer::GetTaskRunner() { 174 scoped_refptr<SequencedTaskRunner> Timer::GetTaskRunner() {
173 return task_runner_.get() ? task_runner_ : ThreadTaskRunnerHandle::Get(); 175 return destination_task_runner_.get() ? destination_task_runner_
176 : SequencedTaskRunnerHandle::Get();
174 } 177 }
175 178
176 void Timer::AbandonScheduledTask() { 179 void Timer::AbandonScheduledTask() {
177 DCHECK(thread_id_ == 0 || 180 DCHECK(origin_sequence_checker_.CalledOnValidSequencedThread());
178 thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
179 if (scheduled_task_) { 181 if (scheduled_task_) {
180 scheduled_task_->Abandon(); 182 scheduled_task_->Abandon();
181 scheduled_task_ = NULL; 183 scheduled_task_ = NULL;
182 } 184 }
183 } 185 }
184 186
185 void Timer::RunScheduledTask() { 187 void Timer::RunScheduledTask() {
186 // Task may have been disabled. 188 // Task may have been disabled.
187 if (!is_running_) 189 if (!is_running_)
188 return; 190 return;
(...skipping 20 matching lines...) Expand all
209 PostNewScheduledTask(delay_); 211 PostNewScheduledTask(delay_);
210 else 212 else
211 Stop(); 213 Stop();
212 214
213 task.Run(); 215 task.Run();
214 216
215 // No more member accesses here: *this could be deleted at this point. 217 // No more member accesses here: *this could be deleted at this point.
216 } 218 }
217 219
218 } // namespace base 220 } // namespace base
OLDNEW
« no previous file with comments | « base/timer/timer.h ('k') | base/timer/timer_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698