xref: /aosp_15_r20/external/libchrome/components/timers/alarm_timer_chromeos.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2014 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "components/timers/alarm_timer_chromeos.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include <stdint.h>
8*635a8641SAndroid Build Coastguard Worker #include <sys/timerfd.h>
9*635a8641SAndroid Build Coastguard Worker 
10*635a8641SAndroid Build Coastguard Worker #include <algorithm>
11*635a8641SAndroid Build Coastguard Worker #include <memory>
12*635a8641SAndroid Build Coastguard Worker #include <utility>
13*635a8641SAndroid Build Coastguard Worker 
14*635a8641SAndroid Build Coastguard Worker #include "base/bind.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/debug/task_annotator.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/files/file_util.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/pending_task.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/trace_event/trace_event.h"
20*635a8641SAndroid Build Coastguard Worker 
21*635a8641SAndroid Build Coastguard Worker namespace timers {
22*635a8641SAndroid Build Coastguard Worker 
SimpleAlarmTimer()23*635a8641SAndroid Build Coastguard Worker SimpleAlarmTimer::SimpleAlarmTimer()
24*635a8641SAndroid Build Coastguard Worker     : alarm_fd_(timerfd_create(CLOCK_REALTIME_ALARM, 0)), weak_factory_(this) {}
25*635a8641SAndroid Build Coastguard Worker 
~SimpleAlarmTimer()26*635a8641SAndroid Build Coastguard Worker SimpleAlarmTimer::~SimpleAlarmTimer() {
27*635a8641SAndroid Build Coastguard Worker   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
28*635a8641SAndroid Build Coastguard Worker   Stop();
29*635a8641SAndroid Build Coastguard Worker }
30*635a8641SAndroid Build Coastguard Worker 
Stop()31*635a8641SAndroid Build Coastguard Worker void SimpleAlarmTimer::Stop() {
32*635a8641SAndroid Build Coastguard Worker   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
33*635a8641SAndroid Build Coastguard Worker 
34*635a8641SAndroid Build Coastguard Worker   if (!IsRunning())
35*635a8641SAndroid Build Coastguard Worker     return;
36*635a8641SAndroid Build Coastguard Worker 
37*635a8641SAndroid Build Coastguard Worker   if (!CanWakeFromSuspend()) {
38*635a8641SAndroid Build Coastguard Worker     base::RetainingOneShotTimer::Stop();
39*635a8641SAndroid Build Coastguard Worker     return;
40*635a8641SAndroid Build Coastguard Worker   }
41*635a8641SAndroid Build Coastguard Worker 
42*635a8641SAndroid Build Coastguard Worker   // Cancel any previous callbacks.
43*635a8641SAndroid Build Coastguard Worker   weak_factory_.InvalidateWeakPtrs();
44*635a8641SAndroid Build Coastguard Worker 
45*635a8641SAndroid Build Coastguard Worker   base::RetainingOneShotTimer::set_is_running(false);
46*635a8641SAndroid Build Coastguard Worker   alarm_fd_watcher_.reset();
47*635a8641SAndroid Build Coastguard Worker   pending_task_.reset();
48*635a8641SAndroid Build Coastguard Worker }
49*635a8641SAndroid Build Coastguard Worker 
Reset()50*635a8641SAndroid Build Coastguard Worker void SimpleAlarmTimer::Reset() {
51*635a8641SAndroid Build Coastguard Worker   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
52*635a8641SAndroid Build Coastguard Worker   DCHECK(!base::RetainingOneShotTimer::user_task().is_null());
53*635a8641SAndroid Build Coastguard Worker 
54*635a8641SAndroid Build Coastguard Worker   if (!CanWakeFromSuspend()) {
55*635a8641SAndroid Build Coastguard Worker     base::RetainingOneShotTimer::Reset();
56*635a8641SAndroid Build Coastguard Worker     return;
57*635a8641SAndroid Build Coastguard Worker   }
58*635a8641SAndroid Build Coastguard Worker 
59*635a8641SAndroid Build Coastguard Worker   // Cancel any previous callbacks and stop watching |alarm_fd_|.
60*635a8641SAndroid Build Coastguard Worker   weak_factory_.InvalidateWeakPtrs();
61*635a8641SAndroid Build Coastguard Worker   alarm_fd_watcher_.reset();
62*635a8641SAndroid Build Coastguard Worker 
63*635a8641SAndroid Build Coastguard Worker   // Ensure that the delay is not negative.
64*635a8641SAndroid Build Coastguard Worker   const base::TimeDelta delay = std::max(
65*635a8641SAndroid Build Coastguard Worker       base::TimeDelta(), base::RetainingOneShotTimer::GetCurrentDelay());
66*635a8641SAndroid Build Coastguard Worker 
67*635a8641SAndroid Build Coastguard Worker   // Set up the pending task.
68*635a8641SAndroid Build Coastguard Worker   base::RetainingOneShotTimer::set_desired_run_time(
69*635a8641SAndroid Build Coastguard Worker       delay.is_zero() ? base::TimeTicks() : base::TimeTicks::Now() + delay);
70*635a8641SAndroid Build Coastguard Worker   pending_task_ = std::make_unique<base::PendingTask>(
71*635a8641SAndroid Build Coastguard Worker       base::RetainingOneShotTimer::posted_from(),
72*635a8641SAndroid Build Coastguard Worker       base::RetainingOneShotTimer::user_task(),
73*635a8641SAndroid Build Coastguard Worker       base::RetainingOneShotTimer::desired_run_time());
74*635a8641SAndroid Build Coastguard Worker 
75*635a8641SAndroid Build Coastguard Worker   // Set |alarm_fd_| to be signaled when the delay expires. If the delay is
76*635a8641SAndroid Build Coastguard Worker   // zero, |alarm_fd_| will never be signaled. This overrides the previous
77*635a8641SAndroid Build Coastguard Worker   // delay, if any.
78*635a8641SAndroid Build Coastguard Worker   itimerspec alarm_time = {};
79*635a8641SAndroid Build Coastguard Worker   alarm_time.it_value.tv_sec = delay.InSeconds();
80*635a8641SAndroid Build Coastguard Worker   alarm_time.it_value.tv_nsec =
81*635a8641SAndroid Build Coastguard Worker       (delay.InMicroseconds() % base::Time::kMicrosecondsPerSecond) *
82*635a8641SAndroid Build Coastguard Worker       base::Time::kNanosecondsPerMicrosecond;
83*635a8641SAndroid Build Coastguard Worker   if (timerfd_settime(alarm_fd_, 0, &alarm_time, NULL) < 0)
84*635a8641SAndroid Build Coastguard Worker     PLOG(ERROR) << "Error while setting alarm time.  Timer will not fire";
85*635a8641SAndroid Build Coastguard Worker 
86*635a8641SAndroid Build Coastguard Worker   // The timer is running.
87*635a8641SAndroid Build Coastguard Worker   base::RetainingOneShotTimer::set_is_running(true);
88*635a8641SAndroid Build Coastguard Worker 
89*635a8641SAndroid Build Coastguard Worker   // If the delay is zero, post the task now.
90*635a8641SAndroid Build Coastguard Worker   if (delay.is_zero()) {
91*635a8641SAndroid Build Coastguard Worker     origin_task_runner_->PostTask(
92*635a8641SAndroid Build Coastguard Worker         FROM_HERE, base::BindOnce(&SimpleAlarmTimer::OnTimerFired,
93*635a8641SAndroid Build Coastguard Worker                                   weak_factory_.GetWeakPtr()));
94*635a8641SAndroid Build Coastguard Worker   } else {
95*635a8641SAndroid Build Coastguard Worker     // Otherwise, if the delay is not zero, generate a tracing event to indicate
96*635a8641SAndroid Build Coastguard Worker     // that the task was posted and watch |alarm_fd_|.
97*635a8641SAndroid Build Coastguard Worker     base::debug::TaskAnnotator().WillQueueTask("SimpleAlarmTimer::Reset",
98*635a8641SAndroid Build Coastguard Worker                                                pending_task_.get());
99*635a8641SAndroid Build Coastguard Worker     alarm_fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
100*635a8641SAndroid Build Coastguard Worker         alarm_fd_,
101*635a8641SAndroid Build Coastguard Worker         base::BindRepeating(&SimpleAlarmTimer::OnAlarmFdReadableWithoutBlocking,
102*635a8641SAndroid Build Coastguard Worker                             weak_factory_.GetWeakPtr()));
103*635a8641SAndroid Build Coastguard Worker   }
104*635a8641SAndroid Build Coastguard Worker }
105*635a8641SAndroid Build Coastguard Worker 
OnAlarmFdReadableWithoutBlocking()106*635a8641SAndroid Build Coastguard Worker void SimpleAlarmTimer::OnAlarmFdReadableWithoutBlocking() {
107*635a8641SAndroid Build Coastguard Worker   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
108*635a8641SAndroid Build Coastguard Worker   DCHECK(base::RetainingOneShotTimer::IsRunning());
109*635a8641SAndroid Build Coastguard Worker 
110*635a8641SAndroid Build Coastguard Worker   // Read from |alarm_fd_| to ack the event.
111*635a8641SAndroid Build Coastguard Worker   char val[sizeof(uint64_t)];
112*635a8641SAndroid Build Coastguard Worker   if (!base::ReadFromFD(alarm_fd_, val, sizeof(uint64_t)))
113*635a8641SAndroid Build Coastguard Worker     PLOG(DFATAL) << "Unable to read from timer file descriptor.";
114*635a8641SAndroid Build Coastguard Worker 
115*635a8641SAndroid Build Coastguard Worker   OnTimerFired();
116*635a8641SAndroid Build Coastguard Worker }
117*635a8641SAndroid Build Coastguard Worker 
OnTimerFired()118*635a8641SAndroid Build Coastguard Worker void SimpleAlarmTimer::OnTimerFired() {
119*635a8641SAndroid Build Coastguard Worker   DCHECK(origin_task_runner_->RunsTasksInCurrentSequence());
120*635a8641SAndroid Build Coastguard Worker   DCHECK(base::RetainingOneShotTimer::IsRunning());
121*635a8641SAndroid Build Coastguard Worker   DCHECK(pending_task_.get());
122*635a8641SAndroid Build Coastguard Worker 
123*635a8641SAndroid Build Coastguard Worker   // Take ownership of the PendingTask to prevent it from being deleted if the
124*635a8641SAndroid Build Coastguard Worker   // SimpleAlarmTimer is deleted.
125*635a8641SAndroid Build Coastguard Worker   const auto pending_user_task = std::move(pending_task_);
126*635a8641SAndroid Build Coastguard Worker 
127*635a8641SAndroid Build Coastguard Worker   base::WeakPtr<SimpleAlarmTimer> weak_ptr = weak_factory_.GetWeakPtr();
128*635a8641SAndroid Build Coastguard Worker 
129*635a8641SAndroid Build Coastguard Worker   // Run the task.
130*635a8641SAndroid Build Coastguard Worker   TRACE_TASK_EXECUTION("SimpleAlarmTimer::OnTimerFired", *pending_user_task);
131*635a8641SAndroid Build Coastguard Worker   base::debug::TaskAnnotator().RunTask("SimpleAlarmTimer::Reset",
132*635a8641SAndroid Build Coastguard Worker                                        pending_user_task.get());
133*635a8641SAndroid Build Coastguard Worker 
134*635a8641SAndroid Build Coastguard Worker   // If the timer wasn't deleted, stopped or reset by the callback, stop it.
135*635a8641SAndroid Build Coastguard Worker   if (weak_ptr)
136*635a8641SAndroid Build Coastguard Worker     Stop();
137*635a8641SAndroid Build Coastguard Worker }
138*635a8641SAndroid Build Coastguard Worker 
CanWakeFromSuspend() const139*635a8641SAndroid Build Coastguard Worker bool SimpleAlarmTimer::CanWakeFromSuspend() const {
140*635a8641SAndroid Build Coastguard Worker   return alarm_fd_ != -1;
141*635a8641SAndroid Build Coastguard Worker }
142*635a8641SAndroid Build Coastguard Worker 
143*635a8641SAndroid Build Coastguard Worker }  // namespace timers
144