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