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 "chre/platform/log.h" 20 #include "chre/util/time.h" 21 22 #include <errno.h> 23 #include <signal.h> 24 #include <string.h> 25 26 namespace chre { 27 28 namespace { 29 30 constexpr uint64_t kOneSecondInNanoseconds = 1000000000; 31 32 void NanosecondsToTimespec(uint64_t ns, struct timespec *ts) { 33 ts->tv_sec = ns / kOneSecondInNanoseconds; 34 ts->tv_nsec = ns % kOneSecondInNanoseconds; 35 } 36 37 } // anonymous namespace 38 39 void SystemTimerBase::systemTimerNotifyCallback(union sigval cookie) { 40 SystemTimer *sysTimer = static_cast<SystemTimer *>(cookie.sival_ptr); 41 sysTimer->mCallback(sysTimer->mData); 42 } 43 44 SystemTimer::SystemTimer() {} 45 46 SystemTimer::~SystemTimer() { 47 if (mInitialized) { 48 int ret = timer_delete(mTimerId); 49 if (ret != 0) { 50 LOGE("Couldn't delete timer: %s", strerror(errno)); 51 } 52 mInitialized = false; 53 } 54 } 55 56 bool SystemTimer::init() { 57 if (mInitialized) { 58 LOGW("Tried re-initializing timer"); 59 } else { 60 struct sigevent sigevt = {}; 61 sigevt.sigev_notify = SIGEV_THREAD; 62 sigevt.sigev_value.sival_ptr = this; 63 sigevt.sigev_notify_function = systemTimerNotifyCallback; 64 sigevt.sigev_notify_attributes = nullptr; 65 66 int ret = timer_create(CLOCK_MONOTONIC, &sigevt, &mTimerId); 67 if (ret != 0) { 68 LOGE("Couldn't create timer: %s", strerror(errno)); 69 } else { 70 mInitialized = true; 71 } 72 } 73 74 return mInitialized; 75 } 76 77 bool SystemTimer::set(SystemTimerCallback *callback, void *data, 78 Nanoseconds delay) { 79 // 0 has a special meaning in POSIX, i.e. cancel the timer. In our API, a 80 // value of 0 just means fire right away. 81 if (delay.toRawNanoseconds() == 0) { 82 delay = Nanoseconds(1); 83 } 84 85 if (mInitialized) { 86 mCallback = callback; 87 mData = data; 88 return setInternal(delay.toRawNanoseconds()); 89 } else { 90 return false; 91 } 92 } 93 94 bool SystemTimer::cancel() { 95 if (mInitialized) { 96 // Setting delay to 0 disarms the timer. 97 return setInternal(0); 98 } else { 99 return false; 100 } 101 } 102 103 bool SystemTimer::isActive() { 104 bool isActive = false; 105 if (mInitialized) { 106 struct itimerspec spec = {}; 107 int ret = timer_gettime(mTimerId, &spec); 108 if (ret != 0) { 109 LOGE("Couldn't obtain current timer configuration: %s", strerror(errno)); 110 } 111 112 isActive = (spec.it_value.tv_sec > 0 || spec.it_value.tv_nsec > 0); 113 } 114 115 return isActive; 116 } 117 118 bool SystemTimerBase::setInternal(uint64_t delayNs) { 119 constexpr int kFlags = 0; 120 struct itimerspec spec = {}; 121 bool success = false; 122 123 NanosecondsToTimespec(delayNs, &spec.it_value); 124 NanosecondsToTimespec(0, &spec.it_interval); 125 126 int ret = timer_settime(mTimerId, kFlags, &spec, nullptr); 127 if (ret != 0) { 128 LOGE("Couldn't set timer: %s", strerror(errno)); 129 } else { 130 success = true; 131 } 132 133 return success; 134 } 135 136 } // namespace chre 137