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( 61 const Nanoapp *nanoapp, Nanoseconds duration, const void *cookie, 62 bool isOneShot) { 63 CHRE_ASSERT(nanoapp != nullptr); 64 return setTimer(nanoapp->getInstanceId(), duration, nullptr /* callback */, 65 CHRE_EVENT_TIMER, cookie, 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 fatally 73 * error. 74 * 75 * TODO: Consider adding a way to directly invoke a callback after the delay 76 * rather than posting an event. 77 * 78 * @param duration The duration to set the timer for. 79 * @param callback The callback to invoke when the timer expires. 80 * @param callbackType The type of this callback. 81 * @param cookie A cookie to pass to this callback. 82 * @return TimerHandle of the requested timer. 83 */ 84 TimerHandle setSystemTimer( 85 Nanoseconds duration, SystemCallbackFunction *callback, 86 SystemCallbackType callbackType, const void *cookie); 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 118 //! The TimerHandle assigned to this request. 119 TimerHandle timerHandle; 120 121 //! The time when the request was made. 122 Nanoseconds expirationTime; 123 124 //! The requested duration of the timer. 125 Nanoseconds duration; 126 127 //! The callback to invoked after the timer event is posted to CHRE. 128 SystemCallbackFunction *callback; 129 130 //! The cookie pointer to be passed as an event to the requesting nanoapp. 131 const void *cookie; 132 133 //! The event type to post when the timer expires. 134 uint16_t eventType; 135 136 //! Whether or not the request is a one shot or should be rescheduled. 137 bool isOneShot; 138 139 /** 140 * Provides a greater than comparison of TimerRequests. 141 * 142 * @param request The other request to compare against. 143 * @return Returns true if this request is greater than the provided 144 * request. 145 */ 146 bool operator>(const TimerRequest& request) const; 147 }; 148 149 //! The queue of outstanding timer requests. 150 PriorityQueue<TimerRequest, std::greater<TimerRequest>> mTimerRequests; 151 152 //! The underlying system timer used to schedule delayed callbacks. 153 SystemTimer mSystemTimer; 154 155 //! The next timer handle for generateTimerHandleLocked() to return. 156 TimerHandle mLastTimerHandle = CHRE_TIMER_INVALID; 157 158 //! Max number of timers that can be requested. 159 static constexpr size_t kMaxTimerRequests = 64; 160 161 //! The number of timers that must be available for all nanoapps 162 //! (per CHRE API). 163 static constexpr size_t kNumReservedNanoappTimers = 32; 164 165 //! Max number of timers that can be allocated for nanoapps. Must be at least 166 //! as large as kNumReservedNanoappTimers. 167 static constexpr size_t kMaxNanoappTimers = 32; 168 169 static_assert(kMaxNanoappTimers >= kNumReservedNanoappTimers, 170 "Max number of nanoapp timers is too small"); 171 172 //! Whether or not the timer handle generation logic needs to perform a 173 //! search for a vacant timer handle. 174 bool mGenerateTimerHandleMustCheckUniqueness = false; 175 176 //! The mutex to lock when using this class. 177 Mutex mMutex; 178 179 //! The number of active nanoapp timers. 180 size_t mNumNanoappTimers = 0; 181 182 /** 183 * Requests a timer given a cookie to pass to the CHRE event loop when the 184 * timer event is published. 185 * 186 * @param instanceId The instance ID of the caller. 187 * @param duration The duration of the timer. 188 * @param cookie A cookie to pass to the app when the timer elapses. 189 * @param isOneShot false if the timer is expected to auto-reload. 190 * @return TimerHandle of the requested timer. Returns CHRE_TIMER_INVALID if 191 * not successful. 192 */ 193 TimerHandle setTimer( 194 uint32_t instanceId, Nanoseconds duration, 195 SystemCallbackFunction *callback, uint16_t eventType, 196 const void *cookie, bool isOneShot); 197 198 /** 199 * Cancels a timer given a handle. 200 * 201 * @param instanceId The instance ID of the caller. 202 * @param timerHandle The handle for a timer to be cancelled. 203 * @return false if the timer handle is invalid or is not owned by the caller 204 */ 205 bool cancelTimer(uint32_t instanceId, TimerHandle timerHandle); 206 207 /** 208 * Looks up a timer request given a timer handle. mMutex must be acquired 209 * prior to calling this function. 210 * 211 * @param timerHandle The timer handle referring to a given request. 212 * @param index A pointer to the index of the handle. If the handle is found 213 * this will be populated with the index of the request from the list 214 * of requests. This is optional and will only be populated if not 215 * nullptr. 216 * @return A pointer to a TimerRequest or nullptr if no match is found. 217 */ 218 TimerRequest *getTimerRequestByTimerHandleLocked(TimerHandle timerHandle, 219 size_t *index = nullptr); 220 221 /** 222 * Obtains a unique timer handle to return to an app requesting a timer. 223 * mMutex must be acquired prior to calling this function. 224 * 225 * @return The guaranteed unique timer handle. 226 */ 227 TimerHandle generateTimerHandleLocked(); 228 229 /** 230 * Obtains a unique timer handle by searching through the list of timer 231 * requests. This is a fallback for once the timer handles have been 232 * exhausted. mMutex must be acquired prior to calling this function. 233 * 234 * @return A guaranteed unique timer handle. 235 */ 236 TimerHandle generateUniqueTimerHandleLocked(); 237 238 /** 239 * Helper function to determine whether a new timer of the specified type 240 * can be allocated. mMutex must be acquired prior to calling this function. 241 * 242 * @param isNanoappTimer true if invoked for a nanoapp timer. 243 * @return true if a new timer of the given type is allowed to be allocated. 244 */ 245 bool isNewTimerAllowedLocked(bool isNanoappTimer) const; 246 247 /** 248 * Inserts a TimerRequest into the list of active timer requests. The order of 249 * mTimerRequests is always maintained such that the timer request with the 250 * closest expiration time is at the front of the list. mMutex must be 251 * acquired prior to calling this function. 252 * 253 * @param timerRequest The timer request being inserted into the list. 254 * @return true if insertion of timer succeeds. 255 */ 256 bool insertTimerRequestLocked(const TimerRequest& timerRequest); 257 258 /** 259 * Pops the TimerRequest at the front of the list. mMutex must be acquired 260 * prior to calling this function. 261 */ 262 void popTimerRequestLocked(); 263 264 /** 265 * Removes the TimerRequest at the specified index of the list. mMutex must be 266 * acquired prior to calling this function. 267 * 268 * @param index The index of the TimerRequest to remove. 269 */ 270 void removeTimerRequestLocked(size_t index); 271 272 /** 273 * Sets the underlying system timer to the next timer in the timer list if 274 * available. 275 * 276 * @return true if any timer events were posted 277 */ 278 bool handleExpiredTimersAndScheduleNext(); 279 280 /** 281 * Same as handleExpiredTimersAndScheduleNext(), except mMutex must be 282 * acquired prior to calling this function. 283 * 284 * @return true if any timer events were posted 285 */ 286 bool handleExpiredTimersAndScheduleNextLocked(); 287 288 /** 289 * This static method handles the callback from the system timer. The data 290 * pointer here is the TimerPool instance. 291 * 292 * @param data A pointer to the timer pool. 293 */ 294 static void handleSystemTimerCallback(void *timerPoolPtr); 295 }; 296 297 } // namespace chre 298 299 #endif // CHRE_CORE_TIMER_POOL_H_ 300