| 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 |