Merge "fix confusion between "input" and "output""
diff --git a/aos/build/aos.gyp b/aos/build/aos.gyp
index 96cfc1b..1187d05 100644
--- a/aos/build/aos.gyp
+++ b/aos/build/aos.gyp
@@ -21,6 +21,9 @@
           'sources': [
             '<(AOS)/linux_code/logging/linux_interface.cc',
           ],
+          'dependencies': [
+            '<(AOS)/linux_code/linux_code.gyp:complex_thread_local',
+          ],
         }],
       ],
       'dependencies': [
diff --git a/aos/build/aos.gypi b/aos/build/aos.gypi
index c390052..5a9119d 100644
--- a/aos/build/aos.gypi
+++ b/aos/build/aos.gypi
@@ -28,6 +28,12 @@
           ['CXX', '<!(readlink -f <(AOS)/build/crio_cxx)'],
         ],
       }
+    ], ['PLATFORM=="linux-arm-gcc_frc"', {
+        'make_global_settings': [
+          ['CC', '<(ccache)<!(which arm-frc-linux-gnueabi-gcc-4.9)'],
+          ['CXX', '<(ccache)<!(which arm-frc-linux-gnueabi-g++-4.9)'],
+        ],
+      },
     ], ['PLATFORM=="linux-arm-gcc"', {
         'make_global_settings': [
           ['CC', '<(ccache)<!(which arm-linux-gnueabihf-gcc-4.7)'],
@@ -105,7 +111,7 @@
           ],
         },
       },
-    ], ['SANITIZER_FPIE!=""', {
+    ], ['EXTERNALS_EXTRA=="-fPIE"', {
         'target_defaults': {
           'cflags': [
             '-fPIE',
@@ -137,7 +143,6 @@
       '__STDC_FORMAT_MACROS',
       '__STDC_CONSTANT_MACROS',
       '__STDC_LIMIT_MACROS',
-      '_FORTIFY_SOURCE=2',
     ],
     'ldflags': [
       '-pipe',
@@ -193,6 +198,7 @@
         }, { # 'DEBUG=="no"'
           'defines': [
             'AOS_DEBUG=0',
+            '_FORTIFY_SOURCE=2',
           ],
           'cflags': [
             '-O3',
@@ -209,12 +215,6 @@
                 '-fno-strict-aliasing',
               ],
             }],
-            ['ARCHITECTURE=="arm"', {
-              'cflags': [
-                '-mcpu=cortex-a8',
-                '-mfpu=neon',
-              ],
-            }],
             ['ARCHITECTURE=="amd64"', {
               'cflags': [
                 '-fstack-protector-all',
@@ -234,6 +234,28 @@
           ],
         }
       ],
+      ['ARCHITECTURE=="arm" and FULL_COMPILER!="gcc_frc"', {
+        'cflags': [
+          '-mcpu=cortex-a8',
+          '-mfpu=neon',
+        ],
+        'ldflags': [
+          '-mcpu=cortex-a8',
+          '-mfpu=neon',
+        ],
+      }],
+      ['ARCHITECTURE=="arm" and FULL_COMPILER=="gcc_frc"', {
+        'cflags': [
+          '-mcpu=cortex-a9',
+          '-mfpu=neon',
+          '-mfloat-abi=softfp',
+        ],
+        'ldflags': [
+          '-mcpu=cortex-a9',
+          '-mfpu=neon',
+          '-mfloat-abi=softfp',
+        ],
+      }],
       ['PLATFORM=="crio"', {
           'target_conditions': [
             ['_type=="shared_library"', {
diff --git a/aos/build/aos_all.gyp b/aos/build/aos_all.gyp
index 2f6be93..1caac63 100644
--- a/aos/build/aos_all.gyp
+++ b/aos/build/aos_all.gyp
@@ -1,6 +1,5 @@
 # This file has the executables etc that AOS builds.
 # User .gyp files for the prime should depend on :Prime.
-# User .gyp files for the crio should depend on :Crio.
 {
   'targets': [
     {
@@ -10,6 +9,7 @@
         'no_rsync': 1,
       },
       'dependencies': [
+        'Common',
         '<(AOS)/linux_code/linux_code.gyp:core',
         '<(AOS)/linux_code/logging/logging.gyp:binary_log_writer',
         '<(AOS)/linux_code/logging/logging.gyp:log_streamer',
@@ -18,27 +18,7 @@
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:ipc_stress_test',
         '<(AOS)/linux_code/starter/starter.gyp:starter_exe',
         '<(AOS)/linux_code/starter/starter.gyp:netconsole',
-        '<(AOS)/common/common.gyp:queue_test',
-        '<(AOS)/common/common.gyp:die_test',
-        '<(AOS)/common/common.gyp:queue_types_test',
-        '<(AOS)/common/util/util.gyp:string_to_num_test',
-        '<(AOS)/common/util/util.gyp:trapezoid_profile_test',
-        '<(AOS)/common/util/util.gyp:wrapping_counter_test',
-        '<(AOS)/common/libc/libc.gyp:dirname_test',
-        '<(AOS)/common/libc/libc.gyp:aos_strerror_test',
-        '<(AOS)/common/libc/libc.gyp:aos_strsignal_test',
-        '<(AOS)/common/util/util.gyp:run_command_test',
-        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:cows_test',
-        '<(DEPTH)/bbb_cape/src/bbb/bbb.gyp:packet_finder_test',
         '<(AOS)/linux_code/linux_code.gyp:complex_thread_local_test',
-        'Common',
-      ],
-    },
-    {
-      'target_name': 'Crio',
-      'type': 'none',
-      'dependencies': [
-        'Common',
       ],
     },
     {
@@ -55,6 +35,15 @@
         '<(AOS)/common/common.gyp:once_test',
         '<(AOS)/common/logging/logging.gyp:logging_impl_test',
         '<(AOS)/common/util/util.gyp:options_test',
+        '<(AOS)/common/common.gyp:queue_test',
+        '<(AOS)/common/common.gyp:die_test',
+        '<(AOS)/common/common.gyp:queue_types_test',
+        '<(AOS)/common/util/util.gyp:trapezoid_profile_test',
+        '<(AOS)/common/util/util.gyp:wrapping_counter_test',
+        '<(AOS)/common/libc/libc.gyp:dirname_test',
+        '<(AOS)/common/libc/libc.gyp:aos_strerror_test',
+        '<(AOS)/common/libc/libc.gyp:aos_strsignal_test',
+        '<(AOS)/common/util/util.gyp:run_command_test',
       ],
     },
   ],
diff --git a/aos/build/build.py b/aos/build/build.py
index f0300f9..faa6fe1 100755
--- a/aos/build/build.py
+++ b/aos/build/build.py
@@ -553,7 +553,7 @@
       return r
 
   ARCHITECTURES = ('arm', 'amd64')
-  COMPILERS = ('clang', 'gcc', 'gcc_4.8')
+  COMPILERS = ('clang', 'gcc', 'gcc_4.8', 'gcc_frc')
   SANITIZERS = ('address', 'undefined', 'integer', 'memory', 'thread', 'none')
   SANITIZER_TEST_WARNINGS = {
       'memory': (True,
@@ -570,7 +570,8 @@
     for architecture in PrimeProcessor.ARCHITECTURES:
       for compiler in PrimeProcessor.COMPILERS:
         for debug in [True, False]:
-          if architecture == 'arm' and compiler == 'gcc_4.8':
+          if ((architecture == 'arm' and compiler == 'gcc_4.8') or
+              (architecture == 'amd64' and compiler == 'gcc_frc')):
             # We don't have a compiler to use here.
             continue
           platforms.append(
@@ -611,13 +612,21 @@
   def download_externals(self, platforms):
     to_download = set()
     for architecture in PrimeProcessor.ARCHITECTURES:
+      pie_sanitizers = set()
       for sanitizer in PrimeProcessor.PIE_SANITIZERS:
-        if platforms & self.select_platforms(architecture=architecture,
-                                             sanitizer=sanitizer):
-          to_download.add(architecture + '-fPIE')
-        if platforms & self.select_platforms(architecture=architecture,
-                                             sanitizer='none'):
-          to_download.add(architecture)
+        pie_sanitizers.update(self.select_platforms(architecture=architecture,
+                                                    sanitizer=sanitizer))
+      if platforms & pie_sanitizers:
+        to_download.add(architecture + '-fPIE')
+
+      frc_platforms = self.select_platforms(architecture=architecture,
+                                            compiler='gcc_frc')
+      if platforms & frc_platforms:
+        to_download.add(architecture + '_frc')
+
+      if platforms & (self.platforms() - pie_sanitizers - frc_platforms):
+        to_download.add(architecture)
+
     for download_target in to_download:
       call_download_externals(download_target)
 
@@ -695,6 +704,9 @@
       if platform.compiler() == 'gcc' and platform.architecture() == 'amd64':
         packages.add('gcc-4.7')
         packages.add('g++-4.7')
+      elif platform.compiler() == 'gcc_frc':
+        packages.add('gcc-4.9-arm-frc-linux-gnueabi')
+        packages.add('g++-4.9-arm-frc-linux-gnueabi')
 
     self.do_check_installed(tuple(packages))
 
@@ -955,9 +967,9 @@
              '-DFULL_COMPILER=%s' % platform.compiler(),
              '-DDEBUG=%s' % ('yes' if platform.debug() else 'no'),
              '-DSANITIZER=%s' % platform.sanitizer(),
-             '-DSANITIZER_FPIE=%s' %
+             '-DEXTERNALS_EXTRA=%s' %
              ('-fPIE' if platform.sanitizer() in PrimeProcessor.PIE_SANITIZERS
-              else '')) +
+              else ('_frc' if platform.compiler() == 'gcc_frc' else ''))) +
             processor.extra_gyp_flags() + (args.main_gyp,),
             stdin=subprocess.PIPE)
         gyp.communicate(("""
diff --git a/aos/build/download_externals.sh b/aos/build/download_externals.sh
index 106e2db..ecd1b01 100755
--- a/aos/build/download_externals.sh
+++ b/aos/build/download_externals.sh
@@ -10,6 +10,11 @@
 # the value from CONFIGURE_FLAGS has to get overriden in some places.
 ALL_LDFLAGS=""
 
+# Flags that should get passed to all configure scripts.
+# Some of them need to set LDFLAGS separately to work around stupid configure
+# scripts, so we can't just set that here.
+CONFIGURE_FLAGS=""
+
 if [ "$1" == "arm" ]; then
   COMPILED=${EXTERNALS}/../compiled-arm
 
@@ -20,11 +25,19 @@
   export CFLAGS="-mcpu=cortex-a8 -mfpu=neon"
   export CXXFLAGS="-mcpu=cortex-a8 -mfpu=neon"
   export OBJDUMP=${CROSS_COMPILE}objdump
-  # Flags that should get passed to all configure scripts.
-  # Some of them need to set LDFLAGS separately to work around stupid configure
-  # scripts, so we can't just set that here.
   CONFIGURE_FLAGS="--host=arm-linux-gnueabihf CC=${CC} CXX=${CXX} CFLAGS=\"${CFLAGS}\" CXXFLAGS=\"${CXXFLAGS}\" OBJDUMP=${OBJDUMP}"
   IS_CRIO=0
+elif [ "$1" == "arm_frc" ]; then
+  COMPILED=${EXTERNALS}/../compiled-arm_frc
+
+  CROSS_COMPILE=arm-frc-linux-gnueabi-
+
+  export CC=${CROSS_COMPILE}gcc-4.9
+  export CXX=${CROSS_COMPILE}g++-4.9
+  export CFLAGS="-mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp"
+  export CXXFLAGS="-mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp"
+  export OBJDUMP=${CROSS_COMPILE}objdump
+  CONFIGURE_FLAGS="--host=arm-frc-linux-gnueabi CC=${CC} CXX=${CXX} CFLAGS=\"${CFLAGS}\" CXXFLAGS=\"${CXXFLAGS}\" OBJDUMP=${OBJDUMP}"
 elif [ "$1" == "amd64" ]; then
   COMPILED=${EXTERNALS}/../compiled-amd64
   IS_CRIO=0
diff --git a/aos/build/externals.gyp b/aos/build/externals.gyp
index 44ca1d7..a097fd7 100644
--- a/aos/build/externals.gyp
+++ b/aos/build/externals.gyp
@@ -4,8 +4,8 @@
   'variables': {
     'externals': '<(AOS)/../output/downloaded',
     'externals_abs': '<!(readlink -f ../../output/downloaded)',
-    'compiled': '<(externals)/../compiled-<(ARCHITECTURE)<(SANITIZER_FPIE)',
-    'compiled_abs': '<(externals_abs)/../compiled-<(ARCHITECTURE)<(SANITIZER_FPIE)',
+    'compiled': '<(externals)/../compiled-<(ARCHITECTURE)<(EXTERNALS_EXTRA)',
+    'compiled_abs': '<(externals_abs)/../compiled-<(ARCHITECTURE)<(EXTERNALS_EXTRA)',
 
 # These versions have to be kept in sync with the ones in download_externals.sh.
     'eigen_version': '3.2.1',
diff --git a/aos/common/common.gyp b/aos/common/common.gyp
index e098c0f..fb410b7 100644
--- a/aos/common/common.gyp
+++ b/aos/common/common.gyp
@@ -305,6 +305,7 @@
         'queue_testutils',
         '<(AOS)/linux_code/ipc_lib/ipc_lib.gyp:core_lib',
         'die',
+        '<(AOS)/common/util/util.gyp:thread',
        ],
     },
     {
diff --git a/aos/common/condition.h b/aos/common/condition.h
index c913b47..ef51b89 100644
--- a/aos/common/condition.h
+++ b/aos/common/condition.h
@@ -54,7 +54,8 @@
   // and will be locked when this method returns.
   // NOTE: The relocking of the mutex is not performed atomically with waking
   // up.
-  void Wait();
+  // Returns false.
+  bool Wait();
 
   // Signals at most 1 other process currently Wait()ing on this condition
   // variable. Calling this does not require the mutex associated with this
diff --git a/aos/common/condition_test.cc b/aos/common/condition_test.cc
index 6914a8b..7b9145d 100644
--- a/aos/common/condition_test.cc
+++ b/aos/common/condition_test.cc
@@ -4,6 +4,8 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 
+#include <atomic>
+
 #include "gtest/gtest.h"
 
 #include "aos/common/time.h"
@@ -14,6 +16,7 @@
 #include "aos/common/logging/logging.h"
 #include "aos/common/macros.h"
 #include "aos/common/die.h"
+#include "aos/common/util/thread.h"
 
 using ::aos::time::Time;
 using ::aos::common::testing::GlobalCoreInstance;
@@ -21,7 +24,57 @@
 namespace aos {
 namespace testing {
 
-class ConditionTest : public ::testing::Test {
+class ConditionTestCommon : public ::testing::Test {
+ public:
+  ConditionTestCommon() {}
+
+  void Settle() {
+    time::SleepFor(::Time::InSeconds(0.008));
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(ConditionTestCommon);
+};
+
+// Some simple tests that don't rely on a GlobalCoreInstance to help with
+// debugging problems that cause tests using that to just completely lock up.
+class SimpleConditionTest : public ConditionTestCommon {
+ public:
+  SimpleConditionTest() : condition_(&mutex_) {}
+
+  Mutex mutex_;
+  Condition condition_;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(SimpleConditionTest);
+};
+
+// Makes sure that nothing crashes or anything with a basic Wait() and then
+// Signal().
+// This test is written to hopefully fail instead of deadlocking on failure, but
+// it's tricky because there's no way to kill the child in the middle.
+TEST_F(SimpleConditionTest, Basic) {
+  ::std::atomic_bool child_finished(false);
+  Condition child_ready(&mutex_);
+  ASSERT_FALSE(mutex_.Lock());
+  util::FunctionThread child([this, &child_finished, &child_ready](
+      util::FunctionThread *) {
+    ASSERT_FALSE(mutex_.Lock());
+    child_ready.Broadcast();
+    ASSERT_FALSE(condition_.Wait());
+    child_finished.store(true);
+    mutex_.Unlock();
+  });
+  child.Start();
+  ASSERT_FALSE(child_ready.Wait());
+  EXPECT_FALSE(child_finished.load());
+  condition_.Signal();
+  mutex_.Unlock();
+  child.Join();
+  EXPECT_TRUE(child_finished.load());
+}
+
+class ConditionTest : public ConditionTestCommon {
  public:
   struct Shared {
     Shared() : condition(&mutex) {}
@@ -40,10 +93,6 @@
 
   Shared *const shared_;
 
-  void Settle() {
-    time::SleepFor(::Time::InSeconds(0.008));
-  }
-
  protected:
   void SetUp() override {
     SetDieTestMode(true);
diff --git a/aos/common/mutex.h b/aos/common/mutex.h
index ff953e4..251eb3c 100644
--- a/aos/common/mutex.h
+++ b/aos/common/mutex.h
@@ -28,7 +28,8 @@
   ~Mutex();
 #endif
   // Locks the mutex. If it fails, it calls LOG(FATAL).
-  void Lock();
+  // Returns false.
+  bool Lock();
   // Unlocks the mutex. Fails like Lock.
   // Multiple unlocking is undefined.
   void Unlock();
diff --git a/aos/linux_code/ipc_lib/condition.cc b/aos/linux_code/ipc_lib/condition.cc
index 0ba4145..ed488c5 100644
--- a/aos/linux_code/ipc_lib/condition.cc
+++ b/aos/linux_code/ipc_lib/condition.cc
@@ -11,8 +11,9 @@
 
 Condition::Condition(Mutex *m) : impl_(), m_(m) {}
 
-void Condition::Wait() {
+bool Condition::Wait() {
   condition_wait(&impl_, &m_->impl_);
+  return false;
 }
 
 void Condition::Signal() {
diff --git a/aos/linux_code/ipc_lib/mutex.cpp b/aos/linux_code/ipc_lib/mutex.cpp
index 8c98204..4bd0759 100644
--- a/aos/linux_code/ipc_lib/mutex.cpp
+++ b/aos/linux_code/ipc_lib/mutex.cpp
@@ -17,9 +17,11 @@
 // Lock and Unlock use the return values of mutex_lock/mutex_unlock
 // to determine whether the lock/unlock succeeded.
 
-void Mutex::Lock() {
+bool Mutex::Lock() {
   if (mutex_grab(&impl_) != 0) {
     PLOG(FATAL, "mutex_grab(%p(=%" PRIu32 ")) failed", &impl_, impl_);
+  } else {
+    return false;
   }
 }
 
diff --git a/aos/linux_code/logging/linux_interface.cc b/aos/linux_code/logging/linux_interface.cc
index 0945ddd..0040e94 100644
--- a/aos/linux_code/logging/linux_interface.cc
+++ b/aos/linux_code/logging/linux_interface.cc
@@ -2,6 +2,7 @@
 
 #include <sys/prctl.h>
 
+#include "aos/linux_code/complex_thread_local.h"
 #include "aos/linux_code/thread_local.h"
 #include "aos/common/die.h"
 
@@ -39,23 +40,23 @@
   return process_name + '.' + thread_name;
 }
 
-AOS_THREAD_LOCAL Context *my_context(nullptr);
+::aos::ComplexThreadLocal<Context> my_context;
 
-// A temporary stash for Context objects that we're going to delete ASAP. The
+// True if we're going to delete the current Context object ASAP. The
 // reason for doing this instead of just deleting them is that tsan (at least)
 // doesn't like it when pthread_atfork handlers do complicated stuff and it's
 // not a great idea anyways.
-AOS_THREAD_LOCAL Context *old_context(nullptr);
+AOS_THREAD_LOCAL bool delete_current_context(false);
 
 }  // namespace
 
 Context *Context::Get() {
-  if (__builtin_expect(my_context == nullptr, 0)) {
-    if (old_context != nullptr) {
-      delete old_context;
-      old_context = nullptr;
-    }
-    my_context = new Context();
+  if (__builtin_expect(delete_current_context, false)) {
+    my_context.Clear();
+    delete_current_context = false;
+  }
+  if (__builtin_expect(!my_context.created(), false)) {
+    my_context.Create();
     my_context->name = GetMyName();
     if (my_context->name.size() + 1 > sizeof(LogMessage::name)) {
       Die("logging: process/thread name '%s' is too long\n",
@@ -63,17 +64,11 @@
     }
     my_context->source = getpid();
   }
-  return my_context;
+  return my_context.get();
 }
 
 void Context::Delete() {
-  if (my_context != nullptr) {
-    if (old_context != nullptr) {
-      delete old_context;
-    }
-    old_context = my_context;
-    my_context = nullptr;
-  }
+  delete_current_context = true;
 }
 
 }  // namespace internal