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