blob: e0d0b49672435b5012bb2064362e69ad0486738c [file] [log] [blame]
Parker Schuhe4a70d62017-12-27 20:10:20 -08001#include "aos/events/shm-event-loop.h"
2
3#include "aos/events/event-loop_param_test.h"
4#include "aos/testing/test_shm.h"
5#include "gtest/gtest.h"
6
7namespace aos {
8namespace testing {
9namespace {
Austin Schuh3115a202019-05-27 21:02:14 -070010namespace chrono = ::std::chrono;
Parker Schuhe4a70d62017-12-27 20:10:20 -080011
12class ShmEventLoopTestFactory : public EventLoopTestFactory {
13 public:
Austin Schuh44019f92019-05-19 19:58:27 -070014 ::std::unique_ptr<EventLoop> Make() override {
15 return ::std::unique_ptr<EventLoop>(new ShmEventLoop());
Parker Schuhe4a70d62017-12-27 20:10:20 -080016 }
17
Austin Schuh44019f92019-05-19 19:58:27 -070018 ::std::unique_ptr<EventLoop> MakePrimary() override {
19 ::std::unique_ptr<ShmEventLoop> loop =
20 ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop());
21 primary_event_loop_ = loop.get();
22 return ::std::move(loop);
23 }
24
Austin Schuhf257f3c2019-10-27 21:00:43 -070025 void Run() override { AOS_CHECK_NOTNULL(primary_event_loop_)->Run(); }
Austin Schuh44019f92019-05-19 19:58:27 -070026
Austin Schuhf257f3c2019-10-27 21:00:43 -070027 void Exit() override { AOS_CHECK_NOTNULL(primary_event_loop_)->Exit(); }
Austin Schuh9fe68f72019-08-10 19:32:03 -070028
Austin Schuh52d325c2019-06-23 18:59:06 -070029 void SleepFor(::std::chrono::nanoseconds duration) override {
30 ::std::this_thread::sleep_for(duration);
31 }
32
Austin Schuh44019f92019-05-19 19:58:27 -070033 private:
Parker Schuhe4a70d62017-12-27 20:10:20 -080034 ::aos::testing::TestSharedMemory my_shm_;
Austin Schuh44019f92019-05-19 19:58:27 -070035
36 ::aos::ShmEventLoop *primary_event_loop_;
Parker Schuhe4a70d62017-12-27 20:10:20 -080037};
38
39INSTANTIATE_TEST_CASE_P(ShmEventLoopTest, AbstractEventLoopTest,
40 ::testing::Values([]() {
41 return new ShmEventLoopTestFactory();
42 }));
43
Austin Schuh6b6dfa52019-06-12 20:16:20 -070044INSTANTIATE_TEST_CASE_P(ShmEventLoopDeathTest, AbstractEventLoopDeathTest,
45 ::testing::Values([]() {
46 return new ShmEventLoopTestFactory();
47 }));
48
James Kuszmaulc79768b2019-02-18 15:08:44 -080049struct TestMessage : public ::aos::Message {
50 enum { kQueueLength = 100, kHash = 0x696c0cdc };
51 int msg_value;
52
53 void Zero() { msg_value = 0; }
54 static size_t Size() { return 1 + ::aos::Message::Size(); }
55 size_t Print(char *buffer, size_t length) const;
56 TestMessage() { Zero(); }
57};
58
Parker Schuhe4a70d62017-12-27 20:10:20 -080059} // namespace
James Kuszmaulc79768b2019-02-18 15:08:44 -080060
Austin Schuh3115a202019-05-27 21:02:14 -070061bool IsRealtime() {
62 int scheduler;
63 if ((scheduler = sched_getscheduler(0)) == -1) {
Austin Schuhf257f3c2019-10-27 21:00:43 -070064 AOS_PLOG(FATAL, "sched_getscheduler(0) failed\n");
James Kuszmaulc79768b2019-02-18 15:08:44 -080065 }
Austin Schuhf257f3c2019-10-27 21:00:43 -070066 AOS_LOG(INFO, "scheduler is %d\n", scheduler);
Austin Schuh3115a202019-05-27 21:02:14 -070067 return scheduler == SCHED_FIFO || scheduler == SCHED_RR;
68}
James Kuszmaulc79768b2019-02-18 15:08:44 -080069
Austin Schuh3115a202019-05-27 21:02:14 -070070// Tests that every handler type is realtime and runs. There are threads
71// involved and it's easy to miss one.
72TEST(ShmEventLoopTest, AllHandlersAreRealtime) {
73 ShmEventLoopTestFactory factory;
74 auto loop = factory.MakePrimary();
75 auto loop2 = factory.Make();
76
77 loop->SetRuntimeRealtimePriority(1);
78
79 auto sender = loop2->MakeSender<TestMessage>("/test");
80
81 bool did_onrun = false;
82 bool did_timer = false;
83 bool did_watcher = false;
84
Austin Schuh9fe68f72019-08-10 19:32:03 -070085 auto timer = loop->AddTimer([&did_timer, &loop, &factory]() {
Austin Schuh3115a202019-05-27 21:02:14 -070086 EXPECT_TRUE(IsRealtime());
87 did_timer = true;
Austin Schuh9fe68f72019-08-10 19:32:03 -070088 factory.Exit();
Austin Schuh3115a202019-05-27 21:02:14 -070089 });
90
91 loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
92 EXPECT_TRUE(IsRealtime());
93 did_watcher = true;
94 });
95
96 loop->OnRun([&loop, &did_onrun, &sender, timer]() {
97 EXPECT_TRUE(IsRealtime());
98 did_onrun = true;
99 timer->Setup(loop->monotonic_now() + chrono::milliseconds(100));
James Kuszmaulc79768b2019-02-18 15:08:44 -0800100 auto msg = sender.MakeMessage();
101 msg->msg_value = 200;
Austin Schuh3115a202019-05-27 21:02:14 -0700102 msg.Send();
103 });
James Kuszmaulc79768b2019-02-18 15:08:44 -0800104
Austin Schuh3115a202019-05-27 21:02:14 -0700105 factory.Run();
James Kuszmaulc79768b2019-02-18 15:08:44 -0800106
Austin Schuh3115a202019-05-27 21:02:14 -0700107 EXPECT_TRUE(did_onrun);
108 EXPECT_TRUE(did_timer);
109 EXPECT_TRUE(did_watcher);
James Kuszmaulc79768b2019-02-18 15:08:44 -0800110}
Austin Schuh52d325c2019-06-23 18:59:06 -0700111
112// Tests that missing a deadline inside the function still results in PhasedLoop
113// running at the right offset.
114TEST(ShmEventLoopTest, DelayedPhasedLoop) {
115 ShmEventLoopTestFactory factory;
116 auto loop1 = factory.MakePrimary();
117
118 ::std::vector<::aos::monotonic_clock::time_point> times;
119
120 constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
121
122 loop1->AddPhasedLoop(
Austin Schuh9fe68f72019-08-10 19:32:03 -0700123 [&times, &loop1, &kOffset, &factory](int count) {
Austin Schuh52d325c2019-06-23 18:59:06 -0700124 const ::aos::monotonic_clock::time_point monotonic_now =
125 loop1->monotonic_now();
126
127 // Compute our offset.
128 const ::aos::monotonic_clock::duration remainder =
129 monotonic_now.time_since_epoch() -
130 chrono::duration_cast<chrono::seconds>(
131 monotonic_now.time_since_epoch());
132
133 // Make sure we we are called near where we should be even when we
134 // delay.
135 constexpr chrono::milliseconds kEpsilon(200);
136 EXPECT_LT(remainder, kOffset + kEpsilon);
137 EXPECT_GT(remainder, kOffset - kEpsilon);
138
139 // Confirm that we see the missed count when we sleep.
140 if (times.size() == 0) {
141 EXPECT_EQ(count, 1);
142 } else {
143 EXPECT_EQ(count, 3);
144 }
145
146 times.push_back(loop1->monotonic_now());
147 if (times.size() == 2) {
Austin Schuh9fe68f72019-08-10 19:32:03 -0700148 factory.Exit();
Austin Schuh52d325c2019-06-23 18:59:06 -0700149 }
150
151 // Now, add a large delay. This should push us up to 3 cycles.
152 ::std::this_thread::sleep_for(chrono::milliseconds(2500));
153 },
154 chrono::seconds(1), kOffset);
155
156 factory.Run();
157
158 EXPECT_EQ(times.size(), 2u);
159}
160
Parker Schuhe4a70d62017-12-27 20:10:20 -0800161} // namespace testing
162} // namespace aos