blob: f2981c8e78d568528ebe59c50675712b18d98500 [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
15class RefCountedBuffer {
16 public:
17 RefCountedBuffer() {}
18 ~RefCountedBuffer() { clear(); }
19
20 explicit RefCountedBuffer(aos::Message *data) : data_(data) {}
21
22 explicit RefCountedBuffer(size_t size) {
23 data_ = reinterpret_cast<uint8_t *>(malloc(kRefCountSize + size)) +
24 kRefCountSize;
25 // Initialize the allocated memory with an integer
26 *GetRefCount() = 1;
27 }
28
29 RefCountedBuffer(const RefCountedBuffer &other) {
30 data_ = other.data_;
31 ++*GetRefCount();
32 }
33
34 RefCountedBuffer(RefCountedBuffer &&other) { std::swap(data_, other.data_); }
35
36 RefCountedBuffer &operator=(const RefCountedBuffer &other) {
37 if (this == &other) return *this;
38 clear();
39 data_ = other.data_;
40 ++*GetRefCount();
41 return *this;
42 }
43
44 RefCountedBuffer &operator=(RefCountedBuffer &&other) {
45 if (this == &other) return *this;
46 std::swap(data_, other.data_);
47 return *this;
48 }
49
50 aos::Message *get() const { return static_cast<aos::Message *>(data_); }
51
52 aos::Message *release() {
53 auto tmp = get();
54 data_ = nullptr;
55 return tmp;
56 }
57
58 void clear() {
59 if (data_ != nullptr) {
60 if (--*GetRefCount() == 0) {
61 // Free memory block from the start of the allocated block
62 free(GetRefCount());
63 }
64 data_ = nullptr;
65 }
66 }
67
68 private:
69 void *data_ = nullptr;
70 // Qty. memory to be allocated to the ref counter
71 static constexpr size_t kRefCountSize = sizeof(int64_t);
72
73 int64_t *GetRefCount() {
74 // Need to cast the void* to an 8 bit long object (size of void* is
75 // technically 0)
76 return reinterpret_cast<int64_t *>(static_cast<void *>(
77 reinterpret_cast<uint8_t *>(data_) - kRefCountSize));
78 }
79};
80
81class EventScheduler {
82 public:
83 using QueueType = ::std::multimap<::aos::monotonic_clock::time_point,
84 ::std::function<void()>>;
85 using Token = QueueType::iterator;
86
87 // Schedule an event with a callback function
88 // Returns an iterator to the event
89 Token Schedule(::aos::monotonic_clock::time_point time,
90 ::std::function<void()> callback);
91
92 // Deschedule an event by its iterator
93 void Deschedule(Token token);
94
95 void Run();
Austin Schuh44019f92019-05-19 19:58:27 -070096 void RunFor(::aos::monotonic_clock::duration duration);
Neil Balchc8f41ed2018-01-20 22:06:53 -080097
Austin Schuh44019f92019-05-19 19:58:27 -070098 void Exit() {
99 is_running_ = false;
100 }
101
102 void AddRawEventLoop(RawEventLoop *event_loop) {
103 raw_event_loops_.push_back(event_loop);
104 }
105 void RemoveRawEventLoop(RawEventLoop *event_loop) {
106 raw_event_loops_.erase(::std::find(raw_event_loops_.begin(),
107 raw_event_loops_.end(), event_loop));
108 }
Neil Balchc8f41ed2018-01-20 22:06:53 -0800109
Austin Schuh7267c532019-05-19 19:55:53 -0700110 ::aos::monotonic_clock::time_point monotonic_now() const { return now_; }
Neil Balchc8f41ed2018-01-20 22:06:53 -0800111
112 private:
113 ::aos::monotonic_clock::time_point now_ = ::aos::monotonic_clock::epoch();
114 QueueType events_list_;
115 bool is_running_ = false;
Austin Schuh44019f92019-05-19 19:58:27 -0700116 ::std::vector<RawEventLoop *> raw_event_loops_;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800117};
118
119class SimulatedQueue {
120 public:
Austin Schuhd681bbd2019-02-02 12:03:32 -0800121 explicit SimulatedQueue(const QueueTypeInfo &type, const ::std::string &name,
122 EventScheduler *scheduler)
123 : type_(type), name_(name), scheduler_(scheduler){};
Neil Balchc8f41ed2018-01-20 22:06:53 -0800124
Austin Schuh7267c532019-05-19 19:55:53 -0700125 ::std::unique_ptr<RawSender> MakeRawSender(EventLoop *event_loop);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800126
Austin Schuh7267c532019-05-19 19:55:53 -0700127 ::std::unique_ptr<RawFetcher> MakeRawFetcher();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800128
Austin Schuh7267c532019-05-19 19:55:53 -0700129 void MakeRawWatcher(
130 ::std::function<void(const ::aos::Message *message)> watcher);
Neil Balchc8f41ed2018-01-20 22:06:53 -0800131
132 void Send(RefCountedBuffer message) {
133 index_++;
134 latest_message_ = message;
135 for (auto &watcher : watchers_) {
Austin Schuh7267c532019-05-19 19:55:53 -0700136 scheduler_->Schedule(scheduler_->monotonic_now(),
Neil Balchc8f41ed2018-01-20 22:06:53 -0800137 [watcher, message]() { watcher(message.get()); });
138 }
139 }
140
141 const RefCountedBuffer &latest_message() { return latest_message_; }
142
143 int64_t index() { return index_; }
144
145 size_t size() { return type_.size; }
146
Austin Schuhd681bbd2019-02-02 12:03:32 -0800147 const char *name() const { return name_.c_str(); }
148
Neil Balchc8f41ed2018-01-20 22:06:53 -0800149 private:
150 int64_t index_ = -1;
151 QueueTypeInfo type_;
Austin Schuhd681bbd2019-02-02 12:03:32 -0800152 const ::std::string name_;
Neil Balchc8f41ed2018-01-20 22:06:53 -0800153 ::std::vector<std::function<void(const aos::Message *message)>> watchers_;
154 RefCountedBuffer latest_message_;
155 EventScheduler *scheduler_;
156};
157
Neil Balchc8f41ed2018-01-20 22:06:53 -0800158class SimulatedEventLoopFactory {
159 public:
Austin Schuh7267c532019-05-19 19:55:53 -0700160 ::std::unique_ptr<EventLoop> MakeEventLoop();
161
162 void Run() { scheduler_.Run(); }
Austin Schuh44019f92019-05-19 19:58:27 -0700163 void RunFor(monotonic_clock::duration duration) {
164 scheduler_.RunFor(duration);
165 }
Austin Schuh7267c532019-05-19 19:55:53 -0700166
167 monotonic_clock::time_point monotonic_now() const {
168 return scheduler_.monotonic_now();
Neil Balchc8f41ed2018-01-20 22:06:53 -0800169 }
170
171 private:
172 EventScheduler scheduler_;
173 ::std::map<::std::pair<::std::string, QueueTypeInfo>, SimulatedQueue> queues_;
174};
Austin Schuh7267c532019-05-19 19:55:53 -0700175
Neil Balchc8f41ed2018-01-20 22:06:53 -0800176} // namespace aos
Austin Schuh7267c532019-05-19 19:55:53 -0700177
Neil Balchc8f41ed2018-01-20 22:06:53 -0800178#endif //_AOS_EVENTS_TEST_EVENT_LOOP_H_