xref: /aosp_15_r20/system/chre/platform/linux/system_timer.cc (revision 84e339476a462649f82315436d70fd732297a399)
1*84e33947SAndroid Build Coastguard Worker /*
2*84e33947SAndroid Build Coastguard Worker  * Copyright (C) 2016 The Android Open Source Project
3*84e33947SAndroid Build Coastguard Worker  *
4*84e33947SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*84e33947SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*84e33947SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*84e33947SAndroid Build Coastguard Worker  *
8*84e33947SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*84e33947SAndroid Build Coastguard Worker  *
10*84e33947SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*84e33947SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*84e33947SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*84e33947SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*84e33947SAndroid Build Coastguard Worker  * limitations under the License.
15*84e33947SAndroid Build Coastguard Worker  */
16*84e33947SAndroid Build Coastguard Worker 
17*84e33947SAndroid Build Coastguard Worker #include "chre/platform/system_timer.h"
18*84e33947SAndroid Build Coastguard Worker 
19*84e33947SAndroid Build Coastguard Worker #include <errno.h>
20*84e33947SAndroid Build Coastguard Worker #include <signal.h>
21*84e33947SAndroid Build Coastguard Worker #include <string.h>
22*84e33947SAndroid Build Coastguard Worker 
23*84e33947SAndroid Build Coastguard Worker #include <cinttypes>
24*84e33947SAndroid Build Coastguard Worker #include <mutex>
25*84e33947SAndroid Build Coastguard Worker #include <unordered_set>
26*84e33947SAndroid Build Coastguard Worker 
27*84e33947SAndroid Build Coastguard Worker #include "chre/platform/log.h"
28*84e33947SAndroid Build Coastguard Worker #include "chre/util/time.h"
29*84e33947SAndroid Build Coastguard Worker 
30*84e33947SAndroid Build Coastguard Worker namespace chre {
31*84e33947SAndroid Build Coastguard Worker 
32*84e33947SAndroid Build Coastguard Worker namespace {
33*84e33947SAndroid Build Coastguard Worker 
34*84e33947SAndroid Build Coastguard Worker constexpr uint64_t kOneSecondInNanoseconds = 1000000000;
35*84e33947SAndroid Build Coastguard Worker std::unordered_set<SystemTimer *> gActiveTimerInstances;
36*84e33947SAndroid Build Coastguard Worker std::mutex gGlobalTimerMutex;
37*84e33947SAndroid Build Coastguard Worker 
NanosecondsToTimespec(uint64_t ns,struct timespec * ts)38*84e33947SAndroid Build Coastguard Worker void NanosecondsToTimespec(uint64_t ns, struct timespec *ts) {
39*84e33947SAndroid Build Coastguard Worker   ts->tv_sec = ns / kOneSecondInNanoseconds;
40*84e33947SAndroid Build Coastguard Worker   ts->tv_nsec = ns % kOneSecondInNanoseconds;
41*84e33947SAndroid Build Coastguard Worker }
42*84e33947SAndroid Build Coastguard Worker 
43*84e33947SAndroid Build Coastguard Worker }  // anonymous namespace
44*84e33947SAndroid Build Coastguard Worker 
systemTimerNotifyCallback(union sigval cookie)45*84e33947SAndroid Build Coastguard Worker void SystemTimerBase::systemTimerNotifyCallback(union sigval cookie) {
46*84e33947SAndroid Build Coastguard Worker   SystemTimer *sysTimer = static_cast<SystemTimer *>(cookie.sival_ptr);
47*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> globalLock(gGlobalTimerMutex);
48*84e33947SAndroid Build Coastguard Worker   if (gActiveTimerInstances.find(sysTimer) != gActiveTimerInstances.end()) {
49*84e33947SAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(sysTimer->mMutex);
50*84e33947SAndroid Build Coastguard Worker     sysTimer->mCallback(sysTimer->mData);
51*84e33947SAndroid Build Coastguard Worker   }
52*84e33947SAndroid Build Coastguard Worker }
53*84e33947SAndroid Build Coastguard Worker 
SystemTimer()54*84e33947SAndroid Build Coastguard Worker SystemTimer::SystemTimer() {
55*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> globalLock(gGlobalTimerMutex);
56*84e33947SAndroid Build Coastguard Worker   gActiveTimerInstances.insert(this);
57*84e33947SAndroid Build Coastguard Worker }
58*84e33947SAndroid Build Coastguard Worker 
~SystemTimer()59*84e33947SAndroid Build Coastguard Worker SystemTimer::~SystemTimer() {
60*84e33947SAndroid Build Coastguard Worker   std::lock_guard<std::mutex> globalLock(gGlobalTimerMutex);
61*84e33947SAndroid Build Coastguard Worker   gActiveTimerInstances.erase(this);
62*84e33947SAndroid Build Coastguard Worker   if (mInitialized) {
63*84e33947SAndroid Build Coastguard Worker     int ret = timer_delete(mTimerId);
64*84e33947SAndroid Build Coastguard Worker     if (ret != 0) {
65*84e33947SAndroid Build Coastguard Worker       LOGE("Couldn't delete timer: %s", strerror(errno));
66*84e33947SAndroid Build Coastguard Worker     }
67*84e33947SAndroid Build Coastguard Worker     mInitialized = false;
68*84e33947SAndroid Build Coastguard Worker   }
69*84e33947SAndroid Build Coastguard Worker }
70*84e33947SAndroid Build Coastguard Worker 
init()71*84e33947SAndroid Build Coastguard Worker bool SystemTimer::init() {
72*84e33947SAndroid Build Coastguard Worker   if (mInitialized) {
73*84e33947SAndroid Build Coastguard Worker     LOGW("Tried re-initializing timer");
74*84e33947SAndroid Build Coastguard Worker   } else {
75*84e33947SAndroid Build Coastguard Worker     struct sigevent sigevt = {};
76*84e33947SAndroid Build Coastguard Worker     sigevt.sigev_notify = SIGEV_THREAD;
77*84e33947SAndroid Build Coastguard Worker     sigevt.sigev_value.sival_ptr = this;
78*84e33947SAndroid Build Coastguard Worker     sigevt.sigev_notify_function = systemTimerNotifyCallback;
79*84e33947SAndroid Build Coastguard Worker     sigevt.sigev_notify_attributes = nullptr;
80*84e33947SAndroid Build Coastguard Worker 
81*84e33947SAndroid Build Coastguard Worker     int ret = timer_create(CLOCK_MONOTONIC, &sigevt, &mTimerId);
82*84e33947SAndroid Build Coastguard Worker     if (ret != 0) {
83*84e33947SAndroid Build Coastguard Worker       LOGE("Couldn't create timer: %s", strerror(errno));
84*84e33947SAndroid Build Coastguard Worker     } else {
85*84e33947SAndroid Build Coastguard Worker       mInitialized = true;
86*84e33947SAndroid Build Coastguard Worker     }
87*84e33947SAndroid Build Coastguard Worker   }
88*84e33947SAndroid Build Coastguard Worker 
89*84e33947SAndroid Build Coastguard Worker   return mInitialized;
90*84e33947SAndroid Build Coastguard Worker }
91*84e33947SAndroid Build Coastguard Worker 
set(SystemTimerCallback * callback,void * data,Nanoseconds delay)92*84e33947SAndroid Build Coastguard Worker bool SystemTimer::set(SystemTimerCallback *callback, void *data,
93*84e33947SAndroid Build Coastguard Worker                       Nanoseconds delay) {
94*84e33947SAndroid Build Coastguard Worker   if (!mInitialized) {
95*84e33947SAndroid Build Coastguard Worker     return false;
96*84e33947SAndroid Build Coastguard Worker   }
97*84e33947SAndroid Build Coastguard Worker 
98*84e33947SAndroid Build Coastguard Worker   // 0 has a special meaning in POSIX, i.e. cancel the timer. In our API, a
99*84e33947SAndroid Build Coastguard Worker   // value of 0 just means fire right away.
100*84e33947SAndroid Build Coastguard Worker   if (delay.toRawNanoseconds() == 0) {
101*84e33947SAndroid Build Coastguard Worker     delay = Nanoseconds(1);
102*84e33947SAndroid Build Coastguard Worker   }
103*84e33947SAndroid Build Coastguard Worker 
104*84e33947SAndroid Build Coastguard Worker   {
105*84e33947SAndroid Build Coastguard Worker     std::lock_guard<std::mutex> lock(mMutex);
106*84e33947SAndroid Build Coastguard Worker     mCallback = callback;
107*84e33947SAndroid Build Coastguard Worker     mData = data;
108*84e33947SAndroid Build Coastguard Worker   }
109*84e33947SAndroid Build Coastguard Worker   return setInternal(delay.toRawNanoseconds());
110*84e33947SAndroid Build Coastguard Worker }
111*84e33947SAndroid Build Coastguard Worker 
cancel()112*84e33947SAndroid Build Coastguard Worker bool SystemTimer::cancel() {
113*84e33947SAndroid Build Coastguard Worker   if (mInitialized) {
114*84e33947SAndroid Build Coastguard Worker     // Setting delay to 0 disarms the timer.
115*84e33947SAndroid Build Coastguard Worker     return setInternal(0);
116*84e33947SAndroid Build Coastguard Worker   }
117*84e33947SAndroid Build Coastguard Worker   return false;
118*84e33947SAndroid Build Coastguard Worker }
119*84e33947SAndroid Build Coastguard Worker 
isActive()120*84e33947SAndroid Build Coastguard Worker bool SystemTimer::isActive() {
121*84e33947SAndroid Build Coastguard Worker   bool isActive = false;
122*84e33947SAndroid Build Coastguard Worker   if (mInitialized) {
123*84e33947SAndroid Build Coastguard Worker     struct itimerspec spec = {};
124*84e33947SAndroid Build Coastguard Worker     int ret = timer_gettime(mTimerId, &spec);
125*84e33947SAndroid Build Coastguard Worker     if (ret != 0) {
126*84e33947SAndroid Build Coastguard Worker       LOGE("Couldn't obtain current timer configuration: %s", strerror(errno));
127*84e33947SAndroid Build Coastguard Worker     }
128*84e33947SAndroid Build Coastguard Worker 
129*84e33947SAndroid Build Coastguard Worker     isActive = (spec.it_value.tv_sec > 0 || spec.it_value.tv_nsec > 0);
130*84e33947SAndroid Build Coastguard Worker   }
131*84e33947SAndroid Build Coastguard Worker 
132*84e33947SAndroid Build Coastguard Worker   return isActive;
133*84e33947SAndroid Build Coastguard Worker }
134*84e33947SAndroid Build Coastguard Worker 
setInternal(uint64_t delayNs)135*84e33947SAndroid Build Coastguard Worker bool SystemTimerBase::setInternal(uint64_t delayNs) {
136*84e33947SAndroid Build Coastguard Worker   constexpr int kFlags = 0;
137*84e33947SAndroid Build Coastguard Worker   struct itimerspec spec = {};
138*84e33947SAndroid Build Coastguard Worker 
139*84e33947SAndroid Build Coastguard Worker   NanosecondsToTimespec(delayNs, &spec.it_value);
140*84e33947SAndroid Build Coastguard Worker   NanosecondsToTimespec(0, &spec.it_interval);
141*84e33947SAndroid Build Coastguard Worker 
142*84e33947SAndroid Build Coastguard Worker   int ret = timer_settime(mTimerId, kFlags, &spec, nullptr);
143*84e33947SAndroid Build Coastguard Worker   if (ret != 0) {
144*84e33947SAndroid Build Coastguard Worker     LOGE("Couldn't set timer: %s", strerror(errno));
145*84e33947SAndroid Build Coastguard Worker     return false;
146*84e33947SAndroid Build Coastguard Worker   }
147*84e33947SAndroid Build Coastguard Worker   return true;
148*84e33947SAndroid Build Coastguard Worker }
149*84e33947SAndroid Build Coastguard Worker 
150*84e33947SAndroid Build Coastguard Worker }  // namespace chre
151