Implement a lockless queue

This uses atomics to swap pointers from an array.  It is safe against
process death, and concurent writes.  It also uses signals to wakeup any
processes waiting for new data.

https://docs.google.com/document/d/10xulameLtEqjBFkm54UcN-5N-w5Q_XFNILvNf1Jl1Y4/edit#

Change-Id: Ie7b2aea6f869c1d84e0705aadb21d33fa8241b60
diff --git a/aos/ipc_lib/index.h b/aos/ipc_lib/index.h
index 69f5856..b1afdc8 100644
--- a/aos/ipc_lib/index.h
+++ b/aos/ipc_lib/index.h
@@ -3,6 +3,7 @@
 
 #include <sys/types.h>
 #include <atomic>
+#include <string>
 
 namespace aos {
 namespace ipc_lib {
@@ -104,6 +105,11 @@
   // Returns the raw index.  This should be used very sparingly.
   uint32_t index() const { return index_; }
 
+  QueueIndex Clear() const { return QueueIndex(0, count_); }
+
+  // Returns a string representing the index.
+  ::std::string DebugString() const;
+
  private:
   QueueIndex(uint32_t index, uint32_t count) : index_(index), count_(count) {}
 
@@ -183,6 +189,9 @@
 
   bool operator==(const Index other) const { return other.index_ == index_; }
 
+  // Returns a string representing the index.
+  ::std::string DebugString() const;
+
  private:
   Index(uint32_t index)
       : index_(index) {}
@@ -213,6 +222,7 @@
   void RelaxedInvalidate() { RelaxedStore(Index::Invalid()); }
 
   // Full bidirectional barriers here.
+  void Invalidate() { Store(Index::Invalid()); }
   void Store(Index index) { index_.store(index.index_); }
   Index Load() { return Index(index_.load()); }