blob: 601b411bd7a2daa9bbc10a0c7976f6c48f6b8073 [file] [log] [blame]
chirantanc88389f2015-04-08 05:43:11 +09001// 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
avi2f891b62015-12-26 07:30:46 +09007#include <stdint.h>
chirantanc88389f2015-04-08 05:43:11 +09008#include <sys/timerfd.h>
fdoray5db52172016-10-12 02:31:13 +09009
10#include <algorithm>
dcheng968547c2015-12-31 13:54:47 +090011#include <utility>
chirantanc88389f2015-04-08 05:43:11 +090012
13#include "base/bind.h"
fdoray5db52172016-10-12 02:31:13 +090014#include "base/debug/task_annotator.h"
chirantanc88389f2015-04-08 05:43:11 +090015#include "base/files/file_util.h"
chirantanc88389f2015-04-08 05:43:11 +090016#include "base/logging.h"
fdoray5db52172016-10-12 02:31:13 +090017#include "base/memory/ptr_util.h"
chirantanc88389f2015-04-08 05:43:11 +090018#include "base/pending_task.h"
caseq341a9612015-07-17 04:13:21 +090019#include "base/trace_event/trace_event.h"
chirantanc88389f2015-04-08 05:43:11 +090020
21namespace timers {
chirantanc88389f2015-04-08 05:43:11 +090022
fdoray5db52172016-10-12 02:31:13 +090023AlarmTimer::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)),
26 weak_factory_(this) {}
chirantanc88389f2015-04-08 05:43:11 +090027
fdoray5db52172016-10-12 02:31:13 +090028AlarmTimer::~AlarmTimer() {
29 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
30 Stop();
chirantanc88389f2015-04-08 05:43:11 +090031}
32
fdoray5db52172016-10-12 02:31:13 +090033void AlarmTimer::Stop() {
34 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
chirantanc88389f2015-04-08 05:43:11 +090035
fdoray5db52172016-10-12 02:31:13 +090036 if (!base::Timer::is_running())
37 return;
chirantanc88389f2015-04-08 05:43:11 +090038
fdoray5db52172016-10-12 02:31:13 +090039 if (!CanWakeFromSuspend()) {
40 base::Timer::Stop();
chirantanc88389f2015-04-08 05:43:11 +090041 return;
42 }
43
fdoray5db52172016-10-12 02:31:13 +090044 // Cancel any previous callbacks.
45 weak_factory_.InvalidateWeakPtrs();
chirantanc88389f2015-04-08 05:43:11 +090046
fdoray5db52172016-10-12 02:31:13 +090047 base::Timer::set_is_running(false);
48 alarm_fd_watcher_.reset();
49 pending_task_.reset();
50
51 if (!base::Timer::retain_user_task())
52 base::Timer::set_user_task(base::Closure());
chirantanc88389f2015-04-08 05:43:11 +090053}
54
fdoray5db52172016-10-12 02:31:13 +090055void AlarmTimer::Reset() {
56 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
57 DCHECK(!base::Timer::user_task().is_null());
chirantanc88389f2015-04-08 05:43:11 +090058
fdoray5db52172016-10-12 02:31:13 +090059 if (!CanWakeFromSuspend()) {
60 base::Timer::Reset();
61 return;
chirantanc88389f2015-04-08 05:43:11 +090062 }
63
fdoray5db52172016-10-12 02:31:13 +090064 // Cancel any previous callbacks and stop watching |alarm_fd_|.
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.
chirantanc88389f2015-04-08 05:43:11 +090082 itimerspec alarm_time = {};
83 alarm_time.it_value.tv_sec = delay.InSeconds();
84 alarm_time.it_value.tv_nsec =
85 (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) *
86 base::Time::kNanosecondsPerMicrosecond;
87 if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0)
88 PLOG(ERROR) << "Error while setting alarm time. Timer will not fire";
chirantanc88389f2015-04-08 05:43:11 +090089
fdoray5db52172016-10-12 02:31:13 +090090 // The timer is running.
91 base::Timer::set_is_running(true);
fdorayf7084ad2016-10-07 04:03:34 +090092
fdoray5db52172016-10-12 02:31:13 +090093 // If the delay is zero, post the task now.
94 if (delay.is_zero()) {
naskod3fd0db2016-10-07 06:22:32 +090095 origin_task_runner_->PostTask(
96 FROM_HERE,
fdoray5db52172016-10-12 02:31:13 +090097 base::Bind(&AlarmTimer::OnTimerFired, weak_factory_.GetWeakPtr()));
naskod3fd0db2016-10-07 06:22:32 +090098 } else {
fdoray5db52172016-10-12 02:31:13 +090099 // 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()));
naskod3fd0db2016-10-07 06:22:32 +0900106 }
naskod3fd0db2016-10-07 06:22:32 +0900107}
108
fdoray5db52172016-10-12 02:31:13 +0900109void AlarmTimer::OnAlarmFdReadableWithoutBlocking() {
110 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
111 DCHECK(base::Timer::IsRunning());
112
113 // Read from |alarm_fd_| to ack the event.
114 char val[sizeof(uint64_t)];
115 if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t)))
116 PLOG(DFATAL) << "Unable to read from timer file descriptor.";
117
118 OnTimerFired();
chirantanc88389f2015-04-08 05:43:11 +0900119}
120
121void AlarmTimer::OnTimerFired() {
fdoray5db52172016-10-12 02:31:13 +0900122 DCHECK(origin_task_runner_->RunsTasksOnCurrentThread());
123 DCHECK(base::Timer::IsRunning());
chirantanc88389f2015-04-08 05:43:11 +0900124 DCHECK(pending_task_.get());
125
fdoray5db52172016-10-12 02:31:13 +0900126 // Take ownership of the PendingTask to prevent it from being deleted if the
127 // AlarmTimer is deleted.
128 const auto pending_user_task = std::move(pending_task_);
chirantanc88389f2015-04-08 05:43:11 +0900129
fdoray5db52172016-10-12 02:31:13 +0900130 base::WeakPtr<AlarmTimer> weak_ptr = weak_factory_.GetWeakPtr();
chirantanc88389f2015-04-08 05:43:11 +0900131
fdoray5db52172016-10-12 02:31:13 +0900132 // Run the task.
caseq341a9612015-07-17 04:13:21 +0900133 TRACE_TASK_EXECUTION("AlarmTimer::OnTimerFired", *pending_user_task);
tzike82b7e82016-10-14 23:34:58 +0900134 base::debug::TaskAnnotator().RunTask("AlarmTimer::Reset",
135 pending_user_task.get());
caseq341a9612015-07-17 04:13:21 +0900136
fdoray5db52172016-10-12 02:31:13 +0900137 // If the timer wasn't deleted, stopped or reset by the callback, reset or
138 // stop it.
139 if (weak_ptr.get()) {
140 if (base::Timer::is_repeating())
141 Reset();
142 else
143 Stop();
144 }
145}
146
147bool AlarmTimer::CanWakeFromSuspend() const {
148 return alarm_fd_ != -1;
chirantanc88389f2015-04-08 05:43:11 +0900149}
150
151OneShotAlarmTimer::OneShotAlarmTimer() : AlarmTimer(false, false) {
152}
153
154OneShotAlarmTimer::~OneShotAlarmTimer() {
155}
156
157RepeatingAlarmTimer::RepeatingAlarmTimer() : AlarmTimer(true, true) {
158}
159
chirantanc88389f2015-04-08 05:43:11 +0900160RepeatingAlarmTimer::~RepeatingAlarmTimer() {
161}
162
163SimpleAlarmTimer::SimpleAlarmTimer() : AlarmTimer(true, false) {
164}
165
chirantanc88389f2015-04-08 05:43:11 +0900166SimpleAlarmTimer::~SimpleAlarmTimer() {
167}
168
169} // namespace timers