Add (default off) support for dying on malloc in RT code
Our malloc is not realtime. We shouldn't be using it in RT code. To
enforce this, add a hook into tcmalloc to LOG_RAW(FATAL) whenever an
application tries to allocate memory inside code running at the RT
priority level.
We have code in our drivetrain code which is allocating memory still
when realtime. That prevents us from enabling it yet.
Change-Id: I7679bb11fc9ef0cc676c77f5ef7b041427e1f32a
diff --git a/aos/events/shm_event_loop_test.cc b/aos/events/shm_event_loop_test.cc
index 2aeefb4..8e7ad93 100644
--- a/aos/events/shm_event_loop_test.cc
+++ b/aos/events/shm_event_loop_test.cc
@@ -3,6 +3,7 @@
#include <string_view>
#include "aos/events/event_loop_param_test.h"
+#include "aos/realtime.h"
#include "glog/logging.h"
#include "gtest/gtest.h"
@@ -95,8 +96,22 @@
int scheduler;
PCHECK((scheduler = sched_getscheduler(0)) != -1);
- LOG(INFO) << "scheduler is " << scheduler;
- return scheduler == SCHED_FIFO || scheduler == SCHED_RR;
+ {
+ // If we are RT, logging the scheduler will crash us. Mark that we just
+ // don't care.
+ aos::ScopedNotRealtime nrt;
+ LOG(INFO) << "scheduler is " << scheduler;
+ }
+
+ const bool result = scheduler == SCHED_FIFO || scheduler == SCHED_RR;
+ // Confirm that the scheduler matches AOS' interpretation of if we are
+ // realtime or not.
+ if (result) {
+ aos::CheckRealtime();
+ } else {
+ aos::CheckNotRealtime();
+ }
+ return result;
}
class ShmEventLoopTest : public ::testing::TestWithParam<ReadMethod> {
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index d86d86c..bc15643 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -245,6 +245,9 @@
std::shared_ptr<SimulatedMessage> SimulatedMessage::Make(
SimulatedChannel *channel) {
+ // The allocations in here are due to infrastructure and don't count in the no
+ // mallocs in RT code.
+ ScopedNotRealtime nrt;
const size_t size = channel->max_size();
SimulatedMessage *const message = reinterpret_cast<SimulatedMessage *>(
malloc(sizeof(SimulatedMessage) + size + kChannelDataAlignment - 1));
@@ -288,6 +291,9 @@
aos::monotonic_clock::time_point monotonic_remote_time,
aos::realtime_clock::time_point realtime_remote_time,
uint32_t remote_queue_index) override {
+ // The allocations in here are due to infrastructure and don't count in the
+ // no mallocs in RT code.
+ ScopedNotRealtime nrt;
CHECK_LE(length, size()) << ": Attempting to send too big a message.";
message_->context.monotonic_event_time = event_loop_->monotonic_now();
message_->context.monotonic_remote_time = monotonic_remote_time;
@@ -353,6 +359,9 @@
~SimulatedFetcher() { simulated_channel_->UnregisterFetcher(this); }
std::pair<bool, monotonic_clock::time_point> DoFetchNext() override {
+ // The allocations in here are due to infrastructure and don't count in the
+ // no mallocs in RT code.
+ ScopedNotRealtime nrt;
if (msgs_.size() == 0) {
return std::make_pair(false, monotonic_clock::min_time);
}
@@ -367,6 +376,9 @@
}
std::pair<bool, monotonic_clock::time_point> DoFetch() override {
+ // The allocations in here are due to infrastructure and don't count in the
+ // no mallocs in RT code.
+ ScopedNotRealtime nrt;
if (msgs_.size() == 0) {
// TODO(austin): Can we just do this logic unconditionally? It is a lot
// simpler. And call clear, obviously.
@@ -837,6 +849,9 @@
void SimulatedTimerHandler::Setup(monotonic_clock::time_point base,
monotonic_clock::duration repeat_offset) {
+ // The allocations in here are due to infrastructure and don't count in the no
+ // mallocs in RT code.
+ ScopedNotRealtime nrt;
Disable();
const ::aos::monotonic_clock::time_point monotonic_now =
simulated_event_loop_->monotonic_now();
@@ -925,6 +940,9 @@
void SimulatedPhasedLoopHandler::Schedule(
monotonic_clock::time_point sleep_time) {
+ // The allocations in here are due to infrastructure and don't count in the no
+ // mallocs in RT code.
+ ScopedNotRealtime nrt;
if (token_ != scheduler_->InvalidToken()) {
scheduler_->Deschedule(token_);
token_ = scheduler_->InvalidToken();