blob: 16ac08c25b4b6ff2f6a91909c037e9dd1ce5aee7 [file] [log] [blame]
Alex Perrycb7da4b2019-08-28 19:35:56 -07001#include "aos/events/shm_event_loop.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -08002
Alex Perrycb7da4b2019-08-28 19:35:56 -07003#include "aos/events/event_loop_param_test.h"
4#include "glog/logging.h"
Parker Schuhe4a70d62017-12-27 20:10:20 -08005#include "gtest/gtest.h"
6
Alex Perrycb7da4b2019-08-28 19:35:56 -07007#include "aos/events/test_message_generated.h"
8
9DECLARE_string(shm_base);
10
Parker Schuhe4a70d62017-12-27 20:10:20 -080011namespace aos {
12namespace testing {
13namespace {
Austin Schuh3115a202019-05-27 21:02:14 -070014namespace chrono = ::std::chrono;
Parker Schuhe4a70d62017-12-27 20:10:20 -080015
16class ShmEventLoopTestFactory : public EventLoopTestFactory {
17 public:
Alex Perrycb7da4b2019-08-28 19:35:56 -070018 ShmEventLoopTestFactory() {
19 // Put all the queue files in ${TEST_TMPDIR} if it is set, otherwise
20 // everything will be reusing /dev/shm when sharded.
21 char *test_tmpdir = getenv("TEST_TMPDIR");
22 if (test_tmpdir != nullptr) {
23 FLAGS_shm_base = std::string(test_tmpdir) + "/aos";
24 }
25
26 // Clean up anything left there before.
Austin Schuhde8a8ff2019-11-30 15:25:36 -080027 unlink((FLAGS_shm_base + "/test/aos.TestMessage.v0").c_str());
28 unlink((FLAGS_shm_base + "/test1/aos.TestMessage.v0").c_str());
29 unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v0").c_str());
30 unlink((FLAGS_shm_base + "/test2/aos.TestMessage.v0").c_str());
Alex Perrycb7da4b2019-08-28 19:35:56 -070031 }
32
Austin Schuh44019f92019-05-19 19:58:27 -070033 ::std::unique_ptr<EventLoop> Make() override {
Alex Perrycb7da4b2019-08-28 19:35:56 -070034 return ::std::unique_ptr<EventLoop>(new ShmEventLoop(configuration()));
Parker Schuhe4a70d62017-12-27 20:10:20 -080035 }
36
Austin Schuh44019f92019-05-19 19:58:27 -070037 ::std::unique_ptr<EventLoop> MakePrimary() override {
38 ::std::unique_ptr<ShmEventLoop> loop =
Alex Perrycb7da4b2019-08-28 19:35:56 -070039 ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop(configuration()));
Austin Schuh44019f92019-05-19 19:58:27 -070040 primary_event_loop_ = loop.get();
41 return ::std::move(loop);
42 }
43
Alex Perrycb7da4b2019-08-28 19:35:56 -070044 void Run() override { CHECK_NOTNULL(primary_event_loop_)->Run(); }
Austin Schuh44019f92019-05-19 19:58:27 -070045
Alex Perrycb7da4b2019-08-28 19:35:56 -070046 void Exit() override { CHECK_NOTNULL(primary_event_loop_)->Exit(); }
Austin Schuh9fe68f72019-08-10 19:32:03 -070047
Austin Schuh52d325c2019-06-23 18:59:06 -070048 void SleepFor(::std::chrono::nanoseconds duration) override {
49 ::std::this_thread::sleep_for(duration);
50 }
51
Austin Schuh44019f92019-05-19 19:58:27 -070052 private:
Austin Schuh44019f92019-05-19 19:58:27 -070053 ::aos::ShmEventLoop *primary_event_loop_;
Parker Schuhe4a70d62017-12-27 20:10:20 -080054};
55
56INSTANTIATE_TEST_CASE_P(ShmEventLoopTest, AbstractEventLoopTest,
57 ::testing::Values([]() {
58 return new ShmEventLoopTestFactory();
59 }));
60
Austin Schuh6b6dfa52019-06-12 20:16:20 -070061INSTANTIATE_TEST_CASE_P(ShmEventLoopDeathTest, AbstractEventLoopDeathTest,
62 ::testing::Values([]() {
63 return new ShmEventLoopTestFactory();
64 }));
65
Parker Schuhe4a70d62017-12-27 20:10:20 -080066} // namespace
James Kuszmaulc79768b2019-02-18 15:08:44 -080067
Austin Schuh3115a202019-05-27 21:02:14 -070068bool IsRealtime() {
69 int scheduler;
Alex Perrycb7da4b2019-08-28 19:35:56 -070070 PCHECK((scheduler = sched_getscheduler(0)) != -1);
71
72 LOG(INFO) << "scheduler is " << scheduler;
Austin Schuh3115a202019-05-27 21:02:14 -070073 return scheduler == SCHED_FIFO || scheduler == SCHED_RR;
74}
James Kuszmaulc79768b2019-02-18 15:08:44 -080075
Austin Schuh3115a202019-05-27 21:02:14 -070076// Tests that every handler type is realtime and runs. There are threads
77// involved and it's easy to miss one.
78TEST(ShmEventLoopTest, AllHandlersAreRealtime) {
79 ShmEventLoopTestFactory factory;
80 auto loop = factory.MakePrimary();
81 auto loop2 = factory.Make();
82
83 loop->SetRuntimeRealtimePriority(1);
84
85 auto sender = loop2->MakeSender<TestMessage>("/test");
86
87 bool did_onrun = false;
88 bool did_timer = false;
89 bool did_watcher = false;
90
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 auto timer = loop->AddTimer([&did_timer, &factory]() {
Austin Schuh3115a202019-05-27 21:02:14 -070092 EXPECT_TRUE(IsRealtime());
93 did_timer = true;
Austin Schuh9fe68f72019-08-10 19:32:03 -070094 factory.Exit();
Austin Schuh3115a202019-05-27 21:02:14 -070095 });
96
97 loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
98 EXPECT_TRUE(IsRealtime());
99 did_watcher = true;
100 });
101
102 loop->OnRun([&loop, &did_onrun, &sender, timer]() {
103 EXPECT_TRUE(IsRealtime());
104 did_onrun = true;
105 timer->Setup(loop->monotonic_now() + chrono::milliseconds(100));
Alex Perrycb7da4b2019-08-28 19:35:56 -0700106
107 aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
108 TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
109 builder.add_value(200);
110 msg.Send(builder.Finish());
Austin Schuh3115a202019-05-27 21:02:14 -0700111 });
James Kuszmaulc79768b2019-02-18 15:08:44 -0800112
Austin Schuh3115a202019-05-27 21:02:14 -0700113 factory.Run();
James Kuszmaulc79768b2019-02-18 15:08:44 -0800114
Austin Schuh3115a202019-05-27 21:02:14 -0700115 EXPECT_TRUE(did_onrun);
116 EXPECT_TRUE(did_timer);
117 EXPECT_TRUE(did_watcher);
James Kuszmaulc79768b2019-02-18 15:08:44 -0800118}
Austin Schuh52d325c2019-06-23 18:59:06 -0700119
120// Tests that missing a deadline inside the function still results in PhasedLoop
121// running at the right offset.
122TEST(ShmEventLoopTest, DelayedPhasedLoop) {
123 ShmEventLoopTestFactory factory;
124 auto loop1 = factory.MakePrimary();
125
126 ::std::vector<::aos::monotonic_clock::time_point> times;
127
128 constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
129
130 loop1->AddPhasedLoop(
Austin Schuh9fe68f72019-08-10 19:32:03 -0700131 [&times, &loop1, &kOffset, &factory](int count) {
Austin Schuh52d325c2019-06-23 18:59:06 -0700132 const ::aos::monotonic_clock::time_point monotonic_now =
133 loop1->monotonic_now();
134
135 // Compute our offset.
136 const ::aos::monotonic_clock::duration remainder =
137 monotonic_now.time_since_epoch() -
138 chrono::duration_cast<chrono::seconds>(
139 monotonic_now.time_since_epoch());
140
141 // Make sure we we are called near where we should be even when we
142 // delay.
143 constexpr chrono::milliseconds kEpsilon(200);
144 EXPECT_LT(remainder, kOffset + kEpsilon);
145 EXPECT_GT(remainder, kOffset - kEpsilon);
146
147 // Confirm that we see the missed count when we sleep.
148 if (times.size() == 0) {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800149 CHECK_EQ(count, 1);
Austin Schuh52d325c2019-06-23 18:59:06 -0700150 } else {
Austin Schuhde8a8ff2019-11-30 15:25:36 -0800151 CHECK_EQ(count, 3);
Austin Schuh52d325c2019-06-23 18:59:06 -0700152 }
153
154 times.push_back(loop1->monotonic_now());
155 if (times.size() == 2) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700156 factory.Exit();
Austin Schuh52d325c2019-06-23 18:59:06 -0700157 }
158
159 // Now, add a large delay. This should push us up to 3 cycles.
160 ::std::this_thread::sleep_for(chrono::milliseconds(2500));
161 },
162 chrono::seconds(1), kOffset);
163
164 factory.Run();
165
166 EXPECT_EQ(times.size(), 2u);
167}
168
Parker Schuhe4a70d62017-12-27 20:10:20 -0800169} // namespace testing
170} // namespace aos