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