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/platform/mutex.h" 23 #include "chre/platform/system_timer.h" 24 #include "chre/util/non_copyable.h" 25 #include "chre/util/priority_queue.h" 26 27 namespace chre { 28 29 /** 30 * The type to use when referring to a timer instance. 31 * 32 * Note that this mirrors the CHRE API definition of a timer handle, so should 33 * not be changed without appropriate consideration. 34 */ 35 typedef uint32_t TimerHandle; 36 37 //! Forward declare the EventLoop class to avoid a circular dependency between 38 //! TimerPool and EventLoop. 39 class EventLoop; 40 41 /** 42 * Tracks requests from CHRE apps for timed events. 43 */ 44 class TimerPool : public NonCopyable { 45 public: 46 /** 47 * Sets up the timer instance initial conditions. 48 * 49 * @param The event loop that owns this timer. 50 */ 51 TimerPool(EventLoop& eventLoop); 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 oneShot 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 */ 64 TimerHandle setTimer(const Nanoapp *nanoapp, Nanoseconds duration, 65 const void *cookie, bool oneShot); 66 67 /** 68 * Cancels a timer given a handle. If the timer handle is invalid or the timer 69 * is not owned by the passed in nanoapp, false is returned. 70 * 71 * @param nanoapp The nanoapp requesting a timer to be cancelled. 72 * @param timerHandle The handle for a timer to be cancelled. 73 * @return true if the timer was cancelled successfully. 74 */ 75 bool cancelTimer(const Nanoapp* nanoapp, TimerHandle timerHandle); 76 77 // TODO: should also add methods here to: 78 // - post an event after a delay 79 // - invoke a callback in "unsafe" context (i.e. from other thread), which the 80 // CHRE system could use to trigger things while the task runner is busy 81 82 private: 83 /** 84 * Tracks metadata associated with a request for a timed event. 85 */ 86 struct TimerRequest { 87 //! The nanoapp instance ID from which this request was made. 88 uint32_t nanoappInstanceId; 89 90 //! The TimerHandle assigned to this request. 91 TimerHandle timerHandle; 92 93 //! The time when the request was made. 94 Nanoseconds expirationTime; 95 96 //! The requested duration of the timer. 97 Nanoseconds duration; 98 99 //! Whether or not the request is a one shot or should be rescheduled. 100 bool isOneShot; 101 102 //! The cookie pointer to be passed as an event to the requesting nanoapp. 103 const void *cookie; 104 105 /** 106 * Provides a greater than comparison of TimerRequests. 107 * 108 * @param request The other request to compare against. 109 * @return Returns true if this request is greater than the provided 110 * request. 111 */ 112 bool operator>(const TimerRequest& request) const; 113 }; 114 115 //! The mutex used to lock the shared data structures below. The 116 //! handleSystemTimerCallback may be called from any context so we use a lock 117 //! to ensure exclusive access. 118 // 119 // Consider changing the design here to avoid the use of a mutex. There is 120 // another option to post an event to the system task to re-schedule the next 121 // timer. It would simplify the design and make it easier to make future 122 // extensions to this module. 123 Mutex mMutex; 124 125 //! The event loop that owns this timer pool. 126 EventLoop& mEventLoop; 127 128 //! The queue of outstanding timer requests. 129 PriorityQueue<TimerRequest, std::greater<TimerRequest>> mTimerRequests; 130 131 //! The underlying system timer used to schedule delayed callbacks. 132 SystemTimer mSystemTimer; 133 134 //! The next timer handle for generateTimerHandle() to return. 135 TimerHandle mLastTimerHandle = CHRE_TIMER_INVALID; 136 137 //! Max number of timers that can be requested for all apps 138 static constexpr size_t kMaxTimerRequests = 64; 139 140 //! Whether or not the timer handle generation logic needs to perform a 141 //! search for a vacant timer handle. 142 bool mGenerateTimerHandleMustCheckUniqueness = false; 143 144 /** 145 * Looks up a timer request given a timer handle. The lock must be acquired 146 * prior to entering this function. 147 * 148 * @param timerHandle The timer handle referring to a given request. 149 * @param index A pointer to the index of the handle. If the handle is found 150 * this will be populated with the index of the request from the list 151 * of requests. This is optional and will only be populated if not 152 * nullptr. 153 * @return A pointer to a TimerRequest or nullptr if no match is found. 154 */ 155 TimerRequest *getTimerRequestByTimerHandle(TimerHandle timerHandle, 156 size_t *index = nullptr); 157 158 /** 159 * Obtains a unique timer handle to return to an app requesting a timer. 160 * 161 * @return The guaranteed unique timer handle. 162 */ 163 TimerHandle generateTimerHandle(); 164 165 /** 166 * Obtains a unique timer handle by searching through the list of timer 167 * requests. This is a fallback for once the timer handles have been 168 * exhausted. The lock must be acquired prior to entering this function. 169 * 170 * @return A guaranteed unique timer handle. 171 */ 172 TimerHandle generateUniqueTimerHandle(); 173 174 /** 175 * Inserts a TimerRequest into the list of active timer requests. The order of 176 * mTimerRequests is always maintained such that the timer request with the 177 * closest expiration time is at the front of the list. 178 * 179 * @param timerRequest The timer request being inserted into the list. 180 * @return true if insertion of timer succeeds. 181 */ 182 bool insertTimerRequest(const TimerRequest& timerRequest); 183 184 /** 185 * Handles a completion callback for a timer by scheduling the next timer if 186 * available. If any timers have expired already an event is posted for them 187 * as well. 188 */ 189 void onSystemTimerCallback(); 190 191 /** 192 * Sets the underlying system timer to the next timer in the timer list if 193 * available. The lock must be acquired prior to entering this function. 194 * 195 * @return true if any timer events were posted 196 */ 197 bool handleExpiredTimersAndScheduleNext(); 198 199 /** 200 * This static method handles the callback from the system timer. The data 201 * pointer here is the TimerPool instance. 202 * 203 * @param data A pointer to the timer pool. 204 */ 205 static void handleSystemTimerCallback(void *timerPoolPtr); 206 }; 207 208 } // namespace chre 209 210 #endif // CHRE_CORE_TIMER_POOL_H_ 211