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.
5 #include "components/timers/alarm_timer_chromeos.h"
7 #include <sys/timerfd.h>
10 #include "base/bind_helpers.h"
11 #include "base/files/file_util.h"
12 #include "base/lazy_instance.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/pending_task.h"
17 #include "base/thread_task_runner_handle.h"
18 #include "base/threading/thread.h"
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
24 // a MessageLoopForIO. It is a lazy global instance because it may not always
26 class RtcAlarmIOThread
: public base::Thread
{
28 RtcAlarmIOThread() : Thread("RTC Alarm IO Thread") {
30 StartWithOptions(base::Thread::Options(base::MessageLoop::TYPE_IO
, 0)));
32 ~RtcAlarmIOThread() override
{ Stop(); }
35 base::LazyInstance
<RtcAlarmIOThread
> g_io_thread
= LAZY_INSTANCE_INITIALIZER
;
39 // Watches a MessageLoop and runs a callback if that MessageLoop will be
41 class AlarmTimer::MessageLoopObserver
42 : public base::MessageLoop::DestructionObserver
{
44 // Constructs a MessageLoopObserver that will observe |message_loop| and will
45 // call |on_will_be_destroyed_callback| when |message_loop| is about to be
47 MessageLoopObserver(base::MessageLoop
* message_loop
,
48 base::Closure on_will_be_destroyed_callback
)
49 : message_loop_(message_loop
),
50 on_will_be_destroyed_callback_(on_will_be_destroyed_callback
) {
51 DCHECK(message_loop_
);
52 message_loop_
->AddDestructionObserver(this);
55 ~MessageLoopObserver() override
{
56 // If |message_loop_| was destroyed, then this class will have already
57 // unregistered itself. Doing it again will trigger a warning.
59 message_loop_
->RemoveDestructionObserver(this);
62 // base::MessageLoop::DestructionObserver override.
63 void WillDestroyCurrentMessageLoop() override
{
64 message_loop_
->RemoveDestructionObserver(this);
67 on_will_be_destroyed_callback_
.Run();
71 // The MessageLoop that this class should watch. Is a weak pointer.
72 base::MessageLoop
* message_loop_
;
74 // The callback to run when |message_loop_| will be destroyed.
75 base::Closure on_will_be_destroyed_callback_
;
77 DISALLOW_COPY_AND_ASSIGN(MessageLoopObserver
);
80 // This class manages a Real Time Clock (RTC) alarm, a feature that is available
81 // from linux version 3.11 onwards. It creates a file descriptor for the RTC
82 // alarm timer and then watches that file descriptor to see when it can be read
83 // without blocking, indicating that the timer has fired.
85 // A major problem for this class is that watching file descriptors is only
86 // available on a MessageLoopForIO but there is no guarantee the timer is going
87 // to be created on one. To get around this, the timer has a dedicated thread
88 // with a MessageLoopForIO that posts tasks back to the thread that started the
90 class AlarmTimer::Delegate
91 : public base::RefCountedThreadSafe
<AlarmTimer::Delegate
>,
92 public base::MessageLoopForIO::Watcher
{
94 // Construct a Delegate for the AlarmTimer. It should be safe to call
95 // |on_timer_fired_callback| multiple times.
96 explicit Delegate(base::Closure on_timer_fired_callback
);
98 // Returns true if the system timer managed by this delegate is capable of
99 // waking the system from suspend.
100 bool CanWakeFromSuspend();
102 // Resets the timer to fire after |delay| has passed. Cancels any
103 // pre-existing delay.
104 void Reset(base::TimeDelta delay
);
106 // Stops the currently running timer. It should be safe to call this even if
107 // the timer is not running.
110 // Sets a hook that will be called when the timer fires and a task has been
111 // queued on |origin_task_runner_|. Used by tests to wait until a task is
112 // pending in the MessageLoop.
113 void SetTimerFiredCallbackForTest(base::Closure test_callback
);
115 // base::MessageLoopForIO::Watcher overrides.
116 void OnFileCanReadWithoutBlocking(int fd
) override
;
117 void OnFileCanWriteWithoutBlocking(int fd
) override
;
120 friend class base::RefCountedThreadSafe
<Delegate
>;
121 ~Delegate() override
;
123 // Actually performs the system calls to set up the timer. This must be
124 // called on a MessageLoopForIO.
125 void ResetImpl(base::TimeDelta delay
, int reset_sequence_number
);
127 // Callback that is run when the timer fires. Must be run on
128 // |origin_task_runner_|.
129 void OnTimerFired(int reset_sequence_number
);
131 // File descriptor associated with the alarm timer.
134 // Task runner which initially started the timer.
135 scoped_refptr
<base::SingleThreadTaskRunner
> origin_task_runner_
;
137 // Callback that should be run when the timer fires.
138 base::Closure on_timer_fired_callback_
;
140 // Hook used by tests to be notified when the timer has fired and a task has
141 // been queued in the MessageLoop.
142 base::Closure on_timer_fired_callback_for_test_
;
144 // Manages watching file descriptors.
145 scoped_ptr
<base::MessageLoopForIO::FileDescriptorWatcher
> fd_watcher_
;
147 // The sequence numbers of the last Reset() call handled respectively on
148 // |origin_task_runner_| and on the MessageLoopForIO used for watching the
149 // timer file descriptor. Note that these can be the same MessageLoop.
150 // OnTimerFired() runs |on_timer_fired_callback_| only if the sequence number
151 // it receives from the MessageLoopForIO matches
152 // |origin_reset_sequence_number_|.
153 int origin_reset_sequence_number_
;
154 int io_reset_sequence_number_
;
156 DISALLOW_COPY_AND_ASSIGN(Delegate
);
159 AlarmTimer::Delegate::Delegate(base::Closure on_timer_fired_callback
)
160 : alarm_fd_(timerfd_create(CLOCK_REALTIME_ALARM
, 0)),
161 on_timer_fired_callback_(on_timer_fired_callback
),
162 origin_reset_sequence_number_(0),
163 io_reset_sequence_number_(0) {
164 // The call to timerfd_create above may fail. This is the only indication
165 // that CLOCK_REALTIME_ALARM is not supported on this system.
166 DPLOG_IF(INFO
, (alarm_fd_
== -1))
167 << "CLOCK_REALTIME_ALARM not supported on this system";
170 AlarmTimer::Delegate::~Delegate() {
175 bool AlarmTimer::Delegate::CanWakeFromSuspend() {
176 return alarm_fd_
!= -1;
179 void AlarmTimer::Delegate::Reset(base::TimeDelta delay
) {
180 // Get a task runner for the current message loop. When the timer fires, we
182 // post tasks to this proxy to let the parent timer know.
183 origin_task_runner_
= base::ThreadTaskRunnerHandle::Get();
185 // Increment the sequence number. Used to invalidate any events that have
186 // been queued but not yet run since the last time Reset() was called.
187 origin_reset_sequence_number_
++;
189 // Calling timerfd_settime with a zero delay actually clears the timer so if
190 // the user has requested a zero delay timer, we need to handle it
191 // differently. We queue the task here but we still go ahead and call
192 // timerfd_settime with the zero delay anyway to cancel any previous delay
193 // that might have been programmed.
194 if (delay
<= base::TimeDelta::FromMicroseconds(0)) {
195 // The timerfd_settime documentation is vague on what happens when it is
196 // passed a negative delay. We can sidestep the issue by ensuring that
198 delay
= base::TimeDelta::FromMicroseconds(0);
199 origin_task_runner_
->PostTask(
201 base::Bind(&Delegate::OnTimerFired
, scoped_refptr
<Delegate
>(this),
202 origin_reset_sequence_number_
));
205 // Run ResetImpl() on a MessageLoopForIO.
206 if (base::MessageLoopForIO::IsCurrent()) {
207 ResetImpl(delay
, origin_reset_sequence_number_
);
209 g_io_thread
.Pointer()->task_runner()->PostTask(
211 base::Bind(&Delegate::ResetImpl
, scoped_refptr
<Delegate
>(this), delay
,
212 origin_reset_sequence_number_
));
216 void AlarmTimer::Delegate::Stop() {
217 // Stop the RTC from a MessageLoopForIO.
218 if (!base::MessageLoopForIO::IsCurrent()) {
219 g_io_thread
.Pointer()->task_runner()->PostTask(
220 FROM_HERE
, base::Bind(&Delegate::Stop
, scoped_refptr
<Delegate
>(this)));
224 // Stop watching for events.
227 // Now clear the timer.
228 DCHECK_NE(alarm_fd_
, -1);
229 itimerspec blank_time
= {};
230 if (timerfd_settime(alarm_fd_
, 0, &blank_time
, NULL
) < 0)
231 PLOG(ERROR
) << "Unable to clear alarm time. Timer may still fire.";
234 void AlarmTimer::Delegate::OnFileCanReadWithoutBlocking(int fd
) {
235 DCHECK_EQ(alarm_fd_
, fd
);
237 // Read from the fd to ack the event.
238 char val
[sizeof(uint64_t)];
239 if (!base::ReadFromFD(alarm_fd_
, val
, sizeof(uint64_t)))
240 PLOG(DFATAL
) << "Unable to read from timer file descriptor.";
242 // Make sure that the parent timer is informed on the proper message loop.
243 if (origin_task_runner_
->RunsTasksOnCurrentThread()) {
244 OnTimerFired(io_reset_sequence_number_
);
246 origin_task_runner_
->PostTask(
248 base::Bind(&Delegate::OnTimerFired
, scoped_refptr
<Delegate
>(this),
249 io_reset_sequence_number_
));
253 void AlarmTimer::Delegate::OnFileCanWriteWithoutBlocking(int fd
) {
257 void AlarmTimer::Delegate::SetTimerFiredCallbackForTest(
258 base::Closure test_callback
) {
259 on_timer_fired_callback_for_test_
= test_callback
;
262 void AlarmTimer::Delegate::ResetImpl(base::TimeDelta delay
,
263 int reset_sequence_number
) {
264 DCHECK(base::MessageLoopForIO::IsCurrent());
265 DCHECK_NE(alarm_fd_
, -1);
267 // Store the sequence number in the IO thread variable. When the timer
268 // fires, we will bind this value to the OnTimerFired callback to ensure
269 // that we do the right thing if the timer gets reset.
270 io_reset_sequence_number_
= reset_sequence_number
;
272 // If we were already watching the fd, this will stop watching it.
273 fd_watcher_
.reset(new base::MessageLoopForIO::FileDescriptorWatcher
);
275 // Start watching the fd to see when the timer fires.
276 if (!base::MessageLoopForIO::current()->WatchFileDescriptor(
277 alarm_fd_
, false, base::MessageLoopForIO::WATCH_READ
,
278 fd_watcher_
.get(), this)) {
279 LOG(ERROR
) << "Error while attempting to watch file descriptor for RTC "
280 << "alarm. Timer will not fire.";
283 // Actually set the timer. This will also clear the pre-existing timer, if
285 itimerspec alarm_time
= {};
286 alarm_time
.it_value
.tv_sec
= delay
.InSeconds();
287 alarm_time
.it_value
.tv_nsec
=
288 (delay
.InMicroseconds() % base::Time::kMicrosecondsPerSecond
) *
289 base::Time::kNanosecondsPerMicrosecond
;
290 if (timerfd_settime(alarm_fd_
, 0, &alarm_time
, NULL
) < 0)
291 PLOG(ERROR
) << "Error while setting alarm time. Timer will not fire";
294 void AlarmTimer::Delegate::OnTimerFired(int reset_sequence_number
) {
295 DCHECK(origin_task_runner_
->RunsTasksOnCurrentThread());
297 // If a test wants to be notified when this function is about to run, then
298 // re-queue this task in the MessageLoop and run the test's callback.
299 if (!on_timer_fired_callback_for_test_
.is_null()) {
300 origin_task_runner_
->PostTask(
302 base::Bind(&Delegate::OnTimerFired
, scoped_refptr
<Delegate
>(this),
303 reset_sequence_number
));
305 on_timer_fired_callback_for_test_
.Run();
306 on_timer_fired_callback_for_test_
.Reset();
310 // Check to make sure that the timer was not reset in the time between when
311 // this task was queued to run and now. If it was reset, then don't do
313 if (reset_sequence_number
!= origin_reset_sequence_number_
)
316 on_timer_fired_callback_
.Run();
319 AlarmTimer::AlarmTimer(bool retain_user_task
, bool is_repeating
)
320 : base::Timer(retain_user_task
, is_repeating
),
321 can_wake_from_suspend_(false),
322 origin_message_loop_(NULL
),
323 weak_factory_(this) {
327 AlarmTimer::AlarmTimer(const tracked_objects::Location
& posted_from
,
328 base::TimeDelta delay
,
329 const base::Closure
& user_task
,
331 : base::Timer(posted_from
, delay
, user_task
, is_repeating
),
332 can_wake_from_suspend_(false),
333 origin_message_loop_(NULL
),
334 weak_factory_(this) {
338 AlarmTimer::~AlarmTimer() {
342 void AlarmTimer::SetTimerFiredCallbackForTest(base::Closure test_callback
) {
343 delegate_
->SetTimerFiredCallbackForTest(test_callback
);
346 void AlarmTimer::Init() {
347 delegate_
= make_scoped_refptr(new AlarmTimer::Delegate(
348 base::Bind(&AlarmTimer::OnTimerFired
, weak_factory_
.GetWeakPtr())));
349 can_wake_from_suspend_
= delegate_
->CanWakeFromSuspend();
352 void AlarmTimer::Stop() {
353 if (!can_wake_from_suspend_
) {
358 // Clear the running flag, stop the delegate, and delete the pending task.
359 base::Timer::set_is_running(false);
361 pending_task_
.reset();
363 // Stop watching |origin_message_loop_|.
364 origin_message_loop_
= NULL
;
365 message_loop_observer_
.reset();
367 if (!base::Timer::retain_user_task())
368 base::Timer::set_user_task(base::Closure());
371 void AlarmTimer::Reset() {
372 if (!can_wake_from_suspend_
) {
373 base::Timer::Reset();
377 DCHECK(!base::Timer::user_task().is_null());
378 DCHECK(!origin_message_loop_
||
379 origin_message_loop_
->task_runner()->RunsTasksOnCurrentThread());
381 // Make sure that the timer will stop if the underlying message loop is
383 if (!origin_message_loop_
) {
384 origin_message_loop_
= base::MessageLoop::current();
385 message_loop_observer_
.reset(new MessageLoopObserver(
386 origin_message_loop_
,
387 base::Bind(&AlarmTimer::WillDestroyCurrentMessageLoop
,
388 weak_factory_
.GetWeakPtr())));
391 // Set up the pending task.
392 if (base::Timer::GetCurrentDelay() > base::TimeDelta::FromMicroseconds(0)) {
393 base::Timer::set_desired_run_time(base::TimeTicks::Now() +
394 base::Timer::GetCurrentDelay());
395 pending_task_
.reset(new base::PendingTask(
396 base::Timer::posted_from(), base::Timer::user_task(),
397 base::Timer::desired_run_time(), true /* nestable */));
399 base::Timer::set_desired_run_time(base::TimeTicks());
400 pending_task_
.reset(new base::PendingTask(base::Timer::posted_from(),
401 base::Timer::user_task()));
403 base::MessageLoop::current()->task_annotator()->DidQueueTask(
404 "AlarmTimer::Reset", *pending_task_
);
406 // Now start up the timer.
407 delegate_
->Reset(base::Timer::GetCurrentDelay());
408 base::Timer::set_is_running(true);
411 void AlarmTimer::WillDestroyCurrentMessageLoop() {
415 void AlarmTimer::OnTimerFired() {
416 if (!base::Timer::IsRunning())
419 DCHECK(pending_task_
.get());
421 // Take ownership of the pending user task, which is going to be cleared by
422 // the Stop() or Reset() functions below.
423 scoped_ptr
<base::PendingTask
> pending_user_task(pending_task_
.Pass());
425 // Re-schedule or stop the timer as requested.
426 if (base::Timer::is_repeating())
431 // Now run the user task.
432 base::MessageLoop::current()->task_annotator()->RunTask(
433 "AlarmTimer::Reset", "AlarmTimer::OnTimerFired", *pending_user_task
);
436 OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) {
439 OneShotAlarmTimer::~OneShotAlarmTimer() {
442 RepeatingAlarmTimer::RepeatingAlarmTimer() : AlarmTimer(true, true) {
445 RepeatingAlarmTimer::RepeatingAlarmTimer(
446 const tracked_objects::Location
& posted_from
,
447 base::TimeDelta delay
,
448 const base::Closure
& user_task
)
449 : AlarmTimer(posted_from
, delay
, user_task
, true) {
452 RepeatingAlarmTimer::~RepeatingAlarmTimer() {
455 SimpleAlarmTimer::SimpleAlarmTimer() : AlarmTimer(true, false) {
458 SimpleAlarmTimer::SimpleAlarmTimer(const tracked_objects::Location
& posted_from
,
459 base::TimeDelta delay
,
460 const base::Closure
& user_task
)
461 : AlarmTimer(posted_from
, delay
, user_task
, false) {
464 SimpleAlarmTimer::~SimpleAlarmTimer() {
467 } // namespace timers