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 <sys/timerfd.h> | 7 #include <sys/timerfd.h> |
8 | 8 |
9 #include "base/bind.h" | 9 #include "base/bind.h" |
10 #include "base/bind_helpers.h" | 10 #include "base/bind_helpers.h" |
11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
12 #include "base/lazy_instance.h" | 12 #include "base/lazy_instance.h" |
13 #include "base/logging.h" | 13 #include "base/logging.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/message_loop/message_loop.h" | 15 #include "base/message_loop/message_loop.h" |
16 #include "base/message_loop/message_loop_proxy.h" | |
17 #include "base/pending_task.h" | 16 #include "base/pending_task.h" |
| 17 #include "base/thread_task_runner_handle.h" |
18 #include "base/threading/thread.h" | 18 #include "base/threading/thread.h" |
19 | 19 |
20 namespace timers { | 20 namespace timers { |
21 namespace { | 21 namespace { |
22 // This class represents the IO thread that the AlarmTimer::Delegate may use for | 22 // This class represents the IO thread that the AlarmTimer::Delegate may use for |
23 // watching file descriptors if it gets called from a thread that does not have | 23 // watching file descriptors if it gets called from a thread that does not have |
24 // a MessageLoopForIO. It is a lazy global instance because it may not always | 24 // a MessageLoopForIO. It is a lazy global instance because it may not always |
25 // be necessary. | 25 // be necessary. |
26 class RtcAlarmIOThread : public base::Thread { | 26 class RtcAlarmIOThread : public base::Thread { |
27 public: | 27 public: |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 | 101 |
102 // Resets the timer to fire after |delay| has passed. Cancels any | 102 // Resets the timer to fire after |delay| has passed. Cancels any |
103 // pre-existing delay. | 103 // pre-existing delay. |
104 void Reset(base::TimeDelta delay); | 104 void Reset(base::TimeDelta delay); |
105 | 105 |
106 // Stops the currently running timer. It should be safe to call this even if | 106 // Stops the currently running timer. It should be safe to call this even if |
107 // the timer is not running. | 107 // the timer is not running. |
108 void Stop(); | 108 void Stop(); |
109 | 109 |
110 // Sets a hook that will be called when the timer fires and a task has been | 110 // Sets a hook that will be called when the timer fires and a task has been |
111 // queued on |origin_message_loop_|. Used by tests to wait until a task is | 111 // queued on |origin_task_runner_|. Used by tests to wait until a task is |
112 // pending in the MessageLoop. | 112 // pending in the MessageLoop. |
113 void SetTimerFiredCallbackForTest(base::Closure test_callback); | 113 void SetTimerFiredCallbackForTest(base::Closure test_callback); |
114 | 114 |
115 // base::MessageLoopForIO::Watcher overrides. | 115 // base::MessageLoopForIO::Watcher overrides. |
116 void OnFileCanReadWithoutBlocking(int fd) override; | 116 void OnFileCanReadWithoutBlocking(int fd) override; |
117 void OnFileCanWriteWithoutBlocking(int fd) override; | 117 void OnFileCanWriteWithoutBlocking(int fd) override; |
118 | 118 |
119 private: | 119 private: |
120 friend class base::RefCountedThreadSafe<Delegate>; | 120 friend class base::RefCountedThreadSafe<Delegate>; |
121 ~Delegate() override; | 121 ~Delegate() override; |
122 | 122 |
123 // Actually performs the system calls to set up the timer. This must be | 123 // Actually performs the system calls to set up the timer. This must be |
124 // called on a MessageLoopForIO. | 124 // called on a MessageLoopForIO. |
125 void ResetImpl(base::TimeDelta delay, int reset_sequence_number); | 125 void ResetImpl(base::TimeDelta delay, int reset_sequence_number); |
126 | 126 |
127 // Callback that is run when the timer fires. Must be run on | 127 // Callback that is run when the timer fires. Must be run on |
128 // |origin_message_loop_|. | 128 // |origin_task_runner_|. |
129 void OnTimerFired(int reset_sequence_number); | 129 void OnTimerFired(int reset_sequence_number); |
130 | 130 |
131 // File descriptor associated with the alarm timer. | 131 // File descriptor associated with the alarm timer. |
132 int alarm_fd_; | 132 int alarm_fd_; |
133 | 133 |
134 // Message loop which initially started the timer. | 134 // Task runner which initially started the timer. |
135 scoped_refptr<base::MessageLoopProxy> origin_message_loop_; | 135 scoped_refptr<base::SingleThreadTaskRunner> origin_task_runner_; |
136 | 136 |
137 // Callback that should be run when the timer fires. | 137 // Callback that should be run when the timer fires. |
138 base::Closure on_timer_fired_callback_; | 138 base::Closure on_timer_fired_callback_; |
139 | 139 |
140 // Hook used by tests to be notified when the timer has fired and a task has | 140 // Hook used by tests to be notified when the timer has fired and a task has |
141 // been queued in the MessageLoop. | 141 // been queued in the MessageLoop. |
142 base::Closure on_timer_fired_callback_for_test_; | 142 base::Closure on_timer_fired_callback_for_test_; |
143 | 143 |
144 // Manages watching file descriptors. | 144 // Manages watching file descriptors. |
145 scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> fd_watcher_; | 145 scoped_ptr<base::MessageLoopForIO::FileDescriptorWatcher> fd_watcher_; |
146 | 146 |
147 // The sequence numbers of the last Reset() call handled respectively on | 147 // The sequence numbers of the last Reset() call handled respectively on |
148 // |origin_message_loop_| and on the MessageLoopForIO used for watching the | 148 // |origin_task_runner_| and on the MessageLoopForIO used for watching the |
149 // timer file descriptor. Note that these can be the same MessageLoop. | 149 // timer file descriptor. Note that these can be the same MessageLoop. |
150 // OnTimerFired() runs |on_timer_fired_callback_| only if the sequence number | 150 // OnTimerFired() runs |on_timer_fired_callback_| only if the sequence number |
151 // it receives from the MessageLoopForIO matches | 151 // it receives from the MessageLoopForIO matches |
152 // |origin_reset_sequence_number_|. | 152 // |origin_reset_sequence_number_|. |
153 int origin_reset_sequence_number_; | 153 int origin_reset_sequence_number_; |
154 int io_reset_sequence_number_; | 154 int io_reset_sequence_number_; |
155 | 155 |
156 DISALLOW_COPY_AND_ASSIGN(Delegate); | 156 DISALLOW_COPY_AND_ASSIGN(Delegate); |
157 }; | 157 }; |
158 | 158 |
(...skipping 11 matching lines...) Expand all Loading... |
170 AlarmTimer::Delegate::~Delegate() { | 170 AlarmTimer::Delegate::~Delegate() { |
171 if (alarm_fd_ != -1) | 171 if (alarm_fd_ != -1) |
172 close(alarm_fd_); | 172 close(alarm_fd_); |
173 } | 173 } |
174 | 174 |
175 bool AlarmTimer::Delegate::CanWakeFromSuspend() { | 175 bool AlarmTimer::Delegate::CanWakeFromSuspend() { |
176 return alarm_fd_ != -1; | 176 return alarm_fd_ != -1; |
177 } | 177 } |
178 | 178 |
179 void AlarmTimer::Delegate::Reset(base::TimeDelta delay) { | 179 void AlarmTimer::Delegate::Reset(base::TimeDelta delay) { |
180 // Get a proxy for the current message loop. When the timer fires, we will | 180 // Get a task runner for the current message loop. When the timer fires, we |
| 181 // will |
181 // post tasks to this proxy to let the parent timer know. | 182 // post tasks to this proxy to let the parent timer know. |
182 origin_message_loop_ = base::MessageLoopProxy::current(); | 183 origin_task_runner_ = base::ThreadTaskRunnerHandle::Get(); |
183 | 184 |
184 // Increment the sequence number. Used to invalidate any events that have | 185 // Increment the sequence number. Used to invalidate any events that have |
185 // been queued but not yet run since the last time Reset() was called. | 186 // been queued but not yet run since the last time Reset() was called. |
186 origin_reset_sequence_number_++; | 187 origin_reset_sequence_number_++; |
187 | 188 |
188 // Calling timerfd_settime with a zero delay actually clears the timer so if | 189 // Calling timerfd_settime with a zero delay actually clears the timer so if |
189 // the user has requested a zero delay timer, we need to handle it | 190 // the user has requested a zero delay timer, we need to handle it |
190 // differently. We queue the task here but we still go ahead and call | 191 // differently. We queue the task here but we still go ahead and call |
191 // timerfd_settime with the zero delay anyway to cancel any previous delay | 192 // timerfd_settime with the zero delay anyway to cancel any previous delay |
192 // that might have been programmed. | 193 // that might have been programmed. |
193 if (delay <= base::TimeDelta::FromMicroseconds(0)) { | 194 if (delay <= base::TimeDelta::FromMicroseconds(0)) { |
194 // The timerfd_settime documentation is vague on what happens when it is | 195 // The timerfd_settime documentation is vague on what happens when it is |
195 // passed a negative delay. We can sidestep the issue by ensuring that | 196 // passed a negative delay. We can sidestep the issue by ensuring that |
196 // the delay is 0. | 197 // the delay is 0. |
197 delay = base::TimeDelta::FromMicroseconds(0); | 198 delay = base::TimeDelta::FromMicroseconds(0); |
198 origin_message_loop_->PostTask( | 199 origin_task_runner_->PostTask( |
199 FROM_HERE, | 200 FROM_HERE, |
200 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), | 201 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), |
201 origin_reset_sequence_number_)); | 202 origin_reset_sequence_number_)); |
202 } | 203 } |
203 | 204 |
204 // Run ResetImpl() on a MessageLoopForIO. | 205 // Run ResetImpl() on a MessageLoopForIO. |
205 if (base::MessageLoopForIO::IsCurrent()) { | 206 if (base::MessageLoopForIO::IsCurrent()) { |
206 ResetImpl(delay, origin_reset_sequence_number_); | 207 ResetImpl(delay, origin_reset_sequence_number_); |
207 } else { | 208 } else { |
208 g_io_thread.Pointer()->task_runner()->PostTask( | 209 g_io_thread.Pointer()->task_runner()->PostTask( |
(...skipping 23 matching lines...) Expand all Loading... |
232 | 233 |
233 void AlarmTimer::Delegate::OnFileCanReadWithoutBlocking(int fd) { | 234 void AlarmTimer::Delegate::OnFileCanReadWithoutBlocking(int fd) { |
234 DCHECK_EQ(alarm_fd_, fd); | 235 DCHECK_EQ(alarm_fd_, fd); |
235 | 236 |
236 // Read from the fd to ack the event. | 237 // Read from the fd to ack the event. |
237 char val[sizeof(uint64_t)]; | 238 char val[sizeof(uint64_t)]; |
238 if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t))) | 239 if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t))) |
239 PLOG(DFATAL) << "Unable to read from timer file descriptor."; | 240 PLOG(DFATAL) << "Unable to read from timer file descriptor."; |
240 | 241 |
241 // Make sure that the parent timer is informed on the proper message loop. | 242 // Make sure that the parent timer is informed on the proper message loop. |
242 if (origin_message_loop_->RunsTasksOnCurrentThread()) { | 243 if (origin_task_runner_->RunsTasksOnCurrentThread()) { |
243 OnTimerFired(io_reset_sequence_number_); | 244 OnTimerFired(io_reset_sequence_number_); |
244 } else { | 245 } else { |
245 origin_message_loop_->PostTask( | 246 origin_task_runner_->PostTask( |
246 FROM_HERE, | 247 FROM_HERE, |
247 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), | 248 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), |
248 io_reset_sequence_number_)); | 249 io_reset_sequence_number_)); |
249 } | 250 } |
250 } | 251 } |
251 | 252 |
252 void AlarmTimer::Delegate::OnFileCanWriteWithoutBlocking(int fd) { | 253 void AlarmTimer::Delegate::OnFileCanWriteWithoutBlocking(int fd) { |
253 NOTREACHED(); | 254 NOTREACHED(); |
254 } | 255 } |
255 | 256 |
(...skipping 28 matching lines...) Expand all Loading... |
284 itimerspec alarm_time = {}; | 285 itimerspec alarm_time = {}; |
285 alarm_time.it_value.tv_sec = delay.InSeconds(); | 286 alarm_time.it_value.tv_sec = delay.InSeconds(); |
286 alarm_time.it_value.tv_nsec = | 287 alarm_time.it_value.tv_nsec = |
287 (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) * | 288 (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) * |
288 base::Time::kNanosecondsPerMicrosecond; | 289 base::Time::kNanosecondsPerMicrosecond; |
289 if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0) | 290 if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0) |
290 PLOG(ERROR) << "Error while setting alarm time. Timer will not fire"; | 291 PLOG(ERROR) << "Error while setting alarm time. Timer will not fire"; |
291 } | 292 } |
292 | 293 |
293 void AlarmTimer::Delegate::OnTimerFired(int reset_sequence_number) { | 294 void AlarmTimer::Delegate::OnTimerFired(int reset_sequence_number) { |
294 DCHECK(origin_message_loop_->RunsTasksOnCurrentThread()); | 295 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread()); |
295 | 296 |
296 // If a test wants to be notified when this function is about to run, then | 297 // If a test wants to be notified when this function is about to run, then |
297 // re-queue this task in the MessageLoop and run the test's callback. | 298 // re-queue this task in the MessageLoop and run the test's callback. |
298 if (!on_timer_fired_callback_for_test_.is_null()) { | 299 if (!on_timer_fired_callback_for_test_.is_null()) { |
299 origin_message_loop_->PostTask( | 300 origin_task_runner_->PostTask( |
300 FROM_HERE, | 301 FROM_HERE, |
301 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), | 302 base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this), |
302 reset_sequence_number)); | 303 reset_sequence_number)); |
303 | 304 |
304 on_timer_fired_callback_for_test_.Run(); | 305 on_timer_fired_callback_for_test_.Run(); |
305 on_timer_fired_callback_for_test_.Reset(); | 306 on_timer_fired_callback_for_test_.Reset(); |
306 return; | 307 return; |
307 } | 308 } |
308 | 309 |
309 // Check to make sure that the timer was not reset in the time between when | 310 // Check to make sure that the timer was not reset in the time between when |
(...skipping 147 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
457 SimpleAlarmTimer::SimpleAlarmTimer(const tracked_objects::Location& posted_from, | 458 SimpleAlarmTimer::SimpleAlarmTimer(const tracked_objects::Location& posted_from, |
458 base::TimeDelta delay, | 459 base::TimeDelta delay, |
459 const base::Closure& user_task) | 460 const base::Closure& user_task) |
460 : AlarmTimer(posted_from, delay, user_task, false) { | 461 : AlarmTimer(posted_from, delay, user_task, false) { |
461 } | 462 } |
462 | 463 |
463 SimpleAlarmTimer::~SimpleAlarmTimer() { | 464 SimpleAlarmTimer::~SimpleAlarmTimer() { |
464 } | 465 } |
465 | 466 |
466 } // namespace timers | 467 } // namespace timers |
OLD | NEW |