event_loop.h revision 09a4783208b5ba1e14d0f0102eb31e688caca28d
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_EVENT_LOOP_H_
18#define CHRE_CORE_EVENT_LOOP_H_
19
20#include "chre/core/event.h"
21#include "chre/core/nanoapp.h"
22#include "chre/core/timer_pool.h"
23#include "chre/platform/mutex.h"
24#include "chre/platform/platform_nanoapp.h"
25#include "chre/util/dynamic_vector.h"
26#include "chre/util/fixed_size_blocking_queue.h"
27#include "chre/util/non_copyable.h"
28#include "chre/util/synchronized_memory_pool.h"
29#include "chre/util/unique_ptr.h"
30
31namespace chre {
32
33/**
34 * The EventLoop represents a single thread of execution that is shared among
35 * zero or more nanoapps. As the name implies, the EventLoop is built around a
36 * loop that delivers events to the nanoapps managed within for processing.
37 */
38class EventLoop : public NonCopyable {
39 public:
40  /**
41   * Setup the event loop.
42   */
43  EventLoop();
44
45  /**
46   * Synchronous callback used with forEachNanoapp
47   */
48  typedef void (NanoappCallbackFunction)(const Nanoapp *nanoapp, void *data);
49
50  /**
51   * Searches the set of nanoapps managed by this EventLoop for one with the
52   * given app ID. If found, provides its instance ID, which can be used to send
53   * events to the app.
54   *
55   * This function is safe to call from any thread.
56   *
57   * @param appId The nanoapp identifier to search for.
58   * @param instanceId If this function returns true, will be populated with the
59   *        instanceId associated with the given appId; otherwise unmodified.
60   *        Must not be null.
61   * @return true if the given app ID was found and instanceId was populated
62   */
63  bool findNanoappInstanceIdByAppId(uint64_t appId, uint32_t *instanceId);
64
65  /**
66   * Iterates over the list of Nanoapps managed by this EventLoop, and invokes
67   * the supplied callback for each one. This holds a lock if necessary, so it
68   * is safe to call from any thread.
69   *
70   * @param callback Function to invoke on each Nanoapp (synchronously)
71   * @param data Arbitrary data to pass to the callback
72   */
73  void forEachNanoapp(NanoappCallbackFunction *callback, void *data);
74
75  /**
76   * Invokes a message to host free callback supplied by the given nanoapp
77   * (identified by app ID). Ensures that the calling context is updated
78   * appropriately.
79   *
80   * @param appId Identifies the nanoapp that sent this message and supplied the
81   *        free callback
82   * @param freeFunction The non-null message free callback given by the nanoapp
83   * @param message Pointer to the message data
84   * @param messageSize Size of the message
85   */
86  void invokeMessageFreeFunction(
87      uint64_t appId, chreMessageFreeFunction *freeFunction, void *message,
88      size_t messageSize);
89
90  /**
91   * Invokes the Nanoapp's start callback, and if successful, adds it to the
92   * set of Nanoapps managed by this EventLoop. This function must only be
93   * called from the context of the thread that runs this event loop (i.e. from
94   * the same thread that will call run() or from a callback invoked within
95   * run()).
96   *
97   * @param nanoapp The nanoapp that will be started. Upon success, this
98   *        UniquePtr will become invalid, as the underlying Nanoapp instance
99   *        will have been transferred to be managed by this EventLoop.
100   * @return true if the app was started successfully
101   */
102  bool startNanoapp(UniquePtr<Nanoapp>& nanoapp);
103
104  /**
105   * Stops a nanoapp by invoking the stop entry point. The nanoapp passed in
106   * must have been previously started by the startNanoapp method. After this
107   * function returns, all references to the Nanoapp are invalid.
108   *
109   * @param nanoapp A pointer to the nanoapp to stop.
110   */
111  void stopNanoapp(Nanoapp *nanoapp);
112
113  /**
114   * Executes the loop that blocks on the event queue and delivers received
115   * events to nanoapps. Only returns after stop() is called (from another
116   * context).
117   */
118  void run();
119
120  /**
121   * Signals the event loop currently executing in run() to exit gracefully at
122   * the next available opportunity. This function is thread-safe.
123   */
124  void stop();
125
126  /**
127   * Posts an event to a nanoapp that is currently running (or all nanoapps if
128   * the target instance ID is kBroadcastInstanceId).
129   *
130   * This function is safe to call from any thread.
131   *
132   * @param eventType The type of data being posted.
133   * @param eventData The data being posted.
134   * @param freeCallback The callback to invoke when the event is no longer
135   *        needed.
136   * @param senderInstanceId The instance ID of the sender of this event.
137   * @param targetInstanceId The instance ID of the destination of this event.
138   *
139   * @return true if the event was successfully added to the queue. Note that
140   *         unlike chreSendEvent, this does *not* invoke the free callback if
141   *         it failed to post the event.
142   *
143   * @see chreSendEvent
144   */
145  bool postEvent(uint16_t eventType, void *eventData,
146                 chreEventCompleteFunction *freeCallback,
147                 uint32_t senderInstanceId = kSystemInstanceId,
148                 uint32_t targetInstanceId = kBroadcastInstanceId);
149
150  /**
151   * Returns a pointer to the currently executing Nanoapp, or nullptr if none is
152   * currently executing. Must only be called from within the thread context
153   * associated with this EventLoop.
154   *
155   * @return the currently executing nanoapp, or nullptr
156   */
157  Nanoapp *getCurrentNanoapp() const;
158
159  /**
160   * Gets the number of nanoapps currently associated with this event loop. Must
161   * only be called within the context of this EventLoop.
162   *
163   * @return The number of nanoapps managed by this event loop
164   */
165  size_t getNanoappCount() const;
166
167  /**
168   * Obtains the TimerPool associated with this event loop.
169   *
170   * @return The timer pool owned by this event loop.
171   */
172  TimerPool& getTimerPool();
173
174  /**
175   * Searches the set of nanoapps managed by this EventLoop for one with the
176   * given instance ID.
177   *
178   * This function is safe to call from any thread.
179   *
180   * @param instanceId The nanoapp instance ID to search for.
181   * @return a pointer to the found nanoapp or nullptr if no match was found.
182   */
183  Nanoapp *findNanoappByInstanceId(uint32_t instanceId);
184
185 private:
186  //! The maximum number of events that can be active in the system.
187  static constexpr size_t kMaxEventCount = 1024;
188
189  //! The maximum number of events that are awaiting to be scheduled. These
190  //! events are in a queue to be distributed to apps.
191  static constexpr size_t kMaxUnscheduledEventCount = 1024;
192
193  //! The memory pool to allocate incoming events from.
194  SynchronizedMemoryPool<Event, kMaxEventCount> mEventPool;
195
196  //! The timer used schedule timed events for tasks running in this event loop.
197  TimerPool mTimerPool;
198
199  //! The list of nanoapps managed by this event loop.
200  DynamicVector<UniquePtr<Nanoapp>> mNanoapps;
201
202  //! This lock *must* be held whenever we:
203  //!   (1) make changes to the mNanoapps vector, or
204  //!   (2) read the mNanoapps vector from a thread other than the one
205  //!       associated with this EventLoop
206  //! It is not necessary to acquire the lock when reading mNanoapps from within
207  //! the thread context of this EventLoop.
208  Mutex mNanoappsLock;
209
210  //! The blocking queue of incoming events from the system that have not been
211  //!  distributed out to apps yet.
212  FixedSizeBlockingQueue<Event *, kMaxUnscheduledEventCount> mEvents;
213
214  // TODO: should probably be atomic to be fully correct
215  volatile bool mRunning = true;
216
217  Nanoapp *mCurrentApp = nullptr;
218
219  /**
220   * Delivers the next event pending in the Nanoapp's queue, and takes care of
221   * freeing events once they have been delivered to all nanoapps. Must only be
222   * called after confirming that the app has at least 1 pending event.
223   *
224   * @return true if the nanoapp has another event pending in its queue
225   */
226  bool deliverNextEvent(const UniquePtr<Nanoapp>& app);
227
228  /**
229   * Call after when an Event has been delivered to all intended recipients.
230   * Invokes the event's free callback (if given) and releases resources.
231   *
232   * @param event The event to be freed
233   */
234  void freeEvent(Event *event);
235
236  /**
237   * Finds a Nanoapp with the given 64-bit appId.
238   *
239   * Only safe to call within this EventLoop's thread.
240   *
241   * @param appId Nanoapp ID
242   * @return Pointer to Nanoapp instance in this EventLoop with the given app
243   *         ID, or nullptr if not found
244   */
245  Nanoapp *lookupAppByAppId(uint64_t appId);
246
247  /**
248   * Finds a Nanoapp with the given instanceId.
249   *
250   * Only safe to call within this EventLoop's thread.
251   *
252   * @param instanceId Nanoapp instance identifier
253   * @return Nanoapp with the given instanceId, or nullptr if not found
254   */
255  Nanoapp *lookupAppByInstanceId(uint32_t instanceId);
256
257  /**
258   * Stops the Nanoapp at the given index in mNanoapps
259   */
260  void stopNanoapp(size_t index);
261};
262
263}  // namespace chre
264
265#endif  // CHRE_CORE_EVENT_LOOP_H_
266