Fix recursion of AllowApplicationCreationDuring in LogReader

Change-Id: I051e7e687b6c06c9bc04bff35ec5ec9db9ba6bc1
Signed-off-by: James Kuszmaul <james.kuszmaul@bluerivertech.com>
diff --git a/aos/events/event_scheduler.cc b/aos/events/event_scheduler.cc
index 115b2c7..ae50917 100644
--- a/aos/events/event_scheduler.cc
+++ b/aos/events/event_scheduler.cc
@@ -459,6 +459,10 @@
 }
 
 void EventSchedulerScheduler::TemporarilyStopAndRun(std::function<void()> fn) {
+  if (in_on_run_) {
+    LOG(FATAL)
+        << "Can't call AllowApplicationCreationDuring from an OnRun callback.";
+  }
   const bool was_running = is_running_;
   if (is_running_) {
     is_running_ = false;
@@ -475,11 +479,13 @@
   for (EventScheduler *scheduler : schedulers_) {
     scheduler->MaybeRunOnStartup();
   }
+  in_on_run_ = true;
   // We must trigger all the OnRun's *after* all the OnStartup callbacks are
   // triggered because that is the contract that we have stated.
   for (EventScheduler *scheduler : schedulers_) {
     scheduler->MaybeRunOnRun();
   }
+  in_on_run_ = false;
 }
 
 }  // namespace aos
diff --git a/aos/events/event_scheduler.h b/aos/events/event_scheduler.h
index 848a1cf..55fa9a4 100644
--- a/aos/events/event_scheduler.h
+++ b/aos/events/event_scheduler.h
@@ -357,6 +357,8 @@
 
   // True if we are running.
   bool is_running_ = false;
+
+  bool in_on_run_ = false;
   // The current time.
   distributed_clock::time_point now_ = distributed_clock::epoch();
   // List of schedulers to run in sync.
diff --git a/aos/events/logging/log_reader.h b/aos/events/logging/log_reader.h
index bb3588a..d36db70 100644
--- a/aos/events/logging/log_reader.h
+++ b/aos/events/logging/log_reader.h
@@ -517,9 +517,18 @@
       const monotonic_clock::time_point start_time =
           monotonic_start_time(boot_count());
       if (start_time == monotonic_clock::min_time) {
-        LOG(ERROR)
-            << "No start time, skipping, please figure out when this happens";
-        NotifyLogfileStart();
+        if (event_loop_->node()) {
+          LOG(ERROR) << "No start time for "
+                     << event_loop_->node()->name()->string_view()
+                     << ", skipping.";
+        } else {
+          LOG(ERROR) << "No start time, skipping.";
+        }
+
+        // This is called from OnRun. There is too much complexity in supporting
+        // OnStartup callbacks from inside OnRun.  Instead, schedule a timer for
+        // "now", and have that do what we need.
+        startup_timer_->Schedule(event_loop_->monotonic_now());
         return;
       }
       if (node_event_loop_factory_) {
diff --git a/aos/events/simulated_event_loop_test.cc b/aos/events/simulated_event_loop_test.cc
index 0afa22e..23badae 100644
--- a/aos/events/simulated_event_loop_test.cc
+++ b/aos/events/simulated_event_loop_test.cc
@@ -2101,6 +2101,18 @@
                "All ExitHandles must be destroyed before the factory");
 }
 
+// Test that AllowApplicationCreationDuring can't happen in OnRun callbacks.
+TEST(SimulatedEventLoopDeathTest, AllowApplicationCreationDuringInOnRun) {
+  aos::FlatbufferDetachedBuffer<aos::Configuration> config =
+      aos::configuration::ReadConfig(
+          ArtifactPath("aos/events/multinode_pingpong_test_split_config.json"));
+  auto factory = std::make_unique<SimulatedEventLoopFactory>(&config.message());
+  NodeEventLoopFactory *pi1 = factory->GetNodeEventLoopFactory("pi1");
+  std::unique_ptr<EventLoop> loop = pi1->MakeEventLoop("foo");
+  loop->OnRun([&]() { factory->AllowApplicationCreationDuring([]() {}); });
+  EXPECT_DEATH(factory->RunFor(chrono::seconds(1)), "OnRun");
+}
+
 // Tests that messages don't survive a reboot of a node.
 TEST(SimulatedEventLoopTest, ChannelClearedOnReboot) {
   aos::FlatbufferDetachedBuffer<aos::Configuration> config =