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