merging in the actual implementation of the ruby code
diff --git a/aos/atom_code/ipc_lib/unique_message_ptr.h b/aos/atom_code/ipc_lib/unique_message_ptr.h
new file mode 100644
index 0000000..e30a4c0
--- /dev/null
+++ b/aos/atom_code/ipc_lib/unique_message_ptr.h
@@ -0,0 +1,39 @@
+#include <memory>
+
+#include "aos/atom_code/ipc_lib/queue.h"
+
+namespace aos {
+namespace internal {
+
+template<typename T>
+class queue_free {
+ public:
+  queue_free(RawQueue *queue) : queue_(queue) {}
+
+  void operator()(const T *message) {
+    queue_->FreeMessage(static_cast<const void *>(message));
+  }
+
+ private:
+  RawQueue *const queue_;
+};
+
+}  // namespace internal
+
+template<typename T>
+class unique_message_ptr : public ::std::unique_ptr<T, ::aos::internal::queue_free<T>> {
+ public:
+  unique_message_ptr(RawQueue *queue, T *message = NULL)
+      : ::std::unique_ptr<T, ::aos::internal::queue_free<T>>(message, ::aos::internal::queue_free<T>(queue)) {}
+
+  // Perfectly forward this so that the move functionality of ::std::unique_ptr
+  // works.
+  template <typename... Args>
+  unique_message_ptr<T> &operator=(Args &&... args) {
+        ::std::unique_ptr<T, ::aos::internal::queue_free<T>>::operator=(
+            ::std::forward<Args>(args)...);
+        return *this;
+  }
+};
+
+}  // namespace aos
diff --git a/aos/build/aos.gyp b/aos/build/aos.gyp
index a6e4f33..b7775a1 100644
--- a/aos/build/aos.gyp
+++ b/aos/build/aos.gyp
@@ -25,7 +25,6 @@
       ],
       'dependencies': [
         '<(AOS)/common/common.gyp:die',
-        '<(AOS)/common/common.gyp:queue_types',
       ],
     },
     {
diff --git a/aos/build/aos.gypi b/aos/build/aos.gypi
index 144bffb..bf2e7c9 100644
--- a/aos/build/aos.gypi
+++ b/aos/build/aos.gypi
@@ -79,6 +79,15 @@
     'include_dirs': [
       '<(DEPTH)',
     ],
+    # These have to be here because apparently gyp evaluates target_conditions
+    # even if the target is never used.
+    'variables': {
+      # Set this to 1 to disable rsyncing the file to the target.
+      'no_rsync%': 0,
+      # Set this to 1 if this file isn't a test that should get run by
+      # `build.sh tests`.
+      'is_special_test%': 0,
+    },
     'conditions': [
       ['DEBUG=="yes"', {
           'cflags': [
@@ -163,9 +172,6 @@
             'NOMINMAX',
           ],
         }, {
-          'variables': {
-            'no_rsync%': 0,
-          },
           'target_conditions': [
 # default to putting outputs into rsync_dir
             ['no_rsync==0 and _type!="static_library"', {
diff --git a/aos/build/build.sh b/aos/build/build.sh
index 9073492..943f32e 100755
--- a/aos/build/build.sh
+++ b/aos/build/build.sh
@@ -84,6 +84,6 @@
       ${OUTDIR}/lib/FRC_UserProgram.out
   fi
   if [[ ${ACTION} == tests ]]; then
-    find ${OUTDIR}/tests -executable -exec {} \;
+    find ${OUTDIR}/tests -executable -exec ${AOS}/build/run_test.sh {} \;
   fi
 fi
diff --git a/aos/build/download_externals.sh b/aos/build/download_externals.sh
index 36ce094..a025810 100755
--- a/aos/build/download_externals.sh
+++ b/aos/build/download_externals.sh
@@ -77,7 +77,7 @@
 
 # get gtest
 GTEST_VERSION=1.6.0
-GTEST_DIR=${EXTERNALS}/gtest-${GTEST_VERSION}
+GTEST_DIR=${EXTERNALS}/gtest-${GTEST_VERSION}-p1
 GTEST_ZIP=${EXTERNALS}/gtest-${GTEST_VERSION}.zip
 [ -f ${GTEST_ZIP} ] || wget http://googletest.googlecode.com/files/gtest-${GTEST_VERSION}.zip -O ${GTEST_ZIP}
 [ -d ${GTEST_DIR} ] || ( unzip ${GTEST_ZIP} -d ${TMPDIR} && mv ${TMPDIR}/gtest-${GTEST_VERSION} ${GTEST_DIR} && cd ${GTEST_DIR} && patch -p1 < ${AOS}/externals/gtest.patch )
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
index ee10566..56b7867 100644
--- a/aos/build/externals.gyp
+++ b/aos/build/externals.gyp
@@ -14,7 +14,7 @@
 
 # These versions have to be kept in sync with the ones in download_externals.sh.
     'eigen_version': '3.1.3',
-    'gtest_version': '1.6.0',
+    'gtest_version': '1.6.0-p1',
     'onejar_version': '0.97',
     'ctemplate_version': '129',
     'gflags_version': '2.0',
@@ -180,9 +180,12 @@
       'direct_dependent_settings': {
         'include_dirs': ['<(externals)/gtest-<(gtest_version)/include'],
         'target_conditions': [
-          ['_type=="executable"', {
+          ['_type=="executable" and is_special_test==0', {
               'product_dir': '<(test_dir)',
             },
+          ], ['_type=="executable" and is_special_test==1', {
+              'product_dir': '<(test_dir)-special',
+            },
           ],
         ],
       },
diff --git a/aos/build/run_test.sh b/aos/build/run_test.sh
new file mode 100755
index 0000000..9da830b
--- /dev/null
+++ b/aos/build/run_test.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+
+# This gets called by build.sh to run a test.
+
+EXECUTABLE=$1
+
+echo "Running $(basename ${EXECUTABLE})."
+${EXECUTABLE}
+exit $?
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index 4a99198..d7ec2d2 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -47,6 +47,11 @@
       'sources': [
         'queue_types.cc',
       ],
+      'dependencies': [
+        '<(AOS)/build/aos.gyp:logging_interface',
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:shared_mem',
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:core_lib',
+      ],
     },
     {
       'target_name': 'queue_types_test',
@@ -174,6 +179,7 @@
         'queue_testutils',
         'queue_test_queue',
         '<(AOS)/common/util/util.gyp:thread',
+        'die',
       ],
     },
     {
@@ -285,6 +291,7 @@
       'dependencies': [
         '<(EXTERNALS):gtest',
         'mutex',
+        'die',
       ],
     },
     {
@@ -302,6 +309,7 @@
         '<(AOS)/build/aos.gyp:logging',
         'queue_testutils',
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:core_lib',
+        'die',
        ],
     },
     {
diff --git a/aos/common/condition_test.cc b/aos/common/condition_test.cc
index a10275b..65a1028 100644
--- a/aos/common/condition_test.cc
+++ b/aos/common/condition_test.cc
@@ -13,6 +13,7 @@
 #include "aos/linux_code/ipc_lib/core_lib.h"
 #include "aos/common/logging/logging.h"
 #include "aos/common/macros.h"
+#include "aos/common/die.h"
 
 using ::aos::time::Time;
 using ::aos::common::testing::GlobalCoreInstance;
@@ -43,6 +44,11 @@
     time::SleepFor(::Time::InSeconds(0.008));
   }
 
+ protected:
+  void SetUp() override {
+    SetDieTestMode(true);
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(ConditionTest);
 };
diff --git a/aos/common/die.cc b/aos/common/die.cc
index 467b81d..0ea7007 100644
--- a/aos/common/die.cc
+++ b/aos/common/die.cc
@@ -6,13 +6,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 #include <string.h>
-#ifdef __VXWORKS__
-#include <taskLib.h>
-// Have to re-declare it with __attribute__((noreturn)).
-extern "C" void abort() __attribute__((noreturn));
-#include <usrLib.h>
-#include <dbgLib.h>
-#endif
+#include <signal.h>
 
 #include <string>
 
@@ -28,6 +22,7 @@
 }
 
 namespace {
+
 // Calculates the filename to dump the message into.
 const std::string GetFilename() {
 #ifdef __VXWORKS__
@@ -50,6 +45,9 @@
   }
 #endif
 }
+
+bool test_mode = false;
+
 }  // namespace
 
 void VDie(const char *format, va_list args_in) {
@@ -60,31 +58,28 @@
   fputs("aos fatal: ERROR!! details following\n", stderr);
   va_copy(args1, args_in);
   vfprintf(stderr, format, args1);
-  fputs("aos fatal: ERROR!! see stderr for details\n", stdout);
+  if (!test_mode) {
+    fputs("aos fatal: ERROR!! see stderr for details\n", stdout);
 
-  const std::string filename = GetFilename();
-  if (!filename.empty()) {
-    FILE *error_file = fopen(filename.c_str(), "w");
-    if (error_file != NULL) {
-      va_copy(args2, args_in);
-      vfprintf(error_file, format, args2);
-      fclose(error_file);
-    } else {
-      fprintf(stderr, "aos fatal: fopen('%s', \"w\") failed with %d (%s)\n",
-              filename.c_str(), errno, strerror(errno));
+    const std::string filename = GetFilename();
+    if (!filename.empty()) {
+      FILE *error_file = fopen(filename.c_str(), "w");
+      if (error_file != NULL) {
+        va_copy(args2, args_in);
+        vfprintf(error_file, format, args2);
+        fclose(error_file);
+      } else {
+        fprintf(stderr, "aos fatal: fopen('%s', \"w\") failed with %d (%s)\n",
+                filename.c_str(), errno, strerror(errno));
+      }
     }
   }
 
-#ifdef __VXWORKS__
-  printf("I am 0x%x suspending for debugging purposes.\n", taskIdSelf());
-  printf("\t`tt 0x%x` will give you a stack trace.\n", taskIdSelf());
-  fputs("\t`lkAddr` will reverse lookup a symbol for you.\n", stdout);
-  fputs("\t`dbgHelp` and `help` have some useful commands in them.\n", stdout);
-  taskSuspend(0);
-  printf("You weren't supposed to resume 0x%x!!. Going to really die now.\n",
-         taskIdSelf());
-#endif
   abort();
 }
 
+void SetDieTestMode(bool new_test_mode) {
+  test_mode = new_test_mode;
+}
+
 }  // namespace aos
diff --git a/aos/common/die.h b/aos/common/die.h
index 28519a8..d973b42 100644
--- a/aos/common/die.h
+++ b/aos/common/die.h
@@ -15,6 +15,11 @@
     __attribute__((noreturn))
     __attribute__((format(gnu_printf, 1, 0)));
 
+// Turns on (or off) "test mode", where (V)Die doesn't write out files and
+// doesn't print to stdout.
+// Test mode defaults to false.
+void SetDieTestMode(bool test_mode);
+
 }  // namespace aos
 
 #endif  // AOS_COMMON_DIE_H_
diff --git a/aos/common/logging/logging.gyp b/aos/common/logging/logging.gyp
index b6b339a..ad20166 100644
--- a/aos/common/logging/logging.gyp
+++ b/aos/common/logging/logging.gyp
@@ -11,5 +11,15 @@
         '<(AOS)/build/aos.gyp:logging',
       ],
     },
+    {
+      'target_name': 'queue_logging',
+      'type': 'static_library',
+      'sources': [
+        'queue_logging.cc',
+      ],
+      'dependencies': [
+        '<(AOS)/common/common.gyp:queue_types',
+      ],
+    },
   ],
 }
diff --git a/aos/common/mutex_test.cpp b/aos/common/mutex_test.cpp
index 29e1956..f946dfa 100644
--- a/aos/common/mutex_test.cpp
+++ b/aos/common/mutex_test.cpp
@@ -10,6 +10,7 @@
 #include "gtest/gtest.h"
 
 #include "aos/linux_code/ipc_lib/aos_sync.h"
+#include "aos/common/die.h"
 
 namespace aos {
 namespace testing {
@@ -17,6 +18,11 @@
 class MutexTest : public ::testing::Test {
  public:
   Mutex test_mutex;
+
+ protected:
+  void SetUp() override {
+    SetDieTestMode(true);
+  }
 };
 
 typedef MutexTest MutexDeathTest;
diff --git a/aos/common/queue_test.cc b/aos/common/queue_test.cc
index 32d1d23..ebb0bba 100644
--- a/aos/common/queue_test.cc
+++ b/aos/common/queue_test.cc
@@ -6,6 +6,7 @@
 #include "aos/common/test_queue.q.h"
 #include "aos/common/queue_testutils.h"
 #include "aos/common/util/thread.h"
+#include "aos/common/die.h"
 
 using ::aos::time::Time;
 
@@ -15,6 +16,10 @@
 
 class QueueTest : public ::testing::Test {
  protected:
+  void SetUp() override {
+    SetDieTestMode(true);
+  }
+
   GlobalCoreInstance my_core;
   // Create a new instance of the test queue so that it invalidates the queue
   // that it points to.  Otherwise, we will have a pointer to shared memory that
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index 03d048a..a1925e9 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -1,10 +1,14 @@
 #include "aos/common/queue_types.h"
 
-#include <errno.h>
+#include <inttypes.h>
 
 #include <memory>
+#include <unordered_map>
 
 #include "aos/common/byteorder.h"
+#include "aos/linux_code/ipc_lib/shared_mem.h"
+#include "aos/common/logging/logging.h"
+#include "aos/linux_code/ipc_lib/core_lib.h"
 
 namespace aos {
 
@@ -20,7 +24,6 @@
   }
   if (max_bytes < sizeof(id) + sizeof(name_length) + sizeof(number_fields) +
                       name_length + fields_size) {
-    errno = EOVERFLOW;
     return -1;
   }
   to_network(&id, buffer);
@@ -49,7 +52,6 @@
   decltype(MessageType::id) id;
   decltype(MessageType::number_fields) number_fields;
   if (*bytes < sizeof(id) + sizeof(name_length) + sizeof(number_fields)) {
-    errno = EOVERFLOW;
     return nullptr;
   }
   *bytes -= sizeof(id) + sizeof(name_length) + sizeof(number_fields);
@@ -62,7 +64,6 @@
   buffer += sizeof(number_fields);
 
   if (*bytes < name_length) {
-    errno = EOVERFLOW;
     return nullptr;
   }
   *bytes -= name_length;
@@ -79,7 +80,6 @@
   for (int i = 0; i < number_fields; ++i) {
     size_t field_name_length;
     if (*bytes < sizeof(fields[i]->type) + sizeof(field_name_length)) {
-      errno = EOVERFLOW;
       return nullptr;
     }
     *bytes -= sizeof(fields[i]->type) + sizeof(field_name_length);
@@ -90,7 +90,6 @@
     buffer += sizeof(field_name_length);
 
     if (*bytes < field_name_length) {
-      errno = EOVERFLOW;
       return nullptr;
     }
     *bytes -= field_name_length;
@@ -104,4 +103,95 @@
   return r.release();
 }
 
+namespace type_cache {
+namespace {
+
+struct CacheEntry {
+  const MessageType &type;
+  bool in_shm;
+
+  CacheEntry(const MessageType &type) : type(type), in_shm(false) {}
+};
+
+struct ShmType {
+  uint32_t id;
+  volatile ShmType *next;
+
+  size_t serialized_size;
+  char serialized[];
+};
+
+::std::unordered_map<uint32_t, CacheEntry> cache;
+
+}  // namespace
+
+void Add(const MessageType &type) {
+  if (cache.count(type.id) == 0) {
+    cache.emplace(type.id, type);
+  }
+}
+
+const MessageType &Get(uint32_t type_id) {
+  if (cache.count(type_id) > 0) {
+    return cache.at(type_id).type;
+  }
+
+  const volatile ShmType *c = static_cast<volatile ShmType *>(
+      global_core->mem_struct->queue_types.pointer);
+  while (c != nullptr) {
+    if (c->id == type_id) {
+      size_t bytes = c->serialized_size;
+      MessageType *type = MessageType::Deserialize(
+          const_cast<const char *>(c->serialized), &bytes);
+      cache.emplace(type_id, *type);
+      return *type;
+    }
+    c = c->next;
+  }
+  LOG(FATAL, "MessageType for id 0x%" PRIx32 " not found\n", type_id);
+}
+
+void AddShm(uint32_t type_id) {
+  CacheEntry &cached = cache.at(type_id);
+  if (cached.in_shm) return;
+
+  if (mutex_lock(&global_core->mem_struct->queue_types.lock) != 0) {
+    LOG(FATAL, "locking queue_types lock failed\n");
+  }
+  volatile ShmType *current = static_cast<volatile ShmType *>(
+      global_core->mem_struct->queue_types.pointer);
+  if (current != nullptr) {
+    while (true) {
+      if (current->id == type_id) {
+        cached.in_shm = true;
+        mutex_unlock(&global_core->mem_struct->queue_types.lock);
+        return;
+      }
+      if (current->next == nullptr) break;
+      current = current->next;
+    }
+  }
+  char buffer[512];
+  ssize_t size = cached.type.Serialize(buffer, sizeof(buffer));
+  if (size == -1) {
+    LOG(FATAL, "type %s is too big to fit into %zd bytes\n",
+        cached.type.name, sizeof(buffer));
+  }
+
+  volatile ShmType *shm =
+      static_cast<volatile ShmType *>(shm_malloc(sizeof(ShmType) + size));
+  shm->id = type_id;
+  shm->next = nullptr;
+  shm->serialized_size = size;
+  memcpy(const_cast<char *>(shm->serialized), buffer, size);
+
+  if (current == NULL) {
+    global_core->mem_struct->queue_types.pointer = const_cast<ShmType *>(shm);
+  } else {
+    current->next = shm;
+  }
+  mutex_unlock(&global_core->mem_struct->queue_types.lock);
+}
+
+}  // namespace type_cache
 }  // namespace aos
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index ddc6aea..ba1d7fb 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -39,7 +39,7 @@
   // Constructs a MessageType that doesn't own the storage for any of its
   // names.
   MessageType(uint32_t id, const char *name,
-              ::std::initializer_list<Field *> fields_initializer)
+              ::std::initializer_list<const Field *> fields_initializer)
       : id(id), name(name), owns_names(false) {
     number_fields = fields_initializer.size();
     fields = new const Field *[number_fields];
@@ -61,11 +61,11 @@
     }
   }
 
-  // Returns -1 for error (in errno).
+  // Returns -1 if max_bytes is too small.
   ssize_t Serialize(char *buffer, size_t max_bytes) const;
   // bytes should start out as the number of bytes available in buffer and gets
   // reduced by the number actually read before returning.
-  // Returns a new instance allocated with new or NULL for error (in errno).
+  // Returns a new instance allocated with new or nullptr for error.
   static MessageType *Deserialize(const char *buffer, size_t *bytes);
 
   static bool IsPrimitive(uint32_t type_id) {
diff --git a/aos/common/queue_types_test.cc b/aos/common/queue_types_test.cc
index 38334df..bd95e3a 100644
--- a/aos/common/queue_types_test.cc
+++ b/aos/common/queue_types_test.cc
@@ -13,15 +13,59 @@
                                      new Field{0, "field2"},
                                      new Field{0, "field3"}});
 
-TEST(QueueTypesTest, Serialization) {
+class QueueTypesTest : public ::testing::Test {
+ public:
+  ::testing::AssertionResult Equal(const MessageType &l, const MessageType &r) {
+    using ::testing::AssertionFailure;
+    if (l.id != r.id) {
+      return AssertionFailure() << "id " << l.id << " != " << r.id;
+    }
+    if (strcmp(l.name, r.name) != 0) {
+      return AssertionFailure() << "name '" << l.name << "' != '" << r.name
+                                << "'";
+    }
+    if (l.number_fields != r.number_fields) {
+      return AssertionFailure() << "number_fields " << l.number_fields
+                                << " != " << r.number_fields;
+    }
+    for (int i = 0; i < l.number_fields; ++i) {
+      SCOPED_TRACE("field " + ::std::to_string(i));
+      if (l.fields[i]->type != r.fields[i]->type) {
+        return AssertionFailure() << "type " << l.fields[i]->type
+                                  << " != " << r.fields[i]->type;
+      }
+      if (strcmp(l.fields[i]->name, r.fields[i]->name) != 0) {
+        return AssertionFailure() << "name '" << l.fields[i]->name << "' != '"
+                                  << r.fields[i]->name << "'";
+      }
+    }
+    return ::testing::AssertionSuccess();
+  }
+};
+
+TEST_F(QueueTypesTest, Serialization) {
   char buffer[512];
   ssize_t size;
+  size_t out_size;
+  ::std::unique_ptr<MessageType> deserialized;
 
   size = kTestType1.Serialize(buffer, sizeof(buffer));
   EXPECT_GT(size, 1);
-  size_t out_size = size;
-  ::std::unique_ptr<MessageType> deserialized(MessageType::Deserialize(buffer, &out_size));
+
+  out_size = size;
+  deserialized.reset(MessageType::Deserialize(buffer, &out_size));
   EXPECT_EQ(0u, out_size);
+  EXPECT_TRUE(Equal(kTestType1, *deserialized));
+
+  out_size = size - 1;
+  deserialized.reset(MessageType::Deserialize(buffer, &out_size));
+  EXPECT_EQ(nullptr, deserialized.get());
+
+  out_size = size + 1;
+  ASSERT_LE(out_size, sizeof(buffer));
+  deserialized.reset(MessageType::Deserialize(buffer, &out_size));
+  EXPECT_EQ(1u, out_size);
+  EXPECT_TRUE(Equal(kTestType1, *deserialized));
 }
 
 }  // namespace aos
diff --git a/aos/externals/gtest.patch b/aos/externals/gtest.patch
index 6caba01..cbf7294 100644
--- a/aos/externals/gtest.patch
+++ b/aos/externals/gtest.patch
@@ -1,63 +1,50 @@
-diff -rupN gtest-1.6.0-p1/fused-src/gtest/gtest-all.cc gtest-1.6.0/fused-src/gtest/gtest-all.cc
---- gtest-1.6.0-p1/fused-src/gtest/gtest-all.cc	2011-04-15 12:54:57.000000000 -0700
-+++ gtest-1.6.0/fused-src/gtest/gtest-all.cc	2012-11-12 17:42:37.881573135 -0800
-@@ -379,7 +379,25 @@ class GTEST_API_ SingleFailureChecker {
+diff --git src/gtest-port.cc b/src/gtest-port.cc
+index b860d48..acb459b 100644
+--- a/src/gtest-port.cc
++++ b/src/gtest-port.cc
+@@ -98,6 +98,21 @@ size_t GetThreadCount() {
+   }
+ }
  
- // cpplint thinks that the header is already included, so we want to
- // silence it.
-+#ifdef __VXWORKS__
-+# include <time.h>  // NOLINT
-+# include <sys/times.h>  // NOLINT
-+static inline int gettimeofday(struct timeval *tv, void *) {
-+  struct timespec ts;
++#elif GTEST_OS_LINUX
 +
-+  if (clock_gettime(CLOCK_REALTIME, &ts) != 0) {
-+    printf("Gettimeofday error\n");
-+    tv->tv_sec = 0;
-+    tv->tv_usec = 0;
-+    return -1;
++size_t GetThreadCount() {
++  size_t thread_count = 0;
++  if (DIR *dir = opendir("/proc/self/task")) {
++    while (dirent *entry = readdir(dir)) {
++      if (strcmp(entry->d_name, ".") != 0 && strcmp(entry->d_name, "..") != 0) {
++        ++thread_count;
++      }
++    }
++    closedir(dir);
 +  }
-+  tv->tv_sec  = ts.tv_sec;
-+  tv->tv_usec = ts.tv_nsec/1000;
-+  return 0;
++  return thread_count;
 +}
-+#else
- # include <sys/time.h>  // NOLINT
-+#endif
- # include <unistd.h>  // NOLINT
- 
- #endif  // GTEST_OS_LINUX
-@@ -7751,6 +7769,8 @@ bool FilePath::CreateFolder() const {
-   delete [] unicode;
- #elif GTEST_OS_WINDOWS
-   int result = _mkdir(pathname_.c_str());
-+#elif defined(__VXWORKS__)
-+  int result = mkdir(pathname_.c_str());
- #else
-   int result = mkdir(pathname_.c_str(), 0777);
- #endif  // GTEST_OS_WINDOWS_MOBILE
-@@ -7870,7 +7890,7 @@ void FilePath::Normalize() {
- namespace testing {
- namespace internal {
- 
--#if defined(_MSC_VER) || defined(__BORLANDC__)
-+#if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__VXWORKS__)
- // MSVC and C++Builder do not provide a definition of STDERR_FILENO.
- const int kStdOutFileno = 1;
- const int kStdErrFileno = 2;
-diff -rupN gtest-1.6.0-p1/include/gtest/internal/gtest-port.h gtest-1.6.0/include/gtest/internal/gtest-port.h
---- gtest-1.6.0-p1/include/gtest/internal/gtest-port.h	2011-04-15 12:49:10.000000000 -0700
-+++ gtest-1.6.0/include/gtest/internal/gtest-port.h	2012-11-12 17:27:33.536801263 -0800
-@@ -197,6 +197,12 @@
- #include <sstream>  // NOLINT
- #include <string>  // NOLINT
- 
-+#ifdef __VXWORKS__
-+int read(int fd, void *buf, size_t count);
-+int write(int fd, const void *buf, size_t count);
-+int close(int fd);
-+#endif
 +
- #define GTEST_DEV_EMAIL_ "googletestframework@@googlegroups.com"
- #define GTEST_FLAG_PREFIX_ "gtest_"
- #define GTEST_FLAG_PREFIX_DASH_ "gtest-"
+ #else
+ 
+ size_t GetThreadCount() {
+diff --git a/src/gtest-death-test.cc b/src/gtest-death-test.cc
+index 8b2e413..faad3a4 100644
+--- a/src/gtest-death-test.cc
++++ b/src/gtest-death-test.cc
+@@ -44,6 +44,8 @@
+ # include <fcntl.h>
+ # include <limits.h>
+ # include <stdarg.h>
++# include <sys/time.h>
++# include <sys/resource.h>
+ 
+ # if GTEST_OS_WINDOWS
+ #  include <windows.h>
+@@ -898,6 +900,11 @@ inline char** GetEnviron() { return environ; }
+ // This function is called in a clone()-ed process and thus must avoid
+ // any potentially unsafe operations like malloc or libc functions.
+ static int ExecDeathTestChildMain(void* child_arg) {
++  rlimit core_rlimit;
++  core_rlimit.rlim_cur = 0;
++  core_rlimit.rlim_max = 0;
++  GTEST_DEATH_TEST_CHECK_SYSCALL_(setrlimit(RLIMIT_CORE, &core_limit));
++
+   ExecDeathTestArgs* const args = static_cast<ExecDeathTestArgs*>(child_arg);
+   GTEST_DEATH_TEST_CHECK_SYSCALL_(close(args->close_fd));
diff --git a/aos/linux_code/camera/Buffers.cpp b/aos/linux_code/camera/Buffers.cpp
index e1d22b6..19c1d45 100644
--- a/aos/linux_code/camera/Buffers.cpp
+++ b/aos/linux_code/camera/Buffers.cpp
@@ -61,24 +61,21 @@
 }
 
 void Buffers::Release() {
-  if (message_ != NULL) {
-    queue_->FreeMessage(message_);
-    message_ = NULL;
-  }
+  message_.reset();
 }
-const void *Buffers::GetNext(bool block,
-                       uint32_t *bytesused, timeval *timestamp, uint32_t *sequence) {
+const void *Buffers::GetNext(bool block, uint32_t *bytesused,
+                             timeval *timestamp, uint32_t *sequence) {
   Release();
 
   // TODO(brians) make sure the camera reader process hasn't died
   do {
     if (block) {
-      message_ = static_cast<const Message *>(queue_->ReadMessage(
-              RawQueue::kPeek | RawQueue::kBlock));
+      message_.reset(static_cast<const Message *>(
+          queue_->ReadMessage(RawQueue::kPeek | RawQueue::kBlock)));
     } else {
       static int index = 0;
-      message_ = static_cast<const Message *>(queue_->ReadMessageIndex(
-              RawQueue::kBlock, &index));
+      message_.reset(static_cast<const Message *>(
+          queue_->ReadMessageIndex(RawQueue::kBlock, &index)));
     }
   } while (block && message_ == NULL);
   if (message_ != NULL) {
@@ -132,9 +129,12 @@
   
   return myfds[0];
 }
-Buffers::Buffers() : server_(CreateSocket(connect)), fd_(FetchFD()), message_(NULL) {
+Buffers::Buffers()
+    : server_(CreateSocket(connect)),
+      fd_(FetchFD()),
+      queue_(RawQueue::Fetch(kQueueName.c_str(), sizeof(Message), 971, 1)),
+      message_(queue_) {
   MMap();
-  queue_ = RawQueue::Fetch(kQueueName.c_str(), sizeof(Message), 971, 1);
 }
 
 Buffers::~Buffers() {
diff --git a/aos/linux_code/camera/Buffers.h b/aos/linux_code/camera/Buffers.h
index b447468..aedd79f 100644
--- a/aos/linux_code/camera/Buffers.h
+++ b/aos/linux_code/camera/Buffers.h
@@ -8,6 +8,7 @@
 
 #include "aos/linux_code/ipc_lib/queue.h"
 #include "aos/common/type_traits.h"
+#include "aos/atom_code/ipc_lib/unique_message_ptr.h"
 
 namespace aos {
 namespace camera {
@@ -17,6 +18,7 @@
   // It has to do a lot of the same things as all the other ones, but it gets
   // the information from different places (some of it gets sent out by it).
   friend class Reader;
+
   // Not an abstract name so that an existing one can just be unlinked without
   // disturbing it if necessary (like with shm_link).
   static const std::string kFDServerName;
@@ -50,14 +52,17 @@
     uint32_t sequence;
   };
   static_assert(shm_ok<Message>::value, "it's going through queues");
-  // The current one. Sometimes NULL.
-  const Message *message_;
-  static const std::string kQueueName;
+
   // NULL for the Reader one.
-  RawQueue *queue_;
+  RawQueue *const queue_;
+  // The current one. Sometimes NULL.
+  unique_message_ptr<const Message> message_;
+
+  static const std::string kQueueName;
   // Make the actual mmap calls.
   // Called by Buffers() automatically.
   void MMap();
+
  public:
   Buffers();
   // Will clean everything up.
@@ -89,4 +94,3 @@
 } // namespace aos
 
 #endif
-
diff --git a/aos/linux_code/camera/camera.gyp b/aos/linux_code/camera/camera.gyp
index e4f1e04..fabd52f 100644
--- a/aos/linux_code/camera/camera.gyp
+++ b/aos/linux_code/camera/camera.gyp
@@ -47,9 +47,11 @@
       'dependencies': [
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:queue',
         '<(AOS)/build/aos.gyp:logging',
+        '<(AOS)/atom_code/ipc_lib/ipc_lib.gyp:scoped_message_ptr',
       ],
       'export_dependent_settings': [
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:queue',
+        '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:scoped_message_ptr',
       ],
     },
     {
diff --git a/aos/linux_code/ipc_lib/aos_sync.c b/aos/linux_code/ipc_lib/aos_sync.c
index 52ebed1..a607001 100644
--- a/aos/linux_code/ipc_lib/aos_sync.c
+++ b/aos/linux_code/ipc_lib/aos_sync.c
@@ -18,13 +18,19 @@
   return result;
 }
 
-// this code is based on something that appears to be based on <http://www.akkadia.org/drepper/futex.pdf>, which also has a lot of useful information
-// should probably use <http://lxr.linux.no/linux+v2.6.34/Documentation/robust-futexes.txt> once it becomes available
+// this code is based on something that appears to be based on
+//   <http://www.akkadia.org/drepper/futex.pdf>, which also has a lot of useful
+//   information
+// should probably use
+// <http://lxr.linux.no/linux+v2.6.34/Documentation/robust-futexes.txt> once it
+// becomes available
 //   (sys_set_robust_list appears to be the function name)
 // <http://locklessinc.com/articles/futex_cheat_sheet/> and
 //   <http://locklessinc.com/articles/mutex_cv_futex/> are useful
-// <http://lwn.net/Articles/360699/> has a nice overview of futexes in late 2009 (fairly recent compared to everything else...)
-// can't use PRIVATE futex operations because they use the pid (or something) as part of the hash
+// <http://lwn.net/Articles/360699/> has a nice overview of futexes in late 2009
+//   (fairly recent compared to everything else...)
+// can't use PRIVATE futex operations because they use the pid (or something) as
+//   part of the hash
 //
 // Remember that EAGAIN and EWOUDBLOCK are the same! (ie if you get EAGAIN from
 // FUTEX_WAIT, the docs call it EWOULDBLOCK...)
@@ -60,7 +66,6 @@
   if (c == 1) c = xchg(m, 2);
   while (c) {
     /* Wait in the kernel */
-    //printf("sync here %d\n", __LINE__);
     if (sys_futex(m, FUTEX_WAIT, 2, timeout, NULL, 0) == -1) {
       if (signals_fail && errno == EINTR) {
         return 1;
@@ -69,7 +74,6 @@
         return 2;
       }
     }
-    //printf("sync here %d\n", __LINE__);
     c = xchg(m, 2);
   }
   return 0;
@@ -148,6 +152,8 @@
   mutex_unlock(m);
 
   while (1) {
+    // Wait in the kernel iff the value of it doesn't change (ie somebody else
+    // does a wake) from before we unlocked the mutex.
     if (sys_futex(c, FUTEX_WAIT, wait_start, NULL, NULL, 0) == -1) {
       // If it failed for some reason other than somebody else doing a wake
       // before we actually made it to sleep.
@@ -161,8 +167,12 @@
         abort();
       }
     }
+    // Relock the mutex now that we're done waiting.
     // Simplified mutex_lock that always leaves it
     // contended in case anybody else got requeued.
+    // If we got requeued above, this will just succeed the first time because
+    // the person waking us from the above wait (changed to be on the mutex
+    // instead of the condition) will have just set it to 0.
     while (xchg(m, 2) != 0) {
       if (sys_futex(m, FUTEX_WAIT, 2, NULL, NULL, 0) == -1) {
         // Try again if it was because of a signal or somebody else unlocked it
@@ -180,7 +190,11 @@
 }
 
 void condition_signal(mutex *c) {
+  // This will cause anybody else who is in between unlocking the mutex and
+  // going to sleep in the kernel to not go to sleep and return immediately
+  // instead.
   __sync_fetch_and_add(c, 1);
+  // Wake at most 1 person who is waiting in the kernel.
   if (sys_futex(c, FUTEX_WAKE, 1, NULL, NULL, 0) == -1) {
     fprintf(stderr, "sync: FUTEX_WAKE(%p, 1, NULL, NULL, 0)"
         " failed with %d: %s\n",
@@ -192,7 +206,9 @@
 
 void condition_broadcast(mutex *c, mutex *m) {
   __sync_fetch_and_add(c, 1);
-  // Wake 1 waiter and requeue the rest.
+  // Wake at most 1 waiter and requeue the rest.
+  // Everybody else is going to have to wait for the 1st person to take the
+  // mutex anyways.
   if (sys_futex_requeue(c, FUTEX_REQUEUE, 1, INT_MAX, m) == -1) {
     fprintf(stderr, "sync: FUTEX_REQUEUE(%p, 1, INT_MAX, %p, 0)"
         " failed with %d: %s\n",
diff --git a/aos/linux_code/ipc_lib/aos_sync.h b/aos/linux_code/ipc_lib/aos_sync.h
index 7a81ca3..0d55246 100644
--- a/aos/linux_code/ipc_lib/aos_sync.h
+++ b/aos/linux_code/ipc_lib/aos_sync.h
@@ -48,6 +48,8 @@
 // They are designed for signalling when something happens (possibly to
 // multiple listeners). A mutex manipulated with them can only be set or unset.
 //
+// Another name for this kind of synchronization mechanism is a "notification".
+//
 // They are different from the condition_ functions in that they do NOT work
 // correctly as standard condition variables. While it is possible to keep
 // track of the "condition" using the value part of the futex_* functions, the
diff --git a/aos/linux_code/ipc_lib/condition.cc b/aos/linux_code/ipc_lib/condition.cc
index b764026..0ba4145 100644
--- a/aos/linux_code/ipc_lib/condition.cc
+++ b/aos/linux_code/ipc_lib/condition.cc
@@ -6,8 +6,8 @@
 
 namespace aos {
 
-static_assert(shm_ok<Condition>::value, "Condition should work"
-              " in shared memory");
+static_assert(shm_ok<Condition>::value,
+              "Condition should work in shared memory");
 
 Condition::Condition(Mutex *m) : impl_(), m_(m) {}
 
diff --git a/aos/linux_code/ipc_lib/core_lib.c b/aos/linux_code/ipc_lib/core_lib.c
index cc1ccbb..2bd6c25 100644
--- a/aos/linux_code/ipc_lib/core_lib.c
+++ b/aos/linux_code/ipc_lib/core_lib.c
@@ -5,7 +5,7 @@
 
 #include "aos/linux_code/ipc_lib/shared_mem.h"
 
-static inline uint8_t aos_8max(uint8_t l, uint8_t r) {
+static uint8_t aos_8max(uint8_t l, uint8_t r) {
   return (l > r) ? l : r;
 }
 void *shm_malloc_aligned(size_t length, uint8_t alignment) {
diff --git a/aos/linux_code/ipc_lib/ipc_lib.gyp b/aos/linux_code/ipc_lib/ipc_lib.gyp
index df7b658..08e8df8 100644
--- a/aos/linux_code/ipc_lib/ipc_lib.gyp
+++ b/aos/linux_code/ipc_lib/ipc_lib.gyp
@@ -60,6 +60,7 @@
         'core_lib',
         '<(AOS)/common/common.gyp:queue_testutils',
         '<(AOS)/common/common.gyp:time',
+        '<(AOS)/common/common.gyp:die',
       ],
     },
     {
@@ -76,6 +77,22 @@
         'core_lib',
         '<(AOS)/common/common.gyp:die',
       ],
+      'variables': {
+        'is_special_test': 1,
+      },
+    },
+    {
+      'target_name': 'scoped_message_ptr',
+      'type': 'static_library',
+      'sources': [
+        #'scoped_message_ptr.h',
+      ],
+      'dependencies': [
+        'queue',
+      ],
+      'export_dependent_settings': [
+        'queue',
+      ],
     },
   ],
 }
diff --git a/aos/linux_code/ipc_lib/ipc_stress_test.cc b/aos/linux_code/ipc_lib/ipc_stress_test.cc
index 1b55e82..4a9d93f 100644
--- a/aos/linux_code/ipc_lib/ipc_stress_test.cc
+++ b/aos/linux_code/ipc_lib/ipc_stress_test.cc
@@ -7,7 +7,6 @@
 #include <libgen.h>
 #include <assert.h>
 
-#include <vector>
 #include <string>
 
 #include "aos/common/time.h"
@@ -22,6 +21,10 @@
 // stderr output from each test run and only prints it out (not interleaved with
 // the output from any other run) if the test fails.
 //
+// They have to be run in separate processes because (in addition to various
+// parts of our code not being thread-safe...) gtest does not like multiple
+// threads.
+//
 // It's written in C++ for performance. We need actual OS-level parallelism for
 // this to work, which means that Ruby's out because it doesn't have good
 // support for doing that. My Python implementation ended up pretty heavily disk
@@ -33,14 +36,14 @@
 // arguments to pass to it.
 // Using --gtest_filter is a bad idea because it seems to result in a lot of
 // swapping which causes everything to be disk-bound (at least for me).
-static const ::std::vector< ::std::vector< ::std::string>> kTests = {
+static const char * kTests[][] = {
   {"queue_test"},
   {"condition_test"},
   {"mutex_test"},
   {"raw_queue_test"},
 };
 // These arguments get inserted before any per-test arguments.
-static const ::std::vector< ::std::string> kDefaultArgs = {
+static const char *kDefaultArgs[] = {
   "--gtest_repeat=30",
   "--gtest_shuffle",
 };
@@ -75,7 +78,7 @@
 
 // Gets called after each child forks to run a test.
 void __attribute__((noreturn)) DoRunTest(
-    Shared *shared, const ::std::vector< ::std::string> &test, int pipes[2]) {
+    Shared *shared, const ::std::array<const char *> &test, int pipes[2]) {
   if (close(pipes[0]) == -1) {
     Die("close(%d) of read end of pipe failed with %d: %s\n",
         pipes[0], errno, strerror(errno));
@@ -95,6 +98,7 @@
 
   size_t size = test.size();
   size_t default_size = kDefaultArgs.size();
+  // There's no chance to free this because we either exec or Die.
   const char **args = new const char *[size + default_size + 1];
   // The actual executable to run.
   ::std::string executable;
@@ -120,7 +124,9 @@
 void DoRun(Shared *shared) {
   int iterations = 0;
   // An iterator pointing to a random one of the tests.
-  auto test = kTests.begin() + (getpid() % kTests.size());
+  // We randomize based on PID because otherwise they all end up running the
+  // same test at the same time for the whole test.
+  const char *(*test)[] = &kTests[getpid() % kTestsLength];
   int pipes[2];
   while (time::Time::Now() < shared->stop_time) {
     if (pipe(pipes) == -1) {
@@ -212,7 +218,10 @@
   new (shared) Shared(time::Time::Now() + kTestTime);
 
   char *temp = strdup(argv[0]);
-  shared->path = strdup(dirname(temp));
+  if (asprintf(const_cast<char **>(&shared->path),
+               "%s/../tests", dirname(temp)) == -1) {
+    Die("asprintf failed with %d: %s\n", errno, strerror(errno));
+  }
   free(temp);
 
   for (int i = 0; i < kTesters; ++i) {
diff --git a/aos/linux_code/ipc_lib/queue.cc b/aos/linux_code/ipc_lib/queue.cc
index e67f22c..8a86b7f 100644
--- a/aos/linux_code/ipc_lib/queue.cc
+++ b/aos/linux_code/ipc_lib/queue.cc
@@ -38,6 +38,7 @@
 struct RawQueue::MessageHeader {
   int ref_count;
   int index;  // in pool_
+  // Gets the message header immediately preceding msg.
   static MessageHeader *Get(const void *msg) {
     return reinterpret_cast<MessageHeader *>(__builtin_assume_aligned(
         static_cast<uint8_t *>(const_cast<void *>(msg)) - sizeof(MessageHeader),
@@ -50,8 +51,8 @@
     memcpy(this, &temp, sizeof(*this));
   }
 };
-static_assert(shm_ok<RawQueue::MessageHeader>::value, "the whole point"
-              " is to stick it in shared memory");
+static_assert(shm_ok<RawQueue::MessageHeader>::value,
+              "the whole point is to stick it in shared memory");
 
 struct RawQueue::ReadData {
   bool writable_start;
@@ -73,7 +74,7 @@
 }
 
 RawQueue::RawQueue(const char *name, size_t length, int hash, int queue_length)
-  : readable_(&data_lock_), writable_(&data_lock_) {
+    : readable_(&data_lock_), writable_(&data_lock_) {
   const size_t name_size = strlen(name) + 1;
   char *temp = static_cast<char *>(shm_malloc(name_size));
   memcpy(temp, name, name_size);
@@ -115,17 +116,17 @@
   if (kFetchDebug) {
     printf("fetching queue %s\n", name);
   }
-  if (mutex_lock(&global_core->mem_struct->queues.alloc_lock) != 0) {
+  if (mutex_lock(&global_core->mem_struct->queues.lock) != 0) {
     return NULL;
   }
   RawQueue *current = static_cast<RawQueue *>(
-      global_core->mem_struct->queues.queue_list);
+      global_core->mem_struct->queues.pointer);
   if (current != NULL) {
     while (true) {
       // If we found a matching queue.
       if (strcmp(current->name_, name) == 0 && current->length_ == length &&
           current->hash_ == hash && current->queue_length_ == queue_length) {
-        mutex_unlock(&global_core->mem_struct->queues.alloc_lock);
+        mutex_unlock(&global_core->mem_struct->queues.lock);
         return current;
       } else {
         if (kFetchDebug) {
@@ -142,12 +143,12 @@
   RawQueue *r = new (shm_malloc(sizeof(RawQueue)))
       RawQueue(name, length, hash, queue_length);
   if (current == NULL) {  // if we don't already have one
-    global_core->mem_struct->queues.queue_list = r;
+    global_core->mem_struct->queues.pointer = r;
   } else {
     current->next_ = r;
   }
 
-  mutex_unlock(&global_core->mem_struct->queues.alloc_lock);
+  mutex_unlock(&global_core->mem_struct->queues.lock);
   return r;
 }
 RawQueue *RawQueue::Fetch(const char *name, size_t length, int hash,
diff --git a/aos/linux_code/ipc_lib/queue_test.cc b/aos/linux_code/ipc_lib/queue_test.cc
index c87bd7b..0a982cc 100644
--- a/aos/linux_code/ipc_lib/queue_test.cc
+++ b/aos/linux_code/ipc_lib/queue_test.cc
@@ -15,6 +15,7 @@
 #include "aos/common/queue_testutils.h"
 #include "aos/common/time.h"
 #include "aos/common/logging/logging.h"
+#include "aos/common/die.h"
 
 using ::testing::AssertionResult;
 using ::testing::AssertionSuccess;
@@ -136,6 +137,9 @@
 
   void SetUp() override {
     ::testing::Test::SetUp();
+
+    SetDieTestMode(true);
+
     fatal_failure = static_cast<char *>(shm_malloc(sizeof(fatal_failure)));
     static bool registered = false;
     if (!registered) {
diff --git a/aos/linux_code/ipc_lib/shared_mem.c b/aos/linux_code/ipc_lib/shared_mem.c
index 4e38117..da91b68 100644
--- a/aos/linux_code/ipc_lib/shared_mem.c
+++ b/aos/linux_code/ipc_lib/shared_mem.c
@@ -21,8 +21,10 @@
 void init_shared_mem_core(aos_shm_core *shm_core) {
   clock_gettime(CLOCK_REALTIME, &shm_core->identifier);
   shm_core->msg_alloc_lock = 0;
-  shm_core->queues.queue_list = NULL;
-  shm_core->queues.alloc_lock = 0;
+  shm_core->queues.pointer = NULL;
+  shm_core->queues.lock = 0;
+  shm_core->queue_types.pointer = NULL;
+  shm_core->queue_types.lock = 0;
 }
 
 ptrdiff_t aos_core_get_mem_usage(void) {
diff --git a/aos/linux_code/ipc_lib/shared_mem.h b/aos/linux_code/ipc_lib/shared_mem.h
index e5059c4..c1b1f9c 100644
--- a/aos/linux_code/ipc_lib/shared_mem.h
+++ b/aos/linux_code/ipc_lib/shared_mem.h
@@ -18,10 +18,12 @@
 // can have regular pointers to other stuff in shared memory.
 #define SHM_START 0x20000000
 
-typedef struct aos_queue_global_t {
-  mutex alloc_lock;
-  void *queue_list;  // an aos::Queue* declared in C code
-} aos_queue_global;
+// A structure that represents some kind of global pointer that everything
+// shares.
+typedef struct aos_global_pointer_t {
+  mutex lock;
+  void *pointer;
+} aos_global_pointer;
 
 typedef struct aos_shm_core_t {
   // clock_gettime(CLOCK_REALTIME, &identifier) gets called to identify
@@ -32,7 +34,12 @@
   mutex creation_condition;
   mutex msg_alloc_lock;
   void *msg_alloc;
-  aos_queue_global queues;
+  // A pointer to the head of the linked list of queues.
+  // pointer points to a ::aos::Queue.
+  aos_global_pointer queues;
+  // A pointer to the head of the linked list of queue message types.
+  // pointer points to a ::aos::type_cache::ShmType.
+  aos_global_pointer queue_types;
 } aos_shm_core;
 
 enum aos_core_create {
diff --git a/output/downloaded/.gitignore b/output/downloaded/.gitignore
index df9fd00..4e0d593 100644
--- a/output/downloaded/.gitignore
+++ b/output/downloaded/.gitignore
@@ -4,7 +4,7 @@
 /eigen-3.1.3/
 /gccdist.zip
 /gccdist/
-/gtest-1.6.0/
+/gtest-1.6.0-p1/
 /gtest-1.6.0.zip
 /gyp-1738/
 /javacv-0.2-bin.zip