1 /*
2 * Copyright (C) 2022 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 #include "chre/platform/fatal_error.h"
19 #include "chre/platform/log.h"
20 #include "chre/util/time.h"
21
22 namespace chre {
23
rtTimerCallback(struct rt_timer * rtTimer)24 void SystemTimerBase::rtTimerCallback(struct rt_timer *rtTimer) {
25 if (rtTimer != nullptr) {
26 SystemTimer *systemTimer = static_cast<SystemTimer *>(rtTimer->private_ptr);
27 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
28 vTaskNotifyGiveFromISR(systemTimer->mCallbackRunnerHandle,
29 &xHigherPriorityTaskWoken);
30 portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
31 }
32 }
33
callbackRunner(void * context)34 void SystemTimerBase::callbackRunner(void *context) {
35 SystemTimer *systemTimer = static_cast<SystemTimer *>(context);
36 if (systemTimer == nullptr) {
37 FATAL_ERROR("Null System Timer");
38 }
39 while (true) {
40 ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
41 SystemTimerCallback *callback = systemTimer->mCallback;
42 if (callback != nullptr) {
43 callback(systemTimer->mData);
44 }
45 }
46 }
47
SystemTimer()48 SystemTimer::SystemTimer() {
49 // Initialize the rtSystemTimer struct.
50 // The timer's callback and the private data won't be changed through the
51 // lifetime so init() should only be run once. The creation of the callback
52 // runner thread is delayed to the call of init().
53 rt_timer_init(&rtSystemTimer, /* func= */ rtTimerCallback, /* data= */ this);
54 }
55
~SystemTimer()56 SystemTimer::~SystemTimer() {
57 // cancel an existing timer if any
58 cancel();
59 // Delete the callback runner thread if it was created
60 if (mCallbackRunnerHandle != nullptr) {
61 vTaskDelete(mCallbackRunnerHandle);
62 mCallbackRunnerHandle = nullptr;
63 }
64 }
65
init()66 bool SystemTimer::init() {
67 if (mInitialized) {
68 return true;
69 }
70 BaseType_t xReturned = xTaskCreate(
71 callbackRunner, kTaskName, kStackDepthWords,
72 /* pvParameters= */ this, kTaskPriority, &mCallbackRunnerHandle);
73 if (xReturned == pdPASS) {
74 mInitialized = true;
75 return true;
76 }
77 LOGE("Failed to create the callback runner thread");
78 return false;
79 }
80
set(SystemTimerCallback * callback,void * data,Nanoseconds delay)81 bool SystemTimer::set(SystemTimerCallback *callback, void *data,
82 Nanoseconds delay) {
83 if (!mInitialized) {
84 LOGW("Timer is not initialized");
85 return false;
86 }
87 cancel();
88 mCallback = callback;
89 mData = data;
90 rt_timer_start(&rtSystemTimer, delay.toRawNanoseconds(),
91 /* oneShot= */ true);
92 return true;
93 }
94
cancel()95 bool SystemTimer::cancel() {
96 // TODO(b/254708051): This usage of critical section is pending confirmation.
97 taskENTER_CRITICAL();
98 if (isActive()) {
99 rt_timer_stop(&rtSystemTimer);
100 }
101 taskEXIT_CRITICAL();
102 return true;
103 }
104
isActive()105 bool SystemTimer::isActive() {
106 return rt_timer_active(&rtSystemTimer);
107 }
108
109 } // namespace chre