Convert aos over to flatbuffers

Everything builds, and all the tests pass.  I suspect that some entries
are missing from the config files, but those will be found pretty
quickly on startup.

There is no logging or live introspection of queue messages.

Change-Id: I496ee01ed68f202c7851bed7e8786cee30df29f5
diff --git a/aos/events/shm_event_loop_test.cc b/aos/events/shm_event_loop_test.cc
new file mode 100644
index 0000000..4406e01
--- /dev/null
+++ b/aos/events/shm_event_loop_test.cc
@@ -0,0 +1,169 @@
+#include "aos/events/shm_event_loop.h"
+
+#include "aos/events/event_loop_param_test.h"
+#include "glog/logging.h"
+#include "gtest/gtest.h"
+
+#include "aos/events/test_message_generated.h"
+
+DECLARE_string(shm_base);
+
+namespace aos {
+namespace testing {
+namespace {
+namespace chrono = ::std::chrono;
+
+class ShmEventLoopTestFactory : public EventLoopTestFactory {
+ public:
+  ShmEventLoopTestFactory() {
+    // Put all the queue files in ${TEST_TMPDIR} if it is set, otherwise
+    // everything will be reusing /dev/shm when sharded.
+    char *test_tmpdir = getenv("TEST_TMPDIR");
+    if (test_tmpdir != nullptr) {
+      FLAGS_shm_base = std::string(test_tmpdir) + "/aos";
+    }
+
+    // Clean up anything left there before.
+    unlink((FLAGS_shm_base + "test/aos.TestMessage.v0").c_str());
+    unlink((FLAGS_shm_base + "test1/aos.TestMessage.v0").c_str());
+    unlink((FLAGS_shm_base + "test2/aos.TestMessage.v0").c_str());
+  }
+
+  ::std::unique_ptr<EventLoop> Make() override {
+    return ::std::unique_ptr<EventLoop>(new ShmEventLoop(configuration()));
+  }
+
+  ::std::unique_ptr<EventLoop> MakePrimary() override {
+    ::std::unique_ptr<ShmEventLoop> loop =
+        ::std::unique_ptr<ShmEventLoop>(new ShmEventLoop(configuration()));
+    primary_event_loop_ = loop.get();
+    return ::std::move(loop);
+  }
+
+  void Run() override { CHECK_NOTNULL(primary_event_loop_)->Run(); }
+
+  void Exit() override { CHECK_NOTNULL(primary_event_loop_)->Exit(); }
+
+  void SleepFor(::std::chrono::nanoseconds duration) override {
+    ::std::this_thread::sleep_for(duration);
+  }
+
+ private:
+  ::aos::ShmEventLoop *primary_event_loop_;
+};
+
+INSTANTIATE_TEST_CASE_P(ShmEventLoopTest, AbstractEventLoopTest,
+                        ::testing::Values([]() {
+                          return new ShmEventLoopTestFactory();
+                        }));
+
+INSTANTIATE_TEST_CASE_P(ShmEventLoopDeathTest, AbstractEventLoopDeathTest,
+                        ::testing::Values([]() {
+                          return new ShmEventLoopTestFactory();
+                        }));
+
+}  // namespace
+
+bool IsRealtime() {
+  int scheduler;
+  PCHECK((scheduler = sched_getscheduler(0)) != -1);
+
+  LOG(INFO) << "scheduler is " << scheduler;
+  return scheduler == SCHED_FIFO || scheduler == SCHED_RR;
+}
+
+// Tests that every handler type is realtime and runs.  There are threads
+// involved and it's easy to miss one.
+TEST(ShmEventLoopTest, AllHandlersAreRealtime) {
+  ShmEventLoopTestFactory factory;
+  auto loop = factory.MakePrimary();
+  auto loop2 = factory.Make();
+
+  loop->SetRuntimeRealtimePriority(1);
+
+  auto sender = loop2->MakeSender<TestMessage>("/test");
+
+  bool did_onrun = false;
+  bool did_timer = false;
+  bool did_watcher = false;
+
+  auto timer = loop->AddTimer([&did_timer, &factory]() {
+    EXPECT_TRUE(IsRealtime());
+    did_timer = true;
+    factory.Exit();
+  });
+
+  loop->MakeWatcher("/test", [&did_watcher](const TestMessage &) {
+    EXPECT_TRUE(IsRealtime());
+    did_watcher = true;
+  });
+
+  loop->OnRun([&loop, &did_onrun, &sender, timer]() {
+    EXPECT_TRUE(IsRealtime());
+    did_onrun = true;
+    timer->Setup(loop->monotonic_now() + chrono::milliseconds(100));
+
+    aos::Sender<TestMessage>::Builder msg = sender.MakeBuilder();
+    TestMessage::Builder builder = msg.MakeBuilder<TestMessage>();
+    builder.add_value(200);
+    msg.Send(builder.Finish());
+  });
+
+  factory.Run();
+
+  EXPECT_TRUE(did_onrun);
+  EXPECT_TRUE(did_timer);
+  EXPECT_TRUE(did_watcher);
+}
+
+// Tests that missing a deadline inside the function still results in PhasedLoop
+// running at the right offset.
+TEST(ShmEventLoopTest, DelayedPhasedLoop) {
+  ShmEventLoopTestFactory factory;
+  auto loop1 = factory.MakePrimary();
+
+  ::std::vector<::aos::monotonic_clock::time_point> times;
+
+  constexpr chrono::milliseconds kOffset = chrono::milliseconds(400);
+
+  loop1->AddPhasedLoop(
+      [&times, &loop1, &kOffset, &factory](int count) {
+        const ::aos::monotonic_clock::time_point monotonic_now =
+            loop1->monotonic_now();
+
+        // Compute our offset.
+        const ::aos::monotonic_clock::duration remainder =
+            monotonic_now.time_since_epoch() -
+            chrono::duration_cast<chrono::seconds>(
+                monotonic_now.time_since_epoch());
+
+        // Make sure we we are called near where we should be even when we
+        // delay.
+        constexpr chrono::milliseconds kEpsilon(200);
+        EXPECT_LT(remainder, kOffset + kEpsilon);
+        EXPECT_GT(remainder, kOffset - kEpsilon);
+
+        // Confirm that we see the missed count when we sleep.
+        if (times.size() == 0) {
+          EXPECT_EQ(count, 1);
+        } else {
+          EXPECT_EQ(count, 3);
+        }
+
+        times.push_back(loop1->monotonic_now());
+        if (times.size() == 2) {
+          factory.Exit();
+        }
+
+        // Now, add a large delay.  This should push us up to 3 cycles.
+        ::std::this_thread::sleep_for(chrono::milliseconds(2500));
+      },
+      chrono::seconds(1), kOffset);
+
+  factory.Run();
+
+  EXPECT_EQ(times.size(), 2u);
+}
+
+}  // namespace testing
+}  // namespace aos