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