• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_chromeos.h"
6 
7 #include <stdint.h>
8 #include <sys/timerfd.h>
9 #include <utility>
10 
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/files/file_util.h"
14 #include "base/lazy_instance.h"
15 #include "base/logging.h"
16 #include "base/macros.h"
17 #include "base/message_loop/message_loop.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"
22 
23 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:
RtcAlarmIOThread()31   RtcAlarmIOThread() : Thread("RTC Alarm IO Thread") {
32     CHECK(
33         StartWithOptions(base::Thread::Options(base::MessageLoop::TYPE_IO, 0)));
34   }
~RtcAlarmIOThread()35   ~RtcAlarmIOThread() override { Stop(); }
36 };
37 
38 base::LazyInstance<RtcAlarmIOThread> g_io_thread = LAZY_INSTANCE_INITIALIZER;
39 
40 }  // namespace
41 
42 // Watches a MessageLoop and runs a callback if that MessageLoop will be
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.
MessageLoopObserver(base::MessageLoop * message_loop,base::Closure on_will_be_destroyed_callback)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 
~MessageLoopObserver()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.
WillDestroyCurrentMessageLoop()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 
Delegate(base::Closure on_timer_fired_callback)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 }
172 
~Delegate()173 AlarmTimer::Delegate::~Delegate() {
174   if (alarm_fd_ != -1)
175     close(alarm_fd_);
176 }
177 
CanWakeFromSuspend()178 bool AlarmTimer::Delegate::CanWakeFromSuspend() {
179   return alarm_fd_ != -1;
180 }
181 
Reset(base::TimeDelta delay)182 void AlarmTimer::Delegate::Reset(base::TimeDelta delay) {
183   // Get a task runner for the current message loop.  When the timer fires, we
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 
Stop()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;
225   }
226 
227   // Stop watching for events.
228   fd_watcher_.reset();
229 
230   // Now clear the timer.
231   DCHECK_NE(alarm_fd_, -1);
232 #if defined(ANDROID)
233   itimerspec blank_time;
234   memset(&blank_time, 0, sizeof(blank_time));
235 #else
236   itimerspec blank_time = {};
237 #endif  // defined(ANDROID)
238   if (timerfd_settime(alarm_fd_, 0, &blank_time, NULL) < 0)
239     PLOG(ERROR) << "Unable to clear alarm time.  Timer may still fire.";
240 }
241 
OnFileCanReadWithoutBlocking(int fd)242 void AlarmTimer::Delegate::OnFileCanReadWithoutBlocking(int fd) {
243   DCHECK_EQ(alarm_fd_, fd);
244 
245   // Read from the fd to ack the event.
246   char val[sizeof(uint64_t)];
247   if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t)))
248     PLOG(DFATAL) << "Unable to read from timer file descriptor.";
249 
250   // Make sure that the parent timer is informed on the proper message loop.
251   if (origin_task_runner_->RunsTasksOnCurrentThread()) {
252     OnTimerFired(io_reset_sequence_number_);
253   } else {
254     origin_task_runner_->PostTask(
255         FROM_HERE,
256         base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this),
257                    io_reset_sequence_number_));
258   }
259 }
260 
OnFileCanWriteWithoutBlocking(int)261 void AlarmTimer::Delegate::OnFileCanWriteWithoutBlocking(int /*fd*/) {
262   NOTREACHED();
263 }
264 
SetTimerFiredCallbackForTest(base::Closure test_callback)265 void AlarmTimer::Delegate::SetTimerFiredCallbackForTest(
266     base::Closure test_callback) {
267   on_timer_fired_callback_for_test_ = test_callback;
268 }
269 
ResetImpl(base::TimeDelta delay,int reset_sequence_number)270 void AlarmTimer::Delegate::ResetImpl(base::TimeDelta delay,
271                                      int reset_sequence_number) {
272   DCHECK(base::MessageLoopForIO::IsCurrent());
273   DCHECK_NE(alarm_fd_, -1);
274 
275   // Store the sequence number in the IO thread variable.  When the timer
276   // fires, we will bind this value to the OnTimerFired callback to ensure
277   // that we do the right thing if the timer gets reset.
278   io_reset_sequence_number_ = reset_sequence_number;
279 
280   // If we were already watching the fd, this will stop watching it.
281   fd_watcher_.reset(new base::MessageLoopForIO::FileDescriptorWatcher);
282 
283   // Start watching the fd to see when the timer fires.
284   if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
285           alarm_fd_, false, base::MessageLoopForIO::WATCH_READ,
286           fd_watcher_.get(), this)) {
287     LOG(ERROR) << "Error while attempting to watch file descriptor for RTC "
288                << "alarm.  Timer will not fire.";
289   }
290 
291   // Actually set the timer.  This will also clear the pre-existing timer, if
292   // any.
293 #if defined(ANDROID)
294   itimerspec alarm_time;
295   memset(&alarm_time, 0, sizeof(alarm_time));
296 #else
297   itimerspec alarm_time = {};
298 #endif  // defined(ANDROID)
299   alarm_time.it_value.tv_sec = delay.InSeconds();
300   alarm_time.it_value.tv_nsec =
301       (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) *
302       base::Time::kNanosecondsPerMicrosecond;
303   if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0)
304     PLOG(ERROR) << "Error while setting alarm time.  Timer will not fire";
305 }
306 
OnTimerFired(int reset_sequence_number)307 void AlarmTimer::Delegate::OnTimerFired(int reset_sequence_number) {
308   DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
309 
310   // If a test wants to be notified when this function is about to run, then
311   // re-queue this task in the MessageLoop and run the test's callback.
312   if (!on_timer_fired_callback_for_test_.is_null()) {
313     origin_task_runner_->PostTask(
314         FROM_HERE,
315         base::Bind(&Delegate::OnTimerFired, scoped_refptr<Delegate>(this),
316                    reset_sequence_number));
317 
318     on_timer_fired_callback_for_test_.Run();
319     on_timer_fired_callback_for_test_.Reset();
320     return;
321   }
322 
323   // Check to make sure that the timer was not reset in the time between when
324   // this task was queued to run and now.  If it was reset, then don't do
325   // anything.
326   if (reset_sequence_number != origin_reset_sequence_number_)
327     return;
328 
329   on_timer_fired_callback_.Run();
330 }
331 
AlarmTimer(bool retain_user_task,bool is_repeating)332 AlarmTimer::AlarmTimer(bool retain_user_task, bool is_repeating)
333     : base::Timer(retain_user_task, is_repeating),
334       can_wake_from_suspend_(false),
335       origin_message_loop_(NULL),
336       weak_factory_(this) {
337   Init();
338 }
339 
AlarmTimer(const tracked_objects::Location & posted_from,base::TimeDelta delay,const base::Closure & user_task,bool is_repeating)340 AlarmTimer::AlarmTimer(const tracked_objects::Location& posted_from,
341                        base::TimeDelta delay,
342                        const base::Closure& user_task,
343                        bool is_repeating)
344     : base::Timer(posted_from, delay, user_task, is_repeating),
345       can_wake_from_suspend_(false),
346       origin_message_loop_(NULL),
347       weak_factory_(this) {
348   Init();
349 }
350 
~AlarmTimer()351 AlarmTimer::~AlarmTimer() {
352   Stop();
353 }
354 
SetTimerFiredCallbackForTest(base::Closure test_callback)355 void AlarmTimer::SetTimerFiredCallbackForTest(base::Closure test_callback) {
356   delegate_->SetTimerFiredCallbackForTest(test_callback);
357 }
358 
Init()359 void AlarmTimer::Init() {
360   delegate_ = make_scoped_refptr(new AlarmTimer::Delegate(
361       base::Bind(&AlarmTimer::OnTimerFired, weak_factory_.GetWeakPtr())));
362   can_wake_from_suspend_ = delegate_->CanWakeFromSuspend();
363 }
364 
Stop()365 void AlarmTimer::Stop() {
366   if (!base::Timer::is_running())
367     return;
368 
369   if (!can_wake_from_suspend_) {
370     base::Timer::Stop();
371     return;
372   }
373 
374   // Clear the running flag, stop the delegate, and delete the pending task.
375   base::Timer::set_is_running(false);
376   delegate_->Stop();
377   pending_task_.reset();
378 
379   // Stop watching |origin_message_loop_|.
380   origin_message_loop_ = NULL;
381   message_loop_observer_.reset();
382 
383   if (!base::Timer::retain_user_task())
384     base::Timer::set_user_task(base::Closure());
385 }
386 
Reset()387 void AlarmTimer::Reset() {
388   if (!can_wake_from_suspend_) {
389     base::Timer::Reset();
390     return;
391   }
392 
393   DCHECK(!base::Timer::user_task().is_null());
394   DCHECK(!origin_message_loop_ ||
395          origin_message_loop_->task_runner()->RunsTasksOnCurrentThread());
396 
397   // Make sure that the timer will stop if the underlying message loop is
398   // destroyed.
399   if (!origin_message_loop_) {
400     origin_message_loop_ = base::MessageLoop::current();
401     message_loop_observer_.reset(new MessageLoopObserver(
402         origin_message_loop_,
403         base::Bind(&AlarmTimer::WillDestroyCurrentMessageLoop,
404                    weak_factory_.GetWeakPtr())));
405   }
406 
407   // Set up the pending task.
408   if (base::Timer::GetCurrentDelay() > base::TimeDelta::FromMicroseconds(0)) {
409     base::Timer::set_desired_run_time(base::TimeTicks::Now() +
410                                       base::Timer::GetCurrentDelay());
411     pending_task_.reset(new base::PendingTask(
412         base::Timer::posted_from(), base::Timer::user_task(),
413         base::Timer::desired_run_time(), true /* nestable */));
414   } else {
415     base::Timer::set_desired_run_time(base::TimeTicks());
416     pending_task_.reset(new base::PendingTask(base::Timer::posted_from(),
417                                               base::Timer::user_task()));
418   }
419   base::MessageLoop::current()->task_annotator()->DidQueueTask(
420       "AlarmTimer::Reset", *pending_task_);
421 
422   // Now start up the timer.
423   delegate_->Reset(base::Timer::GetCurrentDelay());
424   base::Timer::set_is_running(true);
425 }
426 
WillDestroyCurrentMessageLoop()427 void AlarmTimer::WillDestroyCurrentMessageLoop() {
428   Stop();
429 }
430 
OnTimerFired()431 void AlarmTimer::OnTimerFired() {
432   if (!base::Timer::IsRunning())
433     return;
434 
435   DCHECK(pending_task_.get());
436 
437   // Take ownership of the pending user task, which is going to be cleared by
438   // the Stop() or Reset() functions below.
439   std::unique_ptr<base::PendingTask> pending_user_task(
440       std::move(pending_task_));
441 
442   // Re-schedule or stop the timer as requested.
443   if (base::Timer::is_repeating())
444     Reset();
445   else
446     Stop();
447 
448   TRACE_TASK_EXECUTION("AlarmTimer::OnTimerFired", *pending_user_task);
449 
450   // Now run the user task.
451   base::MessageLoop::current()->task_annotator()->RunTask("AlarmTimer::Reset",
452                                                           *pending_user_task);
453 }
454 
OneShotAlarmTimer()455 OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) {
456 }
457 
~OneShotAlarmTimer()458 OneShotAlarmTimer::~OneShotAlarmTimer() {
459 }
460 
RepeatingAlarmTimer()461 RepeatingAlarmTimer::RepeatingAlarmTimer() : AlarmTimer(true, true) {
462 }
463 
RepeatingAlarmTimer(const tracked_objects::Location & posted_from,base::TimeDelta delay,const base::Closure & user_task)464 RepeatingAlarmTimer::RepeatingAlarmTimer(
465     const tracked_objects::Location& posted_from,
466     base::TimeDelta delay,
467     const base::Closure& user_task)
468     : AlarmTimer(posted_from, delay, user_task, true) {
469 }
470 
~RepeatingAlarmTimer()471 RepeatingAlarmTimer::~RepeatingAlarmTimer() {
472 }
473 
SimpleAlarmTimer()474 SimpleAlarmTimer::SimpleAlarmTimer() : AlarmTimer(true, false) {
475 }
476 
SimpleAlarmTimer(const tracked_objects::Location & posted_from,base::TimeDelta delay,const base::Closure & user_task)477 SimpleAlarmTimer::SimpleAlarmTimer(const tracked_objects::Location& posted_from,
478                                    base::TimeDelta delay,
479                                    const base::Closure& user_task)
480     : AlarmTimer(posted_from, delay, user_task, false) {
481 }
482 
~SimpleAlarmTimer()483 SimpleAlarmTimer::~SimpleAlarmTimer() {
484 }
485 
486 }  // namespace timers
487