Create an ExitHandle interface

This is a safer alternative to our existing pattern of capturing the
pointer in a lambda, and it's more Rust-friendly.

Change-Id: Id0f3fe5a2badcf1a4ae871d0cc7c3ff48d1c22f8
Signed-off-by: Brian Silverman <bsilver16384@gmail.com>
diff --git a/aos/events/simulated_event_loop.cc b/aos/events/simulated_event_loop.cc
index e0ed7a0..88504a5 100644
--- a/aos/events/simulated_event_loop.cc
+++ b/aos/events/simulated_event_loop.cc
@@ -156,6 +156,23 @@
   SimulatedChannel *simulated_channel_ = nullptr;
 };
 
+class SimulatedFactoryExitHandle : public ExitHandle {
+ public:
+  SimulatedFactoryExitHandle(SimulatedEventLoopFactory *factory)
+      : factory_(factory) {
+    ++factory_->exit_handle_count_;
+  }
+  ~SimulatedFactoryExitHandle() override {
+    CHECK_GT(factory_->exit_handle_count_, 0);
+    --factory_->exit_handle_count_;
+  }
+
+  void Exit() override { factory_->Exit(); }
+
+ private:
+  SimulatedEventLoopFactory *const factory_;
+};
+
 class SimulatedChannel {
  public:
   explicit SimulatedChannel(const Channel *channel,
@@ -1273,7 +1290,10 @@
   }
 }
 
-SimulatedEventLoopFactory::~SimulatedEventLoopFactory() {}
+SimulatedEventLoopFactory::~SimulatedEventLoopFactory() {
+  CHECK_EQ(0, exit_handle_count_)
+      << ": All ExitHandles must be destroyed before the factory";
+}
 
 NodeEventLoopFactory *SimulatedEventLoopFactory::GetNodeEventLoopFactory(
     std::string_view node) {
@@ -1455,6 +1475,10 @@
 
 void SimulatedEventLoopFactory::Exit() { scheduler_scheduler_.Exit(); }
 
+std::unique_ptr<ExitHandle> SimulatedEventLoopFactory::MakeExitHandle() {
+  return std::make_unique<SimulatedFactoryExitHandle>(this);
+}
+
 void SimulatedEventLoopFactory::DisableForwarding(const Channel *channel) {
   CHECK(bridge_) << ": Can't disable forwarding without a message bridge.";
   bridge_->DisableForwarding(channel);