Add RT scheduler tracking
This interacts with event loops nicely, both in simulation and in the
real system. This gives us tools to enforce that certain pieces of code
are run in a RT world, and others are not.
Future work will be to enforce that Malloc is not called while realtime.
Change-Id: I3ce3dc287e25390095bac34aed4888434a82f06e
diff --git a/aos/events/BUILD b/aos/events/BUILD
index 59968c3..7c1abd0 100644
--- a/aos/events/BUILD
+++ b/aos/events/BUILD
@@ -260,6 +260,7 @@
deps = [
":event_loop",
":test_message_fbs",
+ "//aos:realtime",
"//aos/testing:googletest",
],
)
@@ -308,6 +309,7 @@
":aos_logging",
":event_loop",
":simple_channel",
+ "//aos:realtime",
"//aos/events/logging:logger_fbs",
"//aos/ipc_lib:index",
"//aos/network:message_bridge_client_status",
diff --git a/aos/events/event_loop_param_test.cc b/aos/events/event_loop_param_test.cc
index 248dcd3..d92927b 100644
--- a/aos/events/event_loop_param_test.cc
+++ b/aos/events/event_loop_param_test.cc
@@ -5,6 +5,7 @@
#include <unordered_set>
#include "aos/flatbuffer_merge.h"
+#include "aos/realtime.h"
#include "glog/logging.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
@@ -1949,6 +1950,120 @@
aos::Sender<TestMessage> sender = loop1->MakeSender<TestMessage>("/test");
}
+// Tests that a non-realtime event loop timer is marked non-realtime.
+TEST_P(AbstractEventLoopTest, NonRealtimeEventLoopTimer) {
+ auto loop1 = MakePrimary();
+
+ // Add a timer to actually quit.
+ auto test_timer = loop1->AddTimer([this]() {
+ CheckNotRealtime();
+ this->Exit();
+ });
+
+ loop1->OnRun([&test_timer, &loop1]() {
+ CheckNotRealtime();
+ test_timer->Setup(loop1->monotonic_now(), ::std::chrono::milliseconds(100));
+ });
+
+ Run();
+}
+
+// Tests that a realtime event loop timer is marked realtime.
+TEST_P(AbstractEventLoopTest, RealtimeEventLoopTimer) {
+ auto loop1 = MakePrimary();
+
+ loop1->SetRuntimeRealtimePriority(1);
+
+ // Add a timer to actually quit.
+ auto test_timer = loop1->AddTimer([this]() {
+ CheckRealtime();
+ this->Exit();
+ });
+
+ loop1->OnRun([&test_timer, &loop1]() {
+ CheckRealtime();
+ test_timer->Setup(loop1->monotonic_now(), ::std::chrono::milliseconds(100));
+ });
+
+ Run();
+}
+
+// Tests that a non-realtime event loop phased loop is marked non-realtime.
+TEST_P(AbstractEventLoopTest, NonRealtimeEventLoopPhasedLoop) {
+ auto loop1 = MakePrimary();
+
+ // Add a timer to actually quit.
+ loop1->AddPhasedLoop(
+ [this](int) {
+ CheckNotRealtime();
+ this->Exit();
+ },
+ chrono::seconds(1), chrono::seconds(0));
+
+ Run();
+}
+
+// Tests that a realtime event loop phased loop is marked realtime.
+TEST_P(AbstractEventLoopTest, RealtimeEventLoopPhasedLoop) {
+ auto loop1 = MakePrimary();
+
+ loop1->SetRuntimeRealtimePriority(1);
+
+ // Add a timer to actually quit.
+ loop1->AddPhasedLoop(
+ [this](int) {
+ CheckRealtime();
+ this->Exit();
+ },
+ chrono::seconds(1), chrono::seconds(0));
+
+ Run();
+}
+
+// Tests that a non-realtime event loop watcher is marked non-realtime.
+TEST_P(AbstractEventLoopTest, NonRealtimeEventLoopWatcher) {
+ auto loop1 = MakePrimary();
+ auto loop2 = Make();
+
+ aos::Sender<TestMessage> sender = loop2->MakeSender<TestMessage>("/test");
+
+ loop1->OnRun([&]() {
+ aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
+ TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
+ ASSERT_TRUE(msg.Send(builder.Finish()));
+ });
+
+ loop1->MakeWatcher("/test", [&](const TestMessage &) {
+ CheckNotRealtime();
+ this->Exit();
+ });
+
+ Run();
+}
+
+// Tests that a realtime event loop watcher is marked realtime.
+TEST_P(AbstractEventLoopTest, RealtimeEventLoopWatcher) {
+ auto loop1 = MakePrimary();
+ auto loop2 = Make();
+
+ loop1->SetRuntimeRealtimePriority(1);
+
+ aos::Sender<TestMessage> sender = loop2->MakeSender<TestMessage>("/test");
+
+ loop1->OnRun([&]() {
+ aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
+ TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
+ ASSERT_TRUE(msg.Send(builder.Finish()));
+ });
+
+ loop1->MakeWatcher("/test", [&](const TestMessage &) {
+ CheckRealtime();
+ this->Exit();
+ });
+
+ Run();
+}
+
// Tests that watchers fail when created on the wrong node.
TEST_P(AbstractEventLoopDeathTest, NodeWatcher) {
EnableNodes("them");
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index c429eef..3daabb2 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -9,6 +9,7 @@
#include "aos/events/aos_logging.h"
#include "aos/events/simulated_network_bridge.h"
#include "aos/json_to_flatbuffer.h"
+#include "aos/realtime.h"
#include "aos/util/phased_loop.h"
namespace aos {
@@ -19,6 +20,16 @@
namespace {
+class ScopedMarkRealtimeRestorer {
+ public:
+ ScopedMarkRealtimeRestorer(bool rt) : rt_(rt), prior_(MarkRealtime(rt)) {}
+ ~ScopedMarkRealtimeRestorer() { CHECK_EQ(rt_, MarkRealtime(prior_)); }
+
+ private:
+ const bool rt_;
+ const bool prior_;
+};
+
// Container for both a message, and the context for it for simulation. This
// makes tracking the timestamps associated with the data easy.
struct SimulatedMessage final {
@@ -544,7 +555,10 @@
}
void OnRun(::std::function<void()> on_run) override {
- scheduler_->ScheduleOnRun(on_run);
+ scheduler_->ScheduleOnRun([this, on_run = std::move(on_run)]() {
+ ScopedMarkRealtimeRestorer rt(priority() > 0);
+ on_run();
+ });
}
const Node *node() const override { return node_; }
@@ -737,7 +751,10 @@
context.realtime_remote_time = context.realtime_event_time;
}
- DoCallCallback([monotonic_now]() { return monotonic_now; }, context);
+ {
+ ScopedMarkRealtimeRestorer rt(simulated_event_loop_->priority() > 0);
+ DoCallCallback([monotonic_now]() { return monotonic_now; }, context);
+ }
msgs_.pop_front();
if (token_ != scheduler_->InvalidToken()) {
@@ -855,7 +872,10 @@
simulated_event_loop_->AddEvent(&event_);
}
- Call([monotonic_now]() { return monotonic_now; }, monotonic_now);
+ {
+ ScopedMarkRealtimeRestorer rt(simulated_event_loop_->priority() > 0);
+ Call([monotonic_now]() { return monotonic_now; }, monotonic_now);
+ }
}
void SimulatedTimerHandler::Disable() {
@@ -891,9 +911,14 @@
if (simulated_event_loop_->log_impl_) {
prev_logger.Swap(simulated_event_loop_->log_impl_);
}
- Call(
- [monotonic_now]() { return monotonic_now; },
- [this](monotonic_clock::time_point sleep_time) { Schedule(sleep_time); });
+
+ {
+ ScopedMarkRealtimeRestorer rt(simulated_event_loop_->priority() > 0);
+ Call([monotonic_now]() { return monotonic_now; },
+ [this](monotonic_clock::time_point sleep_time) {
+ Schedule(sleep_time);
+ });
+ }
}
void SimulatedPhasedLoopHandler::Schedule(