blob: 6ee7d921be6d4301ba650d0d149f387bdf6022c1 [file] [log] [blame]
Neil Balchc8f41ed2018-01-20 22:06:53 -08001#ifndef _AOS_EVENTS_SIMULATED_EVENT_LOOP_H_
2#define _AOS_EVENTS_SIMULATED_EVENT_LOOP_H_
3
Austin Schuh44019f92019-05-19 19:58:27 -07004#include <algorithm>
Neil Balchc8f41ed2018-01-20 22:06:53 -08005#include <map>
6#include <memory>
7#include <unordered_set>
8#include <utility>
9#include <vector>
10
11#include "aos/events/event-loop.h"
12
13namespace aos {
14
James Kuszmaulcd1db352019-05-26 16:42:29 -070015// This class manages allocation of queue messages for simulation.
16// Unfortunately, because the current interfaces all assume that we pass around
17// raw pointers to messages we can't use a std::shared_ptr or the such, and
18// because aos::Message's themselves to not have any sort of built-in support
19// for this, we need to manage memory for the Messages in some custom fashion.
20// In this case, we do so by allocating a ref-counter in the bytes immediately
21// preceding the aos::Message. We then provide a constructor that takes just a
22// pointer to an existing message and we assume that it was allocated using this
23// class, and can decrement the counter if the RefCountedBuffer we constructed
24// goes out of scope. There are currently no checks to ensure that pointers
25// passed into this class were actually allocated using this class.
Neil Balchc8f41ed2018-01-20 22:06:53 -080026class RefCountedBuffer {
27 public:
28 RefCountedBuffer() {}
29 ~RefCountedBuffer() { clear(); }
30
James Kuszmaulcd1db352019-05-26 16:42:29 -070031 // Create a RefCountedBuffer for some Message that was already allocated using
32 // a RefCountedBuffer class. This, or some function like it, is required to
33 // allow us to let users of the simulated event loops work with raw pointers
34 // to messages.
Neil Balchc8f41ed2018-01-20 22:06:53 -080035 explicit RefCountedBuffer(aos::Message *data) : data_(data) {}
36
James Kuszmaulcd1db352019-05-26 16:42:29 -070037 // Allocates memory for a new message of a given size. Does not initialize the
38 // memory or call any constructors.
Neil Balchc8f41ed2018-01-20 22:06:53 -080039 explicit RefCountedBuffer(size_t size) {
40 data_ = reinterpret_cast<uint8_t *>(malloc(kRefCountSize + size)) +
41 kRefCountSize;
42 // Initialize the allocated memory with an integer
43 *GetRefCount() = 1;
44 }
45
46 RefCountedBuffer(const RefCountedBuffer &other) {
47 data_ = other.data_;
Austin Schuhbbce72d2019-05-26 15:11:46 -070048 if (data_ != nullptr) {
49 ++*GetRefCount();
50 }
Neil Balchc8f41ed2018-01-20 22:06:53 -080051 }
52
53 RefCountedBuffer(RefCountedBuffer &&other) { std::swap(data_, other.data_); }
54
55 RefCountedBuffer &operator=(const RefCountedBuffer &other) {
56 if (this == &other) return *this;
57 clear();
58 data_ = other.data_;
59 ++*GetRefCount();
60 return *this;
61 }
62
63 RefCountedBuffer &operator=(RefCountedBuffer &&other) {
64 if (this == &other) return *this;
65 std::swap(data_, other.data_);
66 return *this;
67 }
68
Austin Schuhbbce72d2019-05-26 15:11:46 -070069 operator bool() const { return data_ != nullptr; }
70
Neil Balchc8f41ed2018-01-20 22:06:53 -080071 aos::Message *get() const { return static_cast<aos::Message *>(data_); }
72
73 aos::Message *release() {
74 auto tmp = get();
75 data_ = nullptr;
76 return tmp;
77 }
78
79 void clear() {
80 if (data_ != nullptr) {
81 if (--*GetRefCount() == 0) {
82 // Free memory block from the start of the allocated block
83 free(GetRefCount());
84 }
85 data_ = nullptr;
86 }
87 }
88
89 private:
90 void *data_ = nullptr;
91 // Qty. memory to be allocated to the ref counter
92 static constexpr size_t kRefCountSize = sizeof(int64_t);
93
94 int64_t *GetRefCount() {
95 // Need to cast the void* to an 8 bit long object (size of void* is
96 // technically 0)
97 return reinterpret_cast<int64_t *>(static_cast<void *>(
98 reinterpret_cast<uint8_t *>(data_) - kRefCountSize));
99 }
100};
101
102class EventScheduler {
103 public:
104 using QueueType = ::std::multimap<::aos::monotonic_clock::time_point,
105 ::std::function<void()>>;
106 using Token = QueueType::iterator;
107
108 // Schedule an event with a callback function
109 // Returns an iterator to the event
110 Token Schedule(::aos::monotonic_clock::time_point time,
111 ::std::function<void()> callback);
112
113 // Deschedule an event by its iterator
114 void Deschedule(Token token);
115
116 void Run();
Austin Schuh44019f92019-05-19 19:58:27 -0700117 void RunFor(::aos::monotonic_clock::duration duration);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800118
Austin Schuh44019f92019-05-19 19:58:27 -0700119 void Exit() {
120 is_running_ = false;
121 }
122
123 void AddRawEventLoop(RawEventLoop *event_loop) {
124 raw_event_loops_.push_back(event_loop);
125 }
126 void RemoveRawEventLoop(RawEventLoop *event_loop) {
127 raw_event_loops_.erase(::std::find(raw_event_loops_.begin(),
128 raw_event_loops_.end(), event_loop));
129 }
Neil Balchc8f41ed2018-01-20 22:06:53 -0800130
Austin Schuh7267c532019-05-19 19:55:53 -0700131 ::aos::monotonic_clock::time_point monotonic_now() const { return now_; }
Neil Balchc8f41ed2018-01-20 22:06:53 -0800132
133 private:
134 ::aos::monotonic_clock::time_point now_ = ::aos::monotonic_clock::epoch();
135 QueueType events_list_;
136 bool is_running_ = false;
Austin Schuh44019f92019-05-19 19:58:27 -0700137 ::std::vector<RawEventLoop *> raw_event_loops_;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800138};
139
Austin Schuhbbce72d2019-05-26 15:11:46 -0700140// Class for simulated fetchers.
141class SimulatedFetcher;
142
Neil Balchc8f41ed2018-01-20 22:06:53 -0800143class SimulatedQueue {
144 public:
Austin Schuhd681bbd2019-02-02 12:03:32 -0800145 explicit SimulatedQueue(const QueueTypeInfo &type, const ::std::string &name,
146 EventScheduler *scheduler)
147 : type_(type), name_(name), scheduler_(scheduler){};
Neil Balchc8f41ed2018-01-20 22:06:53 -0800148
Austin Schuhbbce72d2019-05-26 15:11:46 -0700149 ~SimulatedQueue() { CHECK_EQ(0u, fetchers_.size()); }
150
151 // Makes a connected raw sender which calls Send below.
Austin Schuh7267c532019-05-19 19:55:53 -0700152 ::std::unique_ptr<RawSender> MakeRawSender(EventLoop *event_loop);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800153
Austin Schuhbbce72d2019-05-26 15:11:46 -0700154 // Makes a connected raw fetcher.
Austin Schuh7267c532019-05-19 19:55:53 -0700155 ::std::unique_ptr<RawFetcher> MakeRawFetcher();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800156
Austin Schuhbbce72d2019-05-26 15:11:46 -0700157 // Registers a watcher for the queue.
Austin Schuh7267c532019-05-19 19:55:53 -0700158 void MakeRawWatcher(
159 ::std::function<void(const ::aos::Message *message)> watcher);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800160
Austin Schuhbbce72d2019-05-26 15:11:46 -0700161 // Sends the message to all the connected receivers and fetchers.
162 void Send(RefCountedBuffer message);
163
164 // Unregisters a fetcher.
165 void UnregisterFetcher(SimulatedFetcher *fetcher);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800166
167 const RefCountedBuffer &latest_message() { return latest_message_; }
168
Austin Schuhbbce72d2019-05-26 15:11:46 -0700169 size_t size() const { return type_.size; }
Neil Balchc8f41ed2018-01-20 22:06:53 -0800170
Austin Schuhd681bbd2019-02-02 12:03:32 -0800171 const char *name() const { return name_.c_str(); }
172
Neil Balchc8f41ed2018-01-20 22:06:53 -0800173 private:
Austin Schuhbbce72d2019-05-26 15:11:46 -0700174 const QueueTypeInfo type_;
Austin Schuhd681bbd2019-02-02 12:03:32 -0800175 const ::std::string name_;
Austin Schuhbbce72d2019-05-26 15:11:46 -0700176
177 // List of all watchers.
Neil Balchc8f41ed2018-01-20 22:06:53 -0800178 ::std::vector<std::function<void(const aos::Message *message)>> watchers_;
Austin Schuhbbce72d2019-05-26 15:11:46 -0700179
180 // List of all fetchers.
181 ::std::vector<SimulatedFetcher *> fetchers_;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800182 RefCountedBuffer latest_message_;
183 EventScheduler *scheduler_;
184};
185
Neil Balchc8f41ed2018-01-20 22:06:53 -0800186class SimulatedEventLoopFactory {
187 public:
Austin Schuh7267c532019-05-19 19:55:53 -0700188 ::std::unique_ptr<EventLoop> MakeEventLoop();
189
190 void Run() { scheduler_.Run(); }
Austin Schuh44019f92019-05-19 19:58:27 -0700191 void RunFor(monotonic_clock::duration duration) {
192 scheduler_.RunFor(duration);
193 }
Austin Schuh7267c532019-05-19 19:55:53 -0700194
195 monotonic_clock::time_point monotonic_now() const {
196 return scheduler_.monotonic_now();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800197 }
198
199 private:
200 EventScheduler scheduler_;
201 ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue> queues_;
202};
Austin Schuh7267c532019-05-19 19:55:53 -0700203
Neil Balchc8f41ed2018-01-20 22:06:53 -0800204} // namespace aos
Austin Schuh7267c532019-05-19 19:55:53 -0700205
Neil Balchc8f41ed2018-01-20 22:06:53 -0800206#endif //_AOS_EVENTS_TEST_EVENT_LOOP_H_