event_loop.h revision 022cc6c770c299bb364e35377a2661791475bbce
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// TODO: using std lib for initial test... we can't do this in the real world
21#include <atomic>
22
23#include "chre/core/event.h"
24#include "chre/core/nanoapp.h"
25#include "chre/core/timer_pool.h"
26#include "chre/util/dynamic_vector.h"
27#include "chre/util/fixed_size_blocking_queue.h"
28#include "chre/util/non_copyable.h"
29#include "chre/util/synchronized_memory_pool.h"
30
31namespace chre {
32
33/**
34 * TODO: document this better
35 */
36class EventLoop : public NonCopyable {
37 public:
38  /**
39   * Setup the event loop.
40   */
41  EventLoop();
42
43  // TODO: need a clear delineation for which methods are safe to call from
44  // threads other than the one calling run()... should include stop() and
45  // postEvent()... everything else would decidedly be not thread-safe
46
47  /**
48   * Starts a nanoapp by invoking the start entry point. If this is successful,
49   * the app is managed by the event loop and the pointer passed in must remain
50   * valid.
51   *
52   * @param A pointer to the nanoapp to start.
53   * @return True if the app was started successfully.
54   */
55  bool startNanoapp(Nanoapp *nanoapp);
56
57  /**
58   * Stops a nanoapp by invoking the stop entry point. The nanoapp passed in
59   * must have been previously started by the startNanoapp method.
60   *
61   * @param A pointer to the nanoapp to stop.
62   */
63  void stopNanoapp(Nanoapp *nanoapp);
64
65  /**
66   * Start the main task run loop. Only returns after stop() is called
67   * (from another context).
68   */
69  void run();
70
71  /**
72   * Signals the event loop currently executing in run() to exit gracefully at
73   * the next available opportunity.
74   */
75  void stop();
76
77  /**
78   * Posts an event to a nanoapp that is currently running (or all nanoapps if
79   * the broadcast instance ID is used).
80   *
81   * @param The type of data being posted.
82   * @param The data being posted.
83   * @param The callback to invoke when the event is no longer needed.
84   * @param The instance ID of the sender of this event.
85   * @param The instance ID of the destination of this event.
86   *
87   * TODO: this is safe to call from other threads, and posts to the incoming
88   * event queue, then it is doled out to interested nanoapp queues later
89   */
90  void postEvent(uint16_t eventType, void *eventData,
91                 chreEventCompleteFunction *freeCallback,
92                 uint32_t senderInstanceId = kSystemInstanceId,
93                 uint32_t targetInstanceId = kBroadcastInstanceId);
94
95  // TODO: static method that allocates + constructs + posts an Event to all
96  // EventLoops (i.e. just the one for now), to simplify external code that will
97  // call this (they don't need to worry about how events are allocated, etc)
98
99  // TODO: do we need this? it might be a helpful convenience function that
100  // handles creation of a timer and stuff
101  void postEventDelayed(Event *event, uint64_t delayNs);
102
103  /**
104   * Returns a pointer to the currently executing Nanoapp, or nullptr if none is
105   * currently executing.
106   *
107   * @return a pointer to the currently executing nanoapp and nullptr if not
108   * currently in an app context.
109   */
110  const Nanoapp *getCurrentNanoapp() const;
111
112  /**
113   * Returns a guaranteed unique instance ID that can be used to construct a
114   * nanoapp.
115   *
116   * @return a unique instance ID to assign to a nanoapp.
117   */
118  uint32_t getNextInstanceId();
119
120  /**
121   * Obtains the TimerPool associated with this event loop.
122   *
123   * @return The timer pool owned by this event loop.
124   */
125  TimerPool& getTimerPool();
126
127 private:
128  //! The maximum number of events that can be active in the system.
129  static constexpr size_t kMaxEventCount = 1024;
130
131  //! The maximum number of events that are awaiting to be scheduled. These
132  //! events are in a queue to be distributed to apps.
133  static constexpr size_t kMaxUnscheduledEventCount = 1024;
134
135  //! The instance ID that was previously generated by getNextInstanceId.
136  uint32_t mLastInstanceId = kSystemInstanceId;
137
138  //! The memory pool to allocate incoming events from.
139  SynchronizedMemoryPool<Event, kMaxEventCount> mEventPool;
140
141  //! The timer used schedule timed events for tasks running in this event loop.
142  TimerPool mTimerPool;
143
144  //! The list of nanoapps managed by this event loop.
145  DynamicVector<Nanoapp*> mNanoapps;
146
147  //! The blocking queue of incoming events from the system that have not been
148  //!  distributed out to apps yet.
149  FixedSizeBlockingQueue<Event*, kMaxUnscheduledEventCount> mEvents;
150
151  // TODO: we probably want our own atomic platform abstraction too
152  std::atomic<bool> mRunning{false};
153
154  Nanoapp *mCurrentApp = nullptr;
155
156  void freeEvent(Event *event);
157  Nanoapp *lookupAppByInstanceId(uint32_t instanceId);
158
159  // TODO: we probably want a to model kSystemInstanceId as an actual nanoapp
160  // with entry points and all that to make it simpler to post events to ourself
161  // and the like...
162};
163
164}  // namespace chre
165
166#endif  // CHRE_CORE_EVENT_LOOP_H_
167