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

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: Detach in ctor Created 5 years, 1 month 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
« base/timer/timer.h ('K') | « base/timer/timer.h ('k') | no next file » | 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/threading/sequenced_task_runner_handle.h"
12 #include "base/thread_task_runner_handle.h"
13 #include "base/threading/platform_thread.h"
14 12
15 namespace base { 13 namespace base {
16 14
17 // BaseTimerTaskInternal is a simple delegate for scheduling a callback to 15 // BaseTimerTaskInternal is a simple delegate for scheduling a callback to
18 // Timer in the thread's default task runner. It also handles the following 16 // Timer in the task runner. It also handles the following edge cases:
19 // edge cases:
20 // - deleted by the task runner. 17 // - deleted by the task runner.
21 // - abandoned (orphaned) by Timer. 18 // - abandoned (orphaned) by Timer.
22 class BaseTimerTaskInternal { 19 class BaseTimerTaskInternal {
23 public: 20 public:
24 explicit BaseTimerTaskInternal(Timer* timer) 21 explicit BaseTimerTaskInternal(Timer* timer)
25 : timer_(timer) { 22 : timer_(timer) {
26 } 23 }
27 24
28 ~BaseTimerTaskInternal() { 25 ~BaseTimerTaskInternal() {
29 // This task may be getting cleared because the task runner has been 26 // This task may be getting cleared because the task runner has been
(...skipping 24 matching lines...) Expand all
54 void Abandon() { 51 void Abandon() {
55 timer_ = NULL; 52 timer_ = NULL;
56 } 53 }
57 54
58 private: 55 private:
59 Timer* timer_; 56 Timer* timer_;
60 }; 57 };
61 58
62 Timer::Timer(bool retain_user_task, bool is_repeating) 59 Timer::Timer(bool retain_user_task, bool is_repeating)
63 : scheduled_task_(NULL), 60 : scheduled_task_(NULL),
64 thread_id_(0), 61 was_scheduled_(false),
65 is_repeating_(is_repeating), 62 is_repeating_(is_repeating),
66 retain_user_task_(retain_user_task), 63 retain_user_task_(retain_user_task),
67 is_running_(false) { 64 is_running_(false) {
65 // It is safe for the timer to be created on a different thread (or
66 // sequenced task runner) from the one on which tasks are scheduled. The
67 // first call to the checker's CalledOnValidSequencedThread() method will
68 // re-bind the checker, and later calls will verify that the same task
69 // runner is used.
70 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 sequence_checker_.DetachFromSequence();
82 } 87 }
83 88
84 Timer::~Timer() { 89 Timer::~Timer() {
85 StopAndAbandon(); 90 StopAndAbandon();
86 } 91 }
87 92
88 bool Timer::IsRunning() const { 93 bool Timer::IsRunning() const {
89 return is_running_; 94 return is_running_;
90 } 95 }
91 96
92 TimeDelta Timer::GetCurrentDelay() const { 97 TimeDelta Timer::GetCurrentDelay() const {
93 return delay_; 98 return delay_;
94 } 99 }
95 100
96 void Timer::SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { 101 void Timer::SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) {
97 // Do not allow changing the task runner once something has been scheduled. 102 // Do not allow changing the task runner once something has been scheduled.
98 DCHECK_EQ(thread_id_, 0); 103 DCHECK_EQ(was_scheduled_, false);
danakj 2015/11/16 22:46:42 DCHECK(!was_scheduled_) for a boolean
jsbell 2015/12/01 00:23:10 Done.
99 task_runner_.swap(task_runner); 104 task_runner_.swap(task_runner);
100 } 105 }
101 106
102 void Timer::Start(const tracked_objects::Location& posted_from, 107 void Timer::Start(const tracked_objects::Location& posted_from,
103 TimeDelta delay, 108 TimeDelta delay,
104 const base::Closure& user_task) { 109 const base::Closure& user_task) {
105 SetTaskInfo(posted_from, delay, user_task); 110 SetTaskInfo(posted_from, delay, user_task);
106 Reset(); 111 Reset();
107 } 112 }
108 113
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after
142 void Timer::SetTaskInfo(const tracked_objects::Location& posted_from, 147 void Timer::SetTaskInfo(const tracked_objects::Location& posted_from,
143 TimeDelta delay, 148 TimeDelta delay,
144 const base::Closure& user_task) { 149 const base::Closure& user_task) {
145 posted_from_ = posted_from; 150 posted_from_ = posted_from;
146 delay_ = delay; 151 delay_ = delay;
147 user_task_ = user_task; 152 user_task_ = user_task;
148 } 153 }
149 154
150 void Timer::PostNewScheduledTask(TimeDelta delay) { 155 void Timer::PostNewScheduledTask(TimeDelta delay) {
151 DCHECK(scheduled_task_ == NULL); 156 DCHECK(scheduled_task_ == NULL);
157 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
158 was_scheduled_ = true;
152 is_running_ = true; 159 is_running_ = true;
153 scheduled_task_ = new BaseTimerTaskInternal(this); 160 scheduled_task_ = new BaseTimerTaskInternal(this);
154 if (delay > TimeDelta::FromMicroseconds(0)) { 161 if (delay > TimeDelta::FromMicroseconds(0)) {
155 GetTaskRunner()->PostDelayedTask(posted_from_, 162 GetTaskRunner()->PostDelayedTask(posted_from_,
156 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)), 163 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)),
157 delay); 164 delay);
158 scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay; 165 scheduled_run_time_ = desired_run_time_ = TimeTicks::Now() + delay;
159 } else { 166 } else {
160 GetTaskRunner()->PostTask(posted_from_, 167 GetTaskRunner()->PostTask(posted_from_,
161 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_))); 168 base::Bind(&BaseTimerTaskInternal::Run, base::Owned(scheduled_task_)));
162 scheduled_run_time_ = desired_run_time_ = TimeTicks(); 169 scheduled_run_time_ = desired_run_time_ = TimeTicks();
163 } 170 }
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 } 171 }
171 172
172 scoped_refptr<SingleThreadTaskRunner> Timer::GetTaskRunner() { 173 scoped_refptr<SequencedTaskRunner> Timer::GetTaskRunner() {
173 return task_runner_.get() ? task_runner_ : ThreadTaskRunnerHandle::Get(); 174 return task_runner_.get() ? task_runner_ : SequencedTaskRunnerHandle::Get();
174 } 175 }
175 176
176 void Timer::AbandonScheduledTask() { 177 void Timer::AbandonScheduledTask() {
177 DCHECK(thread_id_ == 0 || 178 DCHECK(sequence_checker_.CalledOnValidSequencedThread());
178 thread_id_ == static_cast<int>(PlatformThread::CurrentId()));
179 if (scheduled_task_) { 179 if (scheduled_task_) {
180 scheduled_task_->Abandon(); 180 scheduled_task_->Abandon();
181 scheduled_task_ = NULL; 181 scheduled_task_ = NULL;
182 } 182 }
183 } 183 }
184 184
185 void Timer::RunScheduledTask() { 185 void Timer::RunScheduledTask() {
186 // Task may have been disabled. 186 // Task may have been disabled.
187 if (!is_running_) 187 if (!is_running_)
188 return; 188 return;
(...skipping 20 matching lines...) Expand all
209 PostNewScheduledTask(delay_); 209 PostNewScheduledTask(delay_);
210 else 210 else
211 Stop(); 211 Stop();
212 212
213 task.Run(); 213 task.Run();
214 214
215 // No more member accesses here: *this could be deleted at this point. 215 // No more member accesses here: *this could be deleted at this point.
216 } 216 }
217 217
218 } // namespace base 218 } // namespace base
OLDNEW
« base/timer/timer.h ('K') | « base/timer/timer.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698