OLD | NEW |
---|---|
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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 "components/timers/alarm_timer_chromeos.h" | 5 #include "components/timers/alarm_timer_chromeos.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 #include <sys/timerfd.h> | 8 #include <sys/timerfd.h> |
9 | |
10 #include <algorithm> | |
9 #include <utility> | 11 #include <utility> |
10 | 12 |
11 #include "base/bind.h" | 13 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 14 #include "base/debug/task_annotator.h" |
13 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
14 #include "base/lazy_instance.h" | |
15 #include "base/logging.h" | 16 #include "base/logging.h" |
16 #include "base/macros.h" | 17 #include "base/memory/ptr_util.h" |
17 #include "base/message_loop/message_loop.h" | |
18 #include "base/pending_task.h" | 18 #include "base/pending_task.h" |
19 #include "base/threading/thread.h" | |
20 #include "base/threading/thread_task_runner_handle.h" | |
21 #include "base/trace_event/trace_event.h" | 19 #include "base/trace_event/trace_event.h" |
22 | 20 |
23 namespace timers { | 21 namespace timers { |
24 namespace { | |
25 // This class represents the IO thread that the AlarmTimer::Delegate may use for | |
26 // watching file descriptors if it gets called from a thread that does not have | |
27 // a MessageLoopForIO. It is a lazy global instance because it may not always | |
28 // be necessary. | |
29 class RtcAlarmIOThread : public base::Thread { | |
30 public: | |
31 RtcAlarmIOThread() : Thread("RTC Alarm IO Thread") { | |
32 CHECK( | |
33 StartWithOptions(base::Thread::Options(base::MessageLoop::TYPE_IO, 0))); | |
34 } | |
35 ~RtcAlarmIOThread() override { Stop(); } | |
36 }; | |
37 | 22 |
38 base::LazyInstance<RtcAlarmIOThread> g_io_thread = LAZY_INSTANCE_INITIALIZER; | 23 AlarmTimer::AlarmTimer(bool retain_user_task, bool is_repeating) |
24 : base::Timer(retain_user_task, is_repeating), | |
25 alarm_fd_(timerfd_create(CLOCK_REALTIME_ALARM, 0)), | |
Chirantan Ekbote
2016/10/06 18:41:51
Does this mean it's now ok to make blocking system
fdoray
2016/10/06 18:57:33
No it's not ok. After the migration to TaskSchedul
| |
26 weak_factory_(this) {} | |
39 | 27 |
40 } // namespace | 28 AlarmTimer::~AlarmTimer() { |
41 | 29 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); |
42 // Watches a MessageLoop and runs a callback if that MessageLoop will be | 30 Stop(); |
43 // destroyed. | |
44 class AlarmTimer::MessageLoopObserver | |
45 : public base::MessageLoop::DestructionObserver { | |
46 public: | |
47 // Constructs a MessageLoopObserver that will observe |message_loop| and will | |
48 // call |on_will_be_destroyed_callback| when |message_loop| is about to be | |
49 // destroyed. | |
50 MessageLoopObserver(base::MessageLoop* message_loop, | |
51 base::Closure on_will_be_destroyed_callback) | |
52 : message_loop_(message_loop), | |
53 on_will_be_destroyed_callback_(on_will_be_destroyed_callback) { | |
54 DCHECK(message_loop_); | |
55 message_loop_->AddDestructionObserver(this); | |
56 } | |
57 | |
58 ~MessageLoopObserver() override { | |
59 // If |message_loop_| was destroyed, then this class will have already | |
60 // unregistered itself. Doing it again will trigger a warning. | |
61 if (message_loop_) | |
62 message_loop_->RemoveDestructionObserver(this); | |
63 } | |
64 | |
65 // base::MessageLoop::DestructionObserver override. | |
66 void WillDestroyCurrentMessageLoop() override { | |
67 message_loop_->RemoveDestructionObserver(this); | |
68 message_loop_ = NULL; | |
69 | |
70 on_will_be_destroyed_callback_.Run(); | |
71 } | |
72 | |
73 private: | |
74 // The MessageLoop that this class should watch. Is a weak pointer. | |
75 base::MessageLoop* message_loop_; | |
76 | |
77 // The callback to run when |message_loop_| will be destroyed. | |
78 base::Closure on_will_be_destroyed_callback_; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver); | |
81 }; | |
82 | |
83 // This class manages a Real Time Clock (RTC) alarm, a feature that is available | |
84 // from linux version 3.11 onwards. It creates a file descriptor for the RTC | |
85 // alarm timer and then watches that file descriptor to see when it can be read | |
86 // without blocking, indicating that the timer has fired. | |
87 // | |
88 // A major problem for this class is that watching file descriptors is only | |
89 // available on a MessageLoopForIO but there is no guarantee the timer is going | |
90 // to be created on one. To get around this, the timer has a dedicated thread | |
91 // with a MessageLoopForIO that posts tasks back to the thread that started the | |
92 // timer. | |
93 class AlarmTimer::Delegate | |
94 : public base::RefCountedThreadSafe<AlarmTimer::Delegate>, | |
95 public base::MessageLoopForIO::Watcher { | |
96 public: | |
97 // Construct a Delegate for the AlarmTimer. It should be safe to call | |
98 // |on_timer_fired_callback| multiple times. | |
99 explicit Delegate(base::Closure on_timer_fired_callback); | |
100 | |
101 // Returns true if the system timer managed by this delegate is capable of | |
102 // waking the system from suspend. | |
103 bool CanWakeFromSuspend(); | |
104 | |
105 // Resets the timer to fire after |delay| has passed. Cancels any | |
106 // pre-existing delay. | |
107 void Reset(base::TimeDelta delay); | |
108 | |
109 // Stops the currently running timer. It should be safe to call this even if | |
110 // the timer is not running. | |
111 void Stop(); | |
112 | |
113 // Sets a hook that will be called when the timer fires and a task has been | |
114 // queued on |origin_task_runner_|. Used by tests to wait until a task is | |
115 // pending in the MessageLoop. | |
116 void SetTimerFiredCallbackForTest(base::Closure test_callback); | |
117 | |
118 // base::MessageLoopForIO::Watcher overrides. | |
119 void OnFileCanReadWithoutBlocking(int fd) override; | |
120 void OnFileCanWriteWithoutBlocking(int fd) override; | |
121 | |
122 private: | |
123 friend class base::RefCountedThreadSafe<Delegate>; | |
124 ~Delegate() override; | |
125 | |
126 // Actually performs the system calls to set up the timer. This must be | |
127 // called on a MessageLoopForIO. | |
128 void ResetImpl(base::TimeDelta delay, int reset_sequence_number); | |
129 | |
130 // Callback that is run when the timer fires. Must be run on | |
131 // |origin_task_runner_|. | |
132 void OnTimerFired(int reset_sequence_number); | |
133 | |
134 // File descriptor associated with the alarm timer. | |
135 int alarm_fd_; | |
136 | |
137 // Task runner which initially started the timer. | |
138 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; | |
139 | |
140 // Callback that should be run when the timer fires. | |
141 base::Closure on_timer_fired_callback_; | |
142 | |
143 // Hook used by tests to be notified when the timer has fired and a task has | |
144 // been queued in the MessageLoop. | |
145 base::Closure on_timer_fired_callback_for_test_; | |
146 | |
147 // Manages watching file descriptors. | |
148 std::unique_ptr<base::MessageLoopForIO::FileDescriptorWatcher> fd_watcher_; | |
149 | |
150 // The sequence numbers of the last Reset() call handled respectively on | |
151 // |origin_task_runner_| and on the MessageLoopForIO used for watching the | |
152 // timer file descriptor. Note that these can be the same MessageLoop. | |
153 // OnTimerFired() runs |on_timer_fired_callback_| only if the sequence number | |
154 // it receives from the MessageLoopForIO matches | |
155 // |origin_reset_sequence_number_|. | |
156 int origin_reset_sequence_number_; | |
157 int io_reset_sequence_number_; | |
158 | |
159 DISALLOW_COPY_AND_ASSIGN(Delegate); | |
160 }; | |
161 | |
162 AlarmTimer::Delegate::Delegate(base::Closure on_timer_fired_callback) | |
163 : alarm_fd_(timerfd_create(CLOCK_REALTIME_ALARM, 0)), | |
164 on_timer_fired_callback_(on_timer_fired_callback), | |
165 origin_reset_sequence_number_(0), | |
166 io_reset_sequence_number_(0) { | |
167 // The call to timerfd_create above may fail. This is the only indication | |
168 // that CLOCK_REALTIME_ALARM is not supported on this system. | |
169 DPLOG_IF(INFO, (alarm_fd_ == -1)) | |
170 << "CLOCK_REALTIME_ALARM not supported on this system"; | |
171 } | 31 } |
172 | 32 |
173 AlarmTimer::Delegate::~Delegate() { | 33 void AlarmTimer::Stop() { |
174 if (alarm_fd_ != -1) | 34 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); |
175 close(alarm_fd_); | |
176 } | |
177 | 35 |
178 bool AlarmTimer::Delegate::CanWakeFromSuspend() { | 36 if (!base::Timer::is_running()) |
179 return alarm_fd_ != -1; | 37 return; |
180 } | |
181 | 38 |
182 void AlarmTimer::Delegate::Reset(base::TimeDelta delay) { | 39 if (!CanWakeFromSuspend()) { |
183 // Get a task runner for the current message loop. When the timer fires, we | 40 base::Timer::Stop(); |
184 // will | |
185 // post tasks to this proxy to let the parent timer know. | |
186 origin_task_runner_ = base::ThreadTaskRunnerHandle::Get(); | |
187 | |
188 // Increment the sequence number. Used to invalidate any events that have | |
189 // been queued but not yet run since the last time Reset() was called. | |
190 origin_reset_sequence_number_++; | |
191 | |
192 // Calling timerfd_settime with a zero delay actually clears the timer so if | |
193 // the user has requested a zero delay timer, we need to handle it | |
194 // differently. We queue the task here but we still go ahead and call | |
195 // timerfd_settime with the zero delay anyway to cancel any previous delay | |
196 // that might have been programmed. | |
197 if (delay <= base::TimeDelta::FromMicroseconds(0)) { | |
198 // The timerfd_settime documentation is vague on what happens when it is | |
199 // passed a negative delay. We can sidestep the issue by ensuring that | |
200 // the delay is 0. | |
201 delay = base::TimeDelta::FromMicroseconds(0); | |
202 origin_task_runner_->PostTask( | |
203 FROM_HERE, | |
204 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), | |
205 origin_reset_sequence_number_)); | |
206 } | |
207 | |
208 // Run ResetImpl() on a MessageLoopForIO. | |
209 if (base::MessageLoopForIO::IsCurrent()) { | |
210 ResetImpl(delay, origin_reset_sequence_number_); | |
211 } else { | |
212 g_io_thread.Pointer()->task_runner()->PostTask( | |
213 FROM_HERE, | |
214 base::Bind(&Delegate::ResetImpl, scoped_refptr<Delegate>(this), delay, | |
215 origin_reset_sequence_number_)); | |
216 } | |
217 } | |
218 | |
219 void AlarmTimer::Delegate::Stop() { | |
220 // Stop the RTC from a MessageLoopForIO. | |
221 if (!base::MessageLoopForIO::IsCurrent()) { | |
222 g_io_thread.Pointer()->task_runner()->PostTask( | |
223 FROM_HERE, base::Bind(&Delegate::Stop, scoped_refptr<Delegate>(this))); | |
224 return; | 41 return; |
225 } | 42 } |
226 | 43 |
227 // Stop watching for events. | 44 // Cancel any previous callbacks. |
228 fd_watcher_.reset(); | 45 weak_factory_.InvalidateWeakPtrs(); |
229 | 46 |
230 // Now clear the timer. | 47 base::Timer::set_is_running(false); |
231 DCHECK_NE(alarm_fd_, -1); | 48 alarm_fd_watcher_.reset(); |
232 itimerspec blank_time = {}; | 49 pending_task_.reset(); |
233 if (timerfd_settime(alarm_fd_, 0, &blank_time, NULL) < 0) | 50 |
234 PLOG(ERROR) << "Unable to clear alarm time. Timer may still fire."; | 51 if (!base::Timer::retain_user_task()) |
52 base::Timer::set_user_task(base::Closure()); | |
235 } | 53 } |
236 | 54 |
237 void AlarmTimer::Delegate::OnFileCanReadWithoutBlocking(int fd) { | 55 void AlarmTimer::Reset() { |
238 DCHECK_EQ(alarm_fd_, fd); | 56 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); |
57 DCHECK(!base::Timer::user_task().is_null()); | |
239 | 58 |
240 // Read from the fd to ack the event. | 59 if (!CanWakeFromSuspend()) { |
241 char val[sizeof(uint64_t)]; | 60 base::Timer::Reset(); |
242 if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t))) | 61 return; |
243 PLOG(DFATAL) << "Unable to read from timer file descriptor."; | |
244 | |
245 // Make sure that the parent timer is informed on the proper message loop. | |
246 if (origin_task_runner_->RunsTasksOnCurrentThread()) { | |
247 OnTimerFired(io_reset_sequence_number_); | |
248 } else { | |
249 origin_task_runner_->PostTask( | |
250 FROM_HERE, | |
251 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), | |
252 io_reset_sequence_number_)); | |
253 } | |
254 } | |
255 | |
256 void AlarmTimer::Delegate::OnFileCanWriteWithoutBlocking(int fd) { | |
257 NOTREACHED(); | |
258 } | |
259 | |
260 void AlarmTimer::Delegate::SetTimerFiredCallbackForTest( | |
261 base::Closure test_callback) { | |
262 on_timer_fired_callback_for_test_ = test_callback; | |
263 } | |
264 | |
265 void AlarmTimer::Delegate::ResetImpl(base::TimeDelta delay, | |
266 int reset_sequence_number) { | |
267 DCHECK(base::MessageLoopForIO::IsCurrent()); | |
268 DCHECK_NE(alarm_fd_, -1); | |
269 | |
270 // Store the sequence number in the IO thread variable. When the timer | |
271 // fires, we will bind this value to the OnTimerFired callback to ensure | |
272 // that we do the right thing if the timer gets reset. | |
273 io_reset_sequence_number_ = reset_sequence_number; | |
274 | |
275 // If we were already watching the fd, this will stop watching it. | |
276 fd_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher); | |
277 | |
278 // Start watching the fd to see when the timer fires. | |
279 if (!base::MessageLoopForIO::current()->WatchFileDescriptor( | |
280 alarm_fd_, false, base::MessageLoopForIO::WATCH_READ, | |
281 fd_watcher_.get(), this)) { | |
282 LOG(ERROR) << "Error while attempting to watch file descriptor for RTC " | |
283 << "alarm. Timer will not fire."; | |
284 } | 62 } |
285 | 63 |
286 // Actually set the timer. This will also clear the pre-existing timer, if | 64 // Cancel any previous callbacks and stop watching |alarm_fd_|. |
287 // any. | 65 weak_factory_.InvalidateWeakPtrs(); |
66 alarm_fd_watcher_.reset(); | |
67 | |
68 // Ensure that the delay is not negative. | |
69 const base::TimeDelta delay = | |
70 std::max(base::TimeDelta(), base::Timer::GetCurrentDelay()); | |
71 | |
72 // Set up the pending task. | |
73 base::Timer::set_desired_run_time( | |
74 delay.is_zero() ? base::TimeTicks() : base::TimeTicks::Now() + delay); | |
75 pending_task_ = base::MakeUnique<base::PendingTask>( | |
76 base::Timer::posted_from(), base::Timer::user_task(), | |
77 base::Timer::desired_run_time(), true /* nestable */); | |
78 | |
79 // Set |alarm_fd_| to be signaled when the delay expires. If the delay is | |
80 // zero, |alarm_fd_| will never be signaled. This overrides the previous | |
81 // delay, if any. | |
288 itimerspec alarm_time = {}; | 82 itimerspec alarm_time = {}; |
289 alarm_time.it_value.tv_sec = delay.InSeconds(); | 83 alarm_time.it_value.tv_sec = delay.InSeconds(); |
290 alarm_time.it_value.tv_nsec = | 84 alarm_time.it_value.tv_nsec = |
291 (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) * | 85 (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) * |
292 base::Time::kNanosecondsPerMicrosecond; | 86 base::Time::kNanosecondsPerMicrosecond; |
293 if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0) | 87 if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0) |
294 PLOG(ERROR) << "Error while setting alarm time. Timer will not fire"; | 88 PLOG(ERROR) << "Error while setting alarm time. Timer will not fire"; |
89 | |
90 // The timer is running. | |
91 base::Timer::set_is_running(true); | |
92 | |
93 // If the delay is zero, post the task now. | |
94 if (delay.is_zero()) { | |
95 origin_task_runner_->PostTask( | |
96 FROM_HERE, | |
97 base::Bind(&AlarmTimer::OnTimerFired, weak_factory_.GetWeakPtr())); | |
98 } else { | |
99 // Otherwise, if the delay is not zero, generate a tracing event to indicate | |
100 // that the task was posted and watch |alarm_fd_|. | |
101 base::debug::TaskAnnotator().DidQueueTask("AlarmTimer::Reset", | |
102 *pending_task_); | |
103 alarm_fd_watcher_ = base::FileDescriptorWatcher::WatchReadable( | |
104 alarm_fd_, base::Bind(&AlarmTimer::OnAlarmFdReadableWithoutBlocking, | |
105 weak_factory_.GetWeakPtr())); | |
106 } | |
295 } | 107 } |
296 | 108 |
297 void AlarmTimer::Delegate::OnTimerFired(int reset_sequence_number) { | 109 void AlarmTimer::OnAlarmFdReadableWithoutBlocking() { |
298 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); | 110 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); |
111 DCHECK(base::Timer::IsRunning()); | |
299 | 112 |
300 // If a test wants to be notified when this function is about to run, then | 113 // Read from |alarm_fd_| to ack the event. |
301 // re-queue this task in the MessageLoop and run the test's callback. | 114 char val[sizeof(uint64_t)]; |
302 if (!on_timer_fired_callback_for_test_.is_null()) { | 115 if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t))) |
303 origin_task_runner_->PostTask( | 116 PLOG(DFATAL) << "Unable to read from timer file descriptor."; |
304 FROM_HERE, | |
305 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), | |
306 reset_sequence_number)); | |
307 | 117 |
308 on_timer_fired_callback_for_test_.Run(); | 118 OnTimerFired(); |
309 on_timer_fired_callback_for_test_.Reset(); | |
310 return; | |
311 } | |
312 | |
313 // Check to make sure that the timer was not reset in the time between when | |
314 // this task was queued to run and now. If it was reset, then don't do | |
315 // anything. | |
316 if (reset_sequence_number != origin_reset_sequence_number_) | |
317 return; | |
318 | |
319 on_timer_fired_callback_.Run(); | |
320 } | |
321 | |
322 AlarmTimer::AlarmTimer(bool retain_user_task, bool is_repeating) | |
323 : base::Timer(retain_user_task, is_repeating), | |
324 can_wake_from_suspend_(false), | |
325 origin_message_loop_(NULL), | |
326 weak_factory_(this) { | |
327 Init(); | |
328 } | |
329 | |
330 AlarmTimer::AlarmTimer(const tracked_objects::Location& posted_from, | |
331 base::TimeDelta delay, | |
332 const base::Closure& user_task, | |
333 bool is_repeating) | |
334 : base::Timer(posted_from, delay, user_task, is_repeating), | |
335 can_wake_from_suspend_(false), | |
336 origin_message_loop_(NULL), | |
337 weak_factory_(this) { | |
338 Init(); | |
339 } | |
340 | |
341 AlarmTimer::~AlarmTimer() { | |
342 Stop(); | |
343 } | |
344 | |
345 void AlarmTimer::SetTimerFiredCallbackForTest(base::Closure test_callback) { | |
346 delegate_->SetTimerFiredCallbackForTest(test_callback); | |
347 } | |
348 | |
349 void AlarmTimer::Init() { | |
350 delegate_ = make_scoped_refptr(new AlarmTimer::Delegate( | |
351 base::Bind(&AlarmTimer::OnTimerFired, weak_factory_.GetWeakPtr()))); | |
352 can_wake_from_suspend_ = delegate_->CanWakeFromSuspend(); | |
353 } | |
354 | |
355 void AlarmTimer::Stop() { | |
356 if (!base::Timer::is_running()) | |
357 return; | |
358 | |
359 if (!can_wake_from_suspend_) { | |
360 base::Timer::Stop(); | |
361 return; | |
362 } | |
363 | |
364 // Clear the running flag, stop the delegate, and delete the pending task. | |
365 base::Timer::set_is_running(false); | |
366 delegate_->Stop(); | |
367 pending_task_.reset(); | |
368 | |
369 // Stop watching |origin_message_loop_|. | |
370 origin_message_loop_ = NULL; | |
371 message_loop_observer_.reset(); | |
372 | |
373 if (!base::Timer::retain_user_task()) | |
374 base::Timer::set_user_task(base::Closure()); | |
375 } | |
376 | |
377 void AlarmTimer::Reset() { | |
378 if (!can_wake_from_suspend_) { | |
379 base::Timer::Reset(); | |
380 return; | |
381 } | |
382 | |
383 DCHECK(!base::Timer::user_task().is_null()); | |
384 DCHECK(!origin_message_loop_ || | |
385 origin_message_loop_->task_runner()->RunsTasksOnCurrentThread()); | |
386 | |
387 // Make sure that the timer will stop if the underlying message loop is | |
388 // destroyed. | |
389 if (!origin_message_loop_) { | |
390 origin_message_loop_ = base::MessageLoop::current(); | |
391 message_loop_observer_.reset(new MessageLoopObserver( | |
392 origin_message_loop_, | |
393 base::Bind(&AlarmTimer::WillDestroyCurrentMessageLoop, | |
394 weak_factory_.GetWeakPtr()))); | |
395 } | |
396 | |
397 // Set up the pending task. | |
398 if (base::Timer::GetCurrentDelay() > base::TimeDelta::FromMicroseconds(0)) { | |
399 base::Timer::set_desired_run_time(base::TimeTicks::Now() + | |
400 base::Timer::GetCurrentDelay()); | |
401 pending_task_.reset(new base::PendingTask( | |
402 base::Timer::posted_from(), base::Timer::user_task(), | |
403 base::Timer::desired_run_time(), true /* nestable */)); | |
404 } else { | |
405 base::Timer::set_desired_run_time(base::TimeTicks()); | |
406 pending_task_.reset(new base::PendingTask(base::Timer::posted_from(), | |
407 base::Timer::user_task())); | |
408 } | |
409 base::MessageLoop::current()->task_annotator()->DidQueueTask( | |
410 "AlarmTimer::Reset", *pending_task_); | |
411 | |
412 // Now start up the timer. | |
413 delegate_->Reset(base::Timer::GetCurrentDelay()); | |
414 base::Timer::set_is_running(true); | |
415 } | |
416 | |
417 void AlarmTimer::WillDestroyCurrentMessageLoop() { | |
418 Stop(); | |
419 } | 119 } |
420 | 120 |
421 void AlarmTimer::OnTimerFired() { | 121 void AlarmTimer::OnTimerFired() { |
422 if (!base::Timer::IsRunning()) | 122 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); |
423 return; | 123 DCHECK(base::Timer::IsRunning()); |
424 | |
425 DCHECK(pending_task_.get()); | 124 DCHECK(pending_task_.get()); |
426 | 125 |
427 // Take ownership of the pending user task, which is going to be cleared by | 126 // Take ownership of the PendingTask to prevent it from being deleted if the |
428 // the Stop() or Reset() functions below. | 127 // AlarmTimer is deleted. |
429 std::unique_ptr<base::PendingTask> pending_user_task( | 128 const auto pending_user_task = std::move(pending_task_); |
430 std::move(pending_task_)); | |
431 | 129 |
432 // Re-schedule or stop the timer as requested. | 130 base::WeakPtr<AlarmTimer> weak_ptr = weak_factory_.GetWeakPtr(); |
433 if (base::Timer::is_repeating()) | |
434 Reset(); | |
435 else | |
436 Stop(); | |
437 | 131 |
132 // Run the task. | |
438 TRACE_TASK_EXECUTION("AlarmTimer::OnTimerFired", *pending_user_task); | 133 TRACE_TASK_EXECUTION("AlarmTimer::OnTimerFired", *pending_user_task); |
134 base::debug::TaskAnnotator().RunTask("AlarmTimer::Reset", *pending_user_task); | |
439 | 135 |
440 // Now run the user task. | 136 // If the timer wasn't deleted, stopped or reset by the callback, reset or |
441 base::MessageLoop::current()->task_annotator()->RunTask("AlarmTimer::Reset", | 137 // stop it. |
442 *pending_user_task); | 138 if (weak_ptr.get()) { |
139 if (base::Timer::is_repeating()) | |
140 Reset(); | |
141 else | |
142 Stop(); | |
143 } | |
144 } | |
145 | |
146 bool AlarmTimer::CanWakeFromSuspend() const { | |
147 return alarm_fd_ != -1; | |
443 } | 148 } |
444 | 149 |
445 OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) { | 150 OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) { |
446 } | 151 } |
447 | 152 |
448 OneShotAlarmTimer::~OneShotAlarmTimer() { | 153 OneShotAlarmTimer::~OneShotAlarmTimer() { |
449 } | 154 } |
450 | 155 |
451 RepeatingAlarmTimer::RepeatingAlarmTimer() : AlarmTimer(true, true) { | 156 RepeatingAlarmTimer::RepeatingAlarmTimer() : AlarmTimer(true, true) { |
452 } | 157 } |
453 | 158 |
454 RepeatingAlarmTimer::RepeatingAlarmTimer( | |
455 const tracked_objects::Location& posted_from, | |
456 base::TimeDelta delay, | |
457 const base::Closure& user_task) | |
458 : AlarmTimer(posted_from, delay, user_task, true) { | |
459 } | |
460 | |
461 RepeatingAlarmTimer::~RepeatingAlarmTimer() { | 159 RepeatingAlarmTimer::~RepeatingAlarmTimer() { |
462 } | 160 } |
463 | 161 |
464 SimpleAlarmTimer::SimpleAlarmTimer() : AlarmTimer(true, false) { | 162 SimpleAlarmTimer::SimpleAlarmTimer() : AlarmTimer(true, false) { |
465 } | 163 } |
466 | 164 |
467 SimpleAlarmTimer::SimpleAlarmTimer(const tracked_objects::Location& posted_from, | |
468 base::TimeDelta delay, | |
469 const base::Closure& user_task) | |
470 : AlarmTimer(posted_from, delay, user_task, false) { | |
471 } | |
472 | |
473 SimpleAlarmTimer::~SimpleAlarmTimer() { | 165 SimpleAlarmTimer::~SimpleAlarmTimer() { |
474 } | 166 } |
475 | 167 |
476 } // namespace timers | 168 } // namespace timers |
OLD | NEW |