• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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