Chromium Code Reviews| 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 |