more work towards using queue types for logging
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index d7ec2d2..a774936 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -1,7 +1,7 @@
 {
   'targets': [
     {
-      'target_name': 'queue_test_queue',
+      'target_name': 'test_queue',
       'type': 'static_library',
       'sources': [
         '<(AOS)/common/test_queue.q',
@@ -51,6 +51,7 @@
         '<(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',
+        'mutex',
       ],
     },
     {
@@ -62,6 +63,7 @@
       'dependencies': [
         'queue_types',
         '<(EXTERNALS):gtest',
+        'test_queue',
       ],
     },
     {
@@ -177,7 +179,7 @@
       'dependencies': [
         '<(EXTERNALS):gtest',
         'queue_testutils',
-        'queue_test_queue',
+        'test_queue',
         '<(AOS)/common/util/util.gyp:thread',
         'die',
       ],
diff --git a/aos/common/queue_types.cc b/aos/common/queue_types.cc
index a1925e9..0183510 100644
--- a/aos/common/queue_types.cc
+++ b/aos/common/queue_types.cc
@@ -9,6 +9,7 @@
 #include "aos/linux_code/ipc_lib/shared_mem.h"
 #include "aos/common/logging/logging.h"
 #include "aos/linux_code/ipc_lib/core_lib.h"
+#include "aos/common/mutex.h"
 
 namespace aos {
 
@@ -110,7 +111,8 @@
   const MessageType &type;
   bool in_shm;
 
-  CacheEntry(const MessageType &type) : type(type), in_shm(false) {}
+  CacheEntry(const MessageType &type, bool in_shm)
+      : type(type), in_shm(in_shm) {}
 };
 
 struct ShmType {
@@ -122,20 +124,26 @@
 };
 
 ::std::unordered_map<uint32_t, CacheEntry> cache;
+::aos::Mutex cache_lock;
 
 }  // namespace
 
 void Add(const MessageType &type) {
+  ::aos::MutexLocker locker(&cache_lock);
   if (cache.count(type.id) == 0) {
-    cache.emplace(type.id, type);
+    cache.emplace(::std::piecewise_construct, ::std::forward_as_tuple(type.id),
+                  ::std::forward_as_tuple(type, false));
   }
 }
 
 const MessageType &Get(uint32_t type_id) {
+  ::aos::MutexLocker locker(&cache_lock);
   if (cache.count(type_id) > 0) {
     return cache.at(type_id).type;
   }
 
+  // No need to lock because the only thing that happens is somebody adds on to
+  // the end, and they shouldn't be adding the one we're looking for.
   const volatile ShmType *c = static_cast<volatile ShmType *>(
       global_core->mem_struct->queue_types.pointer);
   while (c != nullptr) {
@@ -143,7 +151,9 @@
       size_t bytes = c->serialized_size;
       MessageType *type = MessageType::Deserialize(
           const_cast<const char *>(c->serialized), &bytes);
-      cache.emplace(type_id, *type);
+      cache.emplace(::std::piecewise_construct,
+                    ::std::forward_as_tuple(type_id),
+                    ::std::forward_as_tuple(*type, true));
       return *type;
     }
     c = c->next;
@@ -152,6 +162,7 @@
 }
 
 void AddShm(uint32_t type_id) {
+  ::aos::MutexLocker locker(&cache_lock);
   CacheEntry &cached = cache.at(type_id);
   if (cached.in_shm) return;
 
@@ -191,6 +202,12 @@
     current->next = shm;
   }
   mutex_unlock(&global_core->mem_struct->queue_types.lock);
+
+  for (int i = 0; i < cached.type.number_fields; ++i) {
+    if (!MessageType::IsPrimitive(cached.type.fields[i]->type)) {
+      AddShm(cached.type.fields[i]->type);
+    }
+  }
 }
 
 }  // namespace type_cache
diff --git a/aos/common/queue_types.h b/aos/common/queue_types.h
index ba1d7fb..9955fe7 100644
--- a/aos/common/queue_types.h
+++ b/aos/common/queue_types.h
@@ -95,14 +95,20 @@
   DISALLOW_COPY_AND_ASSIGN(MessageType);
 };
 
+// Implements a cache of types which usually works per-process but can (when
+// explicitly instructed) put a type in shared memory which other processes will
+// automatically receive.
+// All of these functions are thread-safe.
 namespace type_cache {
 
 // Makes sure a type is in the type cache. This will store a reference to type.
+// The types of any non-primitive fields of type must already be added.
 void Add(const MessageType &type);
 // Retrieves a type from the type cache or shm. LOG(FATAL)s if it can't find it.
 const MessageType &Get(uint32_t type_id);
 // Makes sure a type is in the list in shm. Add must have already been called
 // for type.
+// Also adds the types of any non-primitive fields of type.
 void AddShm(uint32_t type_id);
 
 }  // namespace type_cache
diff --git a/aos/common/queue_types_test.cc b/aos/common/queue_types_test.cc
index bd95e3a..287d555 100644
--- a/aos/common/queue_types_test.cc
+++ b/aos/common/queue_types_test.cc
@@ -4,6 +4,8 @@
 
 #include "gtest/gtest.h"
 
+#include "aos/common/test_queue.q.h"
+
 namespace aos {
 
 typedef MessageType::Field Field;
diff --git a/aos/common/test_queue.q b/aos/common/test_queue.q
index a7b441f..878be08 100644
--- a/aos/common/test_queue.q
+++ b/aos/common/test_queue.q
@@ -1,5 +1,16 @@
 package aos.common.testing;
 
+struct Structure {
+  bool struct_bool;
+  uint16_t struct_int;
+};
+
+message MessageWithStructure {
+  bool other_member;
+  Structure struct1;
+  Structure struct2;
+};
+
 message TestingMessage {
   bool test_bool;
   int32_t test_int;