Expose the private buffers from fetchers too

This is handy for the same use cases where getting the shared memory is:
teaching other libraries about it to optimize its usage.

Change-Id: I41657333a70c2b9c9dbf8a30f0c52251eb590ba4
diff --git a/aos/events/event_loop.h b/aos/events/event_loop.h
index 7634479..6cb0365 100644
--- a/aos/events/event_loop.h
+++ b/aos/events/event_loop.h
@@ -594,12 +594,18 @@
   // watcher must exist before calling this.
   WatcherState *GetWatcherState(const Channel *channel);
 
-  // Returns a Sender's protected RawSender
+  // Returns a Sender's protected RawSender.
   template <typename T>
   static RawSender *GetRawSender(aos::Sender<T> *sender) {
     return sender->sender_.get();
   }
 
+  // Returns a Fetcher's protected RawFetcher.
+  template <typename T>
+  static RawFetcher *GetRawFetcher(aos::Fetcher<T> *fetcher) {
+    return fetcher->fetcher_.get();
+  }
+
   // Context available for watchers, timers, and phased loops.
   Context context_;
 
diff --git a/aos/events/shm_event_loop.cc b/aos/events/shm_event_loop.cc
index ebfcc07..1315510 100644
--- a/aos/events/shm_event_loop.cc
+++ b/aos/events/shm_event_loop.cc
@@ -316,6 +316,13 @@
     return lockless_queue_memory_.GetSharedMemory();
   }
 
+  absl::Span<char> GetPrivateMemory() const {
+    CHECK(copy_data());
+    return absl::Span<char>(
+        const_cast<SimpleShmFetcher *>(this)->data_storage_start(),
+        lockless_queue_.message_data_size());
+  }
+
  private:
   char *data_storage_start() {
     if (!copy_data()) return nullptr;
@@ -360,6 +367,10 @@
     return std::make_pair(false, monotonic_clock::min_time);
   }
 
+  absl::Span<char> GetPrivateMemory() const {
+    return simple_shm_fetcher_.GetPrivateMemory();
+  }
+
  private:
   SimpleShmFetcher simple_shm_fetcher_;
 };
@@ -920,6 +931,11 @@
   return static_cast<const ShmSender *>(sender)->GetSharedMemory();
 }
 
+absl::Span<char> ShmEventLoop::GetShmFetcherPrivateMemory(
+    const aos::RawFetcher *fetcher) const {
+  return static_cast<const ShmFetcher *>(fetcher)->GetPrivateMemory();
+}
+
 pid_t ShmEventLoop::GetTid() { return syscall(SYS_gettid); }
 
 }  // namespace aos
diff --git a/aos/events/shm_event_loop.h b/aos/events/shm_event_loop.h
index f832242..55fc85f 100644
--- a/aos/events/shm_event_loop.h
+++ b/aos/events/shm_event_loop.h
@@ -81,12 +81,19 @@
   // this.
   absl::Span<char> GetWatcherSharedMemory(const Channel *channel);
 
-  // Returns the local mapping of the shared memory used by the provided Sender
+  // Returns the local mapping of the shared memory used by the provided Sender.
   template <typename T>
   absl::Span<char> GetSenderSharedMemory(aos::Sender<T> *sender) const {
     return GetShmSenderSharedMemory(GetRawSender(sender));
   }
 
+  // Returns the local mapping of the private memory used by the provided
+  // Fetcher to hold messages.
+  template <typename T>
+  absl::Span<char> GetFetcherPrivateMemory(aos::Fetcher<T> *fetcher) const {
+    return GetShmFetcherPrivateMemory(GetRawFetcher(fetcher));
+  }
+
  private:
   friend class shm_event_loop_internal::ShmWatcherState;
   friend class shm_event_loop_internal::ShmTimerHandler;
@@ -107,9 +114,13 @@
   // Returns the TID of the event loop.
   pid_t GetTid() override;
 
-  // Private method to access the shared memory mapping of a ShmSender
+  // Private method to access the shared memory mapping of a ShmSender.
   absl::Span<char> GetShmSenderSharedMemory(const aos::RawSender *sender) const;
 
+  // Private method to access the private memory mapping of a ShmFetcher.
+  absl::Span<char> GetShmFetcherPrivateMemory(
+      const aos::RawFetcher *fetcher) const;
+
   std::vector<std::function<void()>> on_run_;
   int priority_ = 0;
   cpu_set_t affinity_ = DefaultAffinity();
diff --git a/aos/events/shm_event_loop_test.cc b/aos/events/shm_event_loop_test.cc
index 0c39704..3244c39 100644
--- a/aos/events/shm_event_loop_test.cc
+++ b/aos/events/shm_event_loop_test.cc
@@ -207,11 +207,21 @@
   auto generic_loop1 = factory.MakePrimary("primary");
   ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
 
-  // check that GetSenderSharedMemory returns non-null/non-empty memory span
+  // check that GetSenderSharedMemory returns non-null/non-empty memory span.
   auto sender = loop1->MakeSender<TestMessage>("/test");
   EXPECT_FALSE(loop1->GetSenderSharedMemory(&sender).empty());
 }
 
+TEST(ShmEventLoopTest, GetFetcherPrivateMemory) {
+  ShmEventLoopTestFactory factory;
+  auto generic_loop1 = factory.MakePrimary("primary");
+  ShmEventLoop *const loop1 = static_cast<ShmEventLoop *>(generic_loop1.get());
+
+  // check that GetFetcherPrivateMemory returns non-null/non-empty memory span.
+  auto fetcher = loop1->MakeFetcher<TestMessage>("/test");
+  EXPECT_FALSE(loop1->GetFetcherPrivateMemory(&fetcher).empty());
+}
+
 // TODO(austin): Test that missing a deadline with a timer recovers as expected.
 
 }  // namespace testing