OLD | NEW |
| (Empty) |
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 | |
3 // found in the LICENSE file. | |
4 | |
5 #include "components/timers/alarm_timer.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/bind_helpers.h" | |
9 #include "base/files/file_util.h" | |
10 #include "base/logging.h" | |
11 #include "base/pending_task.h" | |
12 #include "components/timers/rtc_alarm.h" | |
13 | |
14 namespace timers { | |
15 | |
16 AlarmTimer::AlarmTimer(bool retain_user_task, bool is_repeating) | |
17 : base::Timer(retain_user_task, is_repeating), | |
18 delegate_(new RtcAlarm()), | |
19 can_wake_from_suspend_(false), | |
20 origin_message_loop_(NULL), | |
21 weak_factory_(this) { | |
22 can_wake_from_suspend_ = delegate_->Init(weak_factory_.GetWeakPtr()); | |
23 } | |
24 | |
25 AlarmTimer::AlarmTimer(const tracked_objects::Location& posted_from, | |
26 base::TimeDelta delay, | |
27 const base::Closure& user_task, | |
28 bool is_repeating) | |
29 : base::Timer(posted_from, delay, user_task, is_repeating), | |
30 delegate_(new RtcAlarm()), | |
31 can_wake_from_suspend_(false), | |
32 origin_message_loop_(NULL), | |
33 weak_factory_(this) { | |
34 can_wake_from_suspend_ = delegate_->Init(weak_factory_.GetWeakPtr()); | |
35 } | |
36 | |
37 AlarmTimer::~AlarmTimer() { | |
38 Stop(); | |
39 } | |
40 | |
41 void AlarmTimer::OnTimerFired() { | |
42 if (!base::Timer::IsRunning()) | |
43 return; | |
44 | |
45 DCHECK(pending_task_.get()); | |
46 | |
47 // Take ownership of the pending user task, which is going to be cleared by | |
48 // the Stop() or Reset() functions below. | |
49 scoped_ptr<base::PendingTask> pending_user_task(pending_task_.Pass()); | |
50 | |
51 // Re-schedule or stop the timer as requested. | |
52 if (base::Timer::is_repeating()) | |
53 Reset(); | |
54 else | |
55 Stop(); | |
56 | |
57 // Now run the user task. | |
58 base::MessageLoop::current()->task_annotator()->RunTask( | |
59 "AlarmTimer::Reset", "AlarmTimer::OnTimerFired", *pending_user_task); | |
60 } | |
61 | |
62 void AlarmTimer::Stop() { | |
63 if (!can_wake_from_suspend_) { | |
64 base::Timer::Stop(); | |
65 return; | |
66 } | |
67 | |
68 // Clear the running flag, stop the delegate, and delete the pending task. | |
69 base::Timer::set_is_running(false); | |
70 delegate_->Stop(); | |
71 pending_task_.reset(); | |
72 | |
73 // Stop is called when the AlarmTimer is destroyed so we need to remove | |
74 // ourselves as a MessageLoop::DestructionObserver to prevent a segfault | |
75 // later. | |
76 if (origin_message_loop_) { | |
77 origin_message_loop_->RemoveDestructionObserver(this); | |
78 origin_message_loop_ = NULL; | |
79 } | |
80 | |
81 if (!base::Timer::retain_user_task()) | |
82 base::Timer::set_user_task(base::Closure()); | |
83 } | |
84 | |
85 void AlarmTimer::Reset() { | |
86 if (!can_wake_from_suspend_) { | |
87 base::Timer::Reset(); | |
88 return; | |
89 } | |
90 | |
91 DCHECK(!base::Timer::user_task().is_null()); | |
92 DCHECK(!origin_message_loop_ || | |
93 origin_message_loop_->task_runner()->RunsTasksOnCurrentThread()); | |
94 | |
95 // Make sure that the timer will stop if the underlying message loop is | |
96 // destroyed. | |
97 if (!origin_message_loop_) { | |
98 origin_message_loop_ = base::MessageLoop::current(); | |
99 origin_message_loop_->AddDestructionObserver(this); | |
100 } | |
101 | |
102 // Set up the pending task. | |
103 if (base::Timer::GetCurrentDelay() > base::TimeDelta::FromMicroseconds(0)) { | |
104 base::Timer::set_desired_run_time( | |
105 base::TimeTicks::Now() + base::Timer::GetCurrentDelay()); | |
106 pending_task_.reset(new base::PendingTask(base::Timer::posted_from(), | |
107 base::Timer::user_task(), | |
108 base::Timer::desired_run_time(), | |
109 true /* nestable */)); | |
110 } else { | |
111 base::Timer::set_desired_run_time(base::TimeTicks()); | |
112 pending_task_.reset(new base::PendingTask(base::Timer::posted_from(), | |
113 base::Timer::user_task())); | |
114 } | |
115 base::MessageLoop::current()->task_annotator()->DidQueueTask( | |
116 "AlarmTimer::Reset", *pending_task_); | |
117 | |
118 // Now start up the timer. | |
119 delegate_->Reset(base::Timer::GetCurrentDelay()); | |
120 base::Timer::set_is_running(true); | |
121 } | |
122 | |
123 void AlarmTimer::WillDestroyCurrentMessageLoop() { | |
124 Stop(); | |
125 } | |
126 | |
127 } // namespace timers | |
OLD | NEW |