timer_pool.h revision 9cfff1a3bd75f9b78aaf2a8c3277ca97c12fa95c
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
27namespace 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 */
35typedef uint32_t TimerHandle;
36
37//! Forward declare the EventLoop class to avoid a circular dependency between
38//! TimerPool and EventLoop.
39class EventLoop;
40
41/**
42 * Tracks requests from CHRE apps for timed events.
43 */
44class 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 instance ID from which this request was made.
86    uint32_t nanoappInstanceId;
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