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 #ifndef CHRE_CORE_TIMER_POOL_H_ 18 #define CHRE_CORE_TIMER_POOL_H_ 19 20 #include "chre_api/chre/re.h" 21 22 #include "chre/core/event_loop_common.h" 23 #include "chre/core/nanoapp.h" 24 #include "chre/platform/mutex.h" 25 #include "chre/platform/system_timer.h" 26 #include "chre/util/non_copyable.h" 27 #include "chre/util/priority_queue.h" 28 29 namespace chre { 30 31 /** 32 * The type to use when referring to a timer instance. 33 * 34 * Note that this mirrors the CHRE API definition of a timer handle, so should 35 * not be changed without appropriate consideration. 36 */ 37 typedef uint32_t TimerHandle; 38 39 /** 40 * Tracks requests from CHRE apps for timed events. 41 */ 42 class TimerPool : public NonCopyable { 43 public: 44 /** 45 * Sets up the timer instance initial conditions. 46 */ 47 TimerPool(); 48 49 /** 50 * Requests a timer for a nanoapp given a cookie to pass to the nanoapp when 51 * the timer event is published. 52 * 53 * @param nanoapp The nanoapp for which this timer is being requested. 54 * @param duration The duration of the timer. 55 * @param cookie A cookie to pass to the app when the timer elapses. 56 * @param isOneShot false if the timer is expected to auto-reload. 57 * @return TimerHandle of the requested timer. Returns CHRE_TIMER_INVALID if 58 * not successful. 59 */ setNanoappTimer(const Nanoapp * nanoapp,Nanoseconds duration,const void * cookie,bool isOneShot)60 TimerHandle setNanoappTimer(const Nanoapp *nanoapp, Nanoseconds duration, 61 const void *cookie, bool isOneShot) { 62 CHRE_ASSERT(nanoapp != nullptr); 63 return setTimer(nanoapp->getInstanceId(), duration, cookie, 64 nullptr /* systemCallback */, 65 SystemCallbackType::FirstCallbackType, isOneShot); 66 } 67 68 /** 69 * Requests a timer for a system callback. When the timer expires, the 70 * specified SystemCallbackFunction will be processed in the context of the 71 * main CHRE event loop. Note that it is not immediately invoked when the 72 * timer expires. If no system timers are available, this method will trigger 73 * a fatal error. 74 * 75 * Safe to invoke from any thread. 76 * 77 * @param duration The duration to set the timer for. 78 * @param callback The callback to invoke when the timer expires. 79 * @param callbackType The type of this callback. 80 * @param data Arbitrary data to pass to the callback. Note that extraData is 81 * always given to the callback as nullptr. 82 * @return TimerHandle of the requested timer. 83 */ 84 TimerHandle setSystemTimer(Nanoseconds duration, 85 SystemEventCallbackFunction *callback, 86 SystemCallbackType callbackType, void *data); 87 88 /** 89 * Cancels a timer given a handle. 90 * 91 * @param nanoapp The nanoapp requesting a timer to be cancelled. 92 * @param timerHandle The handle for a timer to be cancelled. 93 * @return false if the timer handle is invalid or is not owned by the nanoapp 94 */ cancelNanoappTimer(const Nanoapp * nanoapp,TimerHandle timerHandle)95 bool cancelNanoappTimer(const Nanoapp *nanoapp, TimerHandle timerHandle) { 96 CHRE_ASSERT(nanoapp != nullptr); 97 return cancelTimer(nanoapp->getInstanceId(), timerHandle); 98 } 99 100 /** 101 * Cancels a timer created by setSystemTimer() given a handle. 102 * 103 * @param timerHandle The handle for a timer to be cancelled. 104 * @return false if the timer handle is invalid or is not owned by the system 105 */ cancelSystemTimer(TimerHandle timerHandle)106 bool cancelSystemTimer(TimerHandle timerHandle) { 107 return cancelTimer(kSystemInstanceId, timerHandle); 108 } 109 110 private: 111 /** 112 * Tracks metadata associated with a request for a timed event. 113 */ 114 struct TimerRequest { 115 //! The instance ID from which this request was made 116 uint32_t instanceId; 117 TimerHandle timerHandle; 118 Nanoseconds expirationTime; 119 Nanoseconds duration; 120 121 //! The cookie pointer to be passed as an event to the requesting nanoapp, 122 //! or data pointer for system callbacks. 123 const void *cookie; 124 125 //! If a system timer (instanceId == kSystemInstanceId), callback to invoke 126 //! after the timer expires, otherwise nullptr 127 SystemEventCallbackFunction *systemCallback; 128 129 //! Only relevant if this is a system timer 130 SystemCallbackType callbackType; 131 132 //! Whether or not the request is a one shot or should be rescheduled. 133 bool isOneShot; 134 135 /** 136 * Provides a greater than comparison of TimerRequests. 137 * 138 * @param request The other request to compare against. 139 * @return Returns true if this request is greater than the provided 140 * request. 141 */ 142 bool operator>(const TimerRequest &request) const; 143 }; 144 145 //! The queue of outstanding timer requests. 146 PriorityQueue<TimerRequest, std::greater<TimerRequest>> mTimerRequests; 147 148 //! The underlying system timer used to schedule delayed callbacks. 149 SystemTimer mSystemTimer; 150 151 //! The next timer handle for generateTimerHandleLocked() to return. 152 TimerHandle mLastTimerHandle = CHRE_TIMER_INVALID; 153 154 //! Max number of timers that can be requested. 155 static constexpr size_t kMaxTimerRequests = 64; 156 157 //! The number of timers that must be available for all nanoapps 158 //! (per CHRE API). 159 static constexpr size_t kNumReservedNanoappTimers = 32; 160 161 //! Max number of timers that can be allocated for nanoapps. Must be at least 162 //! as large as kNumReservedNanoappTimers. 163 static constexpr size_t kMaxNanoappTimers = 32; 164 165 static_assert(kMaxNanoappTimers >= kNumReservedNanoappTimers, 166 "Max number of nanoapp timers is too small"); 167 168 //! Whether or not the timer handle generation logic needs to perform a 169 //! search for a vacant timer handle. 170 bool mGenerateTimerHandleMustCheckUniqueness = false; 171 172 //! The mutex to lock when using this class. 173 Mutex mMutex; 174 175 //! The number of active nanoapp timers. 176 size_t mNumNanoappTimers = 0; 177 178 /** 179 * Requests a timer given a cookie to pass to the CHRE event loop when the 180 * timer event is published. 181 * 182 * @param instanceId The instance ID of the caller. 183 * @param duration The duration of the timer. 184 * @param cookie A cookie to pass to the app when the timer elapses. 185 * @param systemCallback Callback to invoke (only for system-started timers). 186 * @param callbackType Identifier to pass to the callback. 187 * @param isOneShot false if the timer is expected to auto-reload. 188 * @return TimerHandle of the requested timer. Returns CHRE_TIMER_INVALID if 189 * not successful. 190 */ 191 TimerHandle setTimer(uint32_t instanceId, Nanoseconds duration, 192 const void *cookie, 193 SystemEventCallbackFunction *systemCallback, 194 SystemCallbackType callbackType, bool isOneShot); 195 196 /** 197 * Cancels a timer given a handle. 198 * 199 * @param instanceId The instance ID of the caller. 200 * @param timerHandle The handle for a timer to be cancelled. 201 * @return false if the timer handle is invalid or is not owned by the caller 202 */ 203 bool cancelTimer(uint32_t instanceId, TimerHandle timerHandle); 204 205 /** 206 * Looks up a timer request given a timer handle. mMutex must be acquired 207 * prior to calling this function. 208 * 209 * @param timerHandle The timer handle referring to a given request. 210 * @param index A pointer to the index of the handle. If the handle is found 211 * this will be populated with the index of the request from the list 212 * of requests. This is optional and will only be populated if not 213 * nullptr. 214 * @return A pointer to a TimerRequest or nullptr if no match is found. 215 */ 216 TimerRequest *getTimerRequestByTimerHandleLocked(TimerHandle timerHandle, 217 size_t *index = nullptr); 218 219 /** 220 * Obtains a unique timer handle to return to an app requesting a timer. 221 * mMutex must be acquired prior to calling this function. 222 * 223 * @return The guaranteed unique timer handle. 224 */ 225 TimerHandle generateTimerHandleLocked(); 226 227 /** 228 * Obtains a unique timer handle by searching through the list of timer 229 * requests. This is a fallback for once the timer handles have been 230 * exhausted. mMutex must be acquired prior to calling this function. 231 * 232 * @return A guaranteed unique timer handle. 233 */ 234 TimerHandle generateUniqueTimerHandleLocked(); 235 236 /** 237 * Helper function to determine whether a new timer of the specified type 238 * can be allocated. mMutex must be acquired prior to calling this function. 239 * 240 * @param isNanoappTimer true if invoked for a nanoapp timer. 241 * @return true if a new timer of the given type is allowed to be allocated. 242 */ 243 bool isNewTimerAllowedLocked(bool isNanoappTimer) const; 244 245 /** 246 * Inserts a TimerRequest into the list of active timer requests. The order of 247 * mTimerRequests is always maintained such that the timer request with the 248 * closest expiration time is at the front of the list. mMutex must be 249 * acquired prior to calling this function. 250 * 251 * @param timerRequest The timer request being inserted into the list. 252 * @return true if insertion of timer succeeds. 253 */ 254 bool insertTimerRequestLocked(const TimerRequest &timerRequest); 255 256 /** 257 * Pops the TimerRequest at the front of the list. mMutex must be acquired 258 * prior to calling this function. 259 */ 260 void popTimerRequestLocked(); 261 262 /** 263 * Removes the TimerRequest at the specified index of the list. mMutex must be 264 * acquired prior to calling this function. 265 * 266 * @param index The index of the TimerRequest to remove. 267 */ 268 void removeTimerRequestLocked(size_t index); 269 270 /** 271 * Sets the underlying system timer to the next timer in the timer list if 272 * available. 273 * 274 * @return true if at least one timer had expired 275 */ 276 bool handleExpiredTimersAndScheduleNext(); 277 278 /** 279 * Same as handleExpiredTimersAndScheduleNext(), except mMutex must be 280 * acquired prior to calling this function. 281 * 282 * @return true if at least one timer had expired 283 */ 284 bool handleExpiredTimersAndScheduleNextLocked(); 285 286 /** 287 * This static method handles the callback from the system timer. The data 288 * pointer here is the TimerPool instance. 289 * 290 * @param data A pointer to the timer pool. 291 */ 292 static void handleSystemTimerCallback(void *timerPoolPtr); 293 }; 294 295 } // namespace chre 296 297 #endif // CHRE_CORE_TIMER_POOL_H_ 298