• 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    * @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