Removed Common

Change-Id: I01ea8f07220375c2ad9bc0092281d4f27c642303
diff --git a/aos/mutex/BUILD b/aos/mutex/BUILD
new file mode 100644
index 0000000..02cec57
--- /dev/null
+++ b/aos/mutex/BUILD
@@ -0,0 +1,38 @@
+package(default_visibility = ["//visibility:public"])
+
+cc_library(
+    name = "mutex",
+    srcs = [
+        "mutex.cc",
+    ],
+    hdrs = [
+        "mutex.h",
+    ],
+    compatible_with = [
+        "//tools:armhf-debian",
+    ],
+    deps = [
+        "//aos:die",
+        "//aos/type_traits:type_traits",
+        "//aos/logging",
+        "//aos/linux_code/ipc_lib:aos_sync",
+    ],
+)
+
+cc_test(
+    name = "mutex_test",
+    srcs = [
+        "mutex_test.cc",
+    ],
+    deps = [
+        "//aos:die",
+        ":mutex",
+        "//aos/time:time",
+        "//aos/logging",
+        "//aos/util:death_test_log_implementation",
+        "//aos/util:thread",
+        "//aos/testing:googletest",
+        "//aos/testing:test_logging",
+        "//aos/testing:test_shm",
+    ],
+)
diff --git a/aos/mutex/mutex.cc b/aos/mutex/mutex.cc
new file mode 100644
index 0000000..a35f0cd
--- /dev/null
+++ b/aos/mutex/mutex.cc
@@ -0,0 +1,50 @@
+#include "aos/mutex/mutex.h"
+
+#include <inttypes.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "aos/type_traits/type_traits.h"
+#include "aos/logging/logging.h"
+
+namespace aos {
+
+// Lock and Unlock use the return values of mutex_lock/mutex_unlock
+// to determine whether the lock/unlock succeeded.
+
+bool Mutex::Lock() {
+  const int ret = mutex_grab(&impl_);
+  if (ret == 0) {
+    return false;
+  } else if (ret == 1) {
+    return true;
+  } else {
+    LOG(FATAL, "mutex_grab(%p(=%" PRIu32 ")) failed with %d\n",
+        &impl_, impl_.futex, ret);
+  }
+}
+
+void Mutex::Unlock() {
+  mutex_unlock(&impl_);
+}
+
+Mutex::State Mutex::TryLock() {
+  const int ret = mutex_trylock(&impl_);
+  switch (ret) {
+    case 0:
+      return State::kLocked;
+    case 1:
+      return State::kOwnerDied;
+    case 4:
+      return State::kLockFailed;
+    default:
+      LOG(FATAL, "mutex_trylock(%p(=%" PRIu32 ")) failed with %d\n",
+          &impl_, impl_.futex, ret);
+  }
+}
+
+bool Mutex::OwnedBySelf() const {
+  return mutex_islocked(&impl_);
+}
+
+}  // namespace aos
diff --git a/aos/mutex/mutex.h b/aos/mutex/mutex.h
new file mode 100644
index 0000000..8bd986c
--- /dev/null
+++ b/aos/mutex/mutex.h
@@ -0,0 +1,150 @@
+#ifndef AOS_MUTEX_H_
+#define AOS_MUTEX_H_
+
+#include "aos/macros.h"
+#include "aos/type_traits/type_traits.h"
+#include "aos/die.h"
+#include "aos/linux_code/ipc_lib/aos_sync.h"
+
+namespace aos {
+
+class Condition;
+
+// An abstraction of a mutex that is easy to implement for environments other
+// than Linux too.
+// If there are multiple threads or processes contending for the mutex,
+// higher priority ones will succeed in locking first,
+// and tasks of equal priorities have the same chance of getting the lock.
+// To deal with priority inversion, the linux implementation does priority
+// inheritance.
+// Before destroying a mutex, it is important to make sure it isn't locked.
+// Otherwise, the destructor will LOG(FATAL).
+class Mutex {
+ public:
+  // States that signify the result of TryLock.
+  enum class State {
+    // The mutex was acquired successfully.
+    kLocked,
+    // TryLock tried to grab the mutex and failed.
+    kLockFailed,
+    // The previous owner of the mutex died.
+    kOwnerDied,
+  };
+
+  // Creates an unlocked mutex.
+  Mutex() : impl_() {
+    static_assert(shm_ok<Mutex>::value,
+                  "Mutex is not safe for use in shared memory.");
+  }
+  // Verifies that it isn't locked.
+  //
+  // This is important because freeing a locked mutex means there is freed
+  // memory in the middle of the robust list, which breaks things horribly.
+  ~Mutex() = default;
+
+  // Locks the mutex. If it fails, it calls LOG(FATAL).
+  // Returns true if the previous owner died instead of unlocking nicely.
+  bool Lock() __attribute__((warn_unused_result));
+  // Unlocks the mutex. Fails like Lock.
+  // Multiple unlocking is undefined.
+  void Unlock();
+  // Locks the mutex unless it is already locked.
+  // Returns the new state of the mutex.
+  // Doesn't wait for the mutex to be unlocked if it is locked.
+  State TryLock() __attribute__((warn_unused_result));
+
+  // Returns true iff the current task has this mutex locked.
+  // This is mainly for IPCRecursiveMutexLocker to use.
+  bool OwnedBySelf() const;
+
+ private:
+  aos_mutex impl_;
+
+  friend class Condition;  // for access to impl_
+};
+
+// A class that locks a Mutex when constructed and unlocks it when destructed.
+// Designed to be used as a local variable so that
+// the mutex will be unlocked when the scope is exited.
+// This one immediately Dies if the previous owner died. This makes it a good
+// choice for mutexes that are only used within a single process, but NOT for
+// mutexes shared by multiple processes. For those, use IPCMutexLocker.
+class MutexLocker {
+ public:
+  explicit MutexLocker(Mutex *mutex) : mutex_(mutex) {
+    if (__builtin_expect(mutex_->Lock(), false)) {
+      ::aos::Die("previous owner of mutex %p died but it shouldn't be able to",
+                 this);
+    }
+  }
+  ~MutexLocker() {
+    mutex_->Unlock();
+  }
+
+ private:
+  Mutex *const mutex_;
+
+  DISALLOW_COPY_AND_ASSIGN(MutexLocker);
+};
+
+// A version of MutexLocker which reports the previous owner dying instead of
+// immediately LOG(FATAL)ing.
+class IPCMutexLocker {
+ public:
+  explicit IPCMutexLocker(Mutex *mutex)
+      : mutex_(mutex), owner_died_(mutex_->Lock()) {}
+  ~IPCMutexLocker() {
+    if (__builtin_expect(!owner_died_checked_, false)) {
+      ::aos::Die("nobody checked if the previous owner of mutex %p died", this);
+    }
+    mutex_->Unlock();
+  }
+
+  // Whether or not the previous owner died. If this is not called at least
+  // once, the destructor will ::aos::Die.
+  __attribute__((warn_unused_result)) bool owner_died() {
+    owner_died_checked_ = true;
+    return __builtin_expect(owner_died_, false);
+  }
+
+ private:
+  Mutex *const mutex_;
+  const bool owner_died_;
+  bool owner_died_checked_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCMutexLocker);
+};
+
+// A version of IPCMutexLocker which only locks (and unlocks) the mutex if the
+// current task does not already hold it.
+class IPCRecursiveMutexLocker {
+ public:
+  explicit IPCRecursiveMutexLocker(Mutex *mutex)
+      : mutex_(mutex),
+        locked_(!mutex_->OwnedBySelf()),
+        owner_died_(locked_ ? mutex_->Lock() : false) {}
+  ~IPCRecursiveMutexLocker() {
+    if (__builtin_expect(!owner_died_checked_, false)) {
+      ::aos::Die("nobody checked if the previous owner of mutex %p died", this);
+    }
+    if (locked_) mutex_->Unlock();
+  }
+
+  // Whether or not the previous owner died. If this is not called at least
+  // once, the destructor will ::aos::Die.
+  __attribute__((warn_unused_result)) bool owner_died() {
+    owner_died_checked_ = true;
+    return __builtin_expect(owner_died_, false);
+  }
+
+ private:
+  Mutex *const mutex_;
+  const bool locked_, owner_died_;
+  bool owner_died_checked_ = false;
+
+  DISALLOW_COPY_AND_ASSIGN(IPCRecursiveMutexLocker);
+};
+
+}  // namespace aos
+
+#endif  // AOS_MUTEX_H_
diff --git a/aos/mutex/mutex_test.cc b/aos/mutex/mutex_test.cc
new file mode 100644
index 0000000..8e3daac
--- /dev/null
+++ b/aos/mutex/mutex_test.cc
@@ -0,0 +1,373 @@
+#include "aos/mutex/mutex.h"
+
+#include <math.h>
+#include <pthread.h>
+#include <sched.h>
+
+#include <chrono>
+#include <thread>
+
+#include "gtest/gtest.h"
+
+#include "aos/die.h"
+#include "aos/time/time.h"
+#include "aos/util/death_test_log_implementation.h"
+#include "aos/util/thread.h"
+#include "aos/linux_code/ipc_lib/aos_sync.h"
+#include "aos/linux_code/ipc_lib/core_lib.h"
+#include "aos/testing/test_logging.h"
+#include "aos/testing/test_shm.h"
+
+namespace aos {
+namespace testing {
+
+namespace chrono = ::std::chrono;
+namespace this_thread = ::std::this_thread;
+
+class MutexTest : public ::testing::Test {
+ public:
+  Mutex test_mutex_;
+
+ protected:
+  void SetUp() override {
+    ::aos::testing::EnableTestLogging();
+    SetDieTestMode(true);
+  }
+};
+
+typedef MutexTest MutexDeathTest;
+typedef MutexTest MutexLockerTest;
+typedef MutexTest MutexLockerDeathTest;
+typedef MutexTest IPCMutexLockerTest;
+typedef MutexTest IPCMutexLockerDeathTest;
+typedef MutexTest IPCRecursiveMutexLockerTest;
+
+TEST_F(MutexTest, TryLock) {
+  EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
+  EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+TEST_F(MutexTest, Lock) {
+  ASSERT_FALSE(test_mutex_.Lock());
+  EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+TEST_F(MutexTest, Unlock) {
+  ASSERT_FALSE(test_mutex_.Lock());
+  EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+  test_mutex_.Unlock();
+  EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+// Sees what happens with multiple unlocks.
+TEST_F(MutexDeathTest, RepeatUnlock) {
+  logging::Init();
+  ASSERT_FALSE(test_mutex_.Lock());
+  test_mutex_.Unlock();
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        test_mutex_.Unlock();
+      },
+      ".*multiple unlock.*");
+}
+
+// Sees what happens if you unlock without ever locking (or unlocking) it.
+TEST_F(MutexDeathTest, NeverLock) {
+  logging::Init();
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        test_mutex_.Unlock();
+      },
+      ".*multiple unlock.*");
+}
+
+// Tests that locking a mutex multiple times from the same thread fails nicely.
+TEST_F(MutexDeathTest, RepeatLock) {
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        ASSERT_FALSE(test_mutex_.Lock());
+        ASSERT_FALSE(test_mutex_.Lock());
+      },
+      ".*multiple lock.*");
+}
+
+// Tests that Lock behaves correctly when the previous owner exits with the lock
+// held (which is the same as dying any other way).
+TEST_F(MutexTest, OwnerDiedDeathLock) {
+  testing::TestSharedMemory my_shm;
+  Mutex *mutex =
+      static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
+  new (mutex) Mutex();
+
+  util::FunctionThread::RunInOtherThread([&]() {
+    ASSERT_FALSE(mutex->Lock());
+  });
+  EXPECT_TRUE(mutex->Lock());
+
+  mutex->Unlock();
+  mutex->~Mutex();
+}
+
+// Tests that TryLock behaves correctly when the previous owner dies.
+TEST_F(MutexTest, OwnerDiedDeathTryLock) {
+  testing::TestSharedMemory my_shm;
+  Mutex *mutex =
+      static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
+  new (mutex) Mutex();
+
+  util::FunctionThread::RunInOtherThread([&]() {
+    ASSERT_FALSE(mutex->Lock());
+  });
+  EXPECT_EQ(Mutex::State::kOwnerDied, mutex->TryLock());
+
+  mutex->Unlock();
+  mutex->~Mutex();
+}
+
+// TODO(brians): Test owner dying by being SIGKILLed and SIGTERMed.
+
+// This sequence of mutex operations used to mess up the robust list and cause
+// one of the mutexes to not get owner-died like it should.
+TEST_F(MutexTest, DontCorruptRobustList) {
+  // I think this was the allocator lock in the original failure.
+  Mutex mutex1;
+  // This one should get owner-died afterwards (iff the kernel accepts the
+  // robust list and uses it). I think it was the task_death_notification lock
+  // in the original failure.
+  Mutex mutex2;
+
+  util::FunctionThread::RunInOtherThread([&]() {
+    ASSERT_FALSE(mutex1.Lock());
+    ASSERT_FALSE(mutex2.Lock());
+    mutex1.Unlock();
+  });
+
+  EXPECT_EQ(Mutex::State::kLocked, mutex1.TryLock());
+  EXPECT_EQ(Mutex::State::kOwnerDied, mutex2.TryLock());
+
+  mutex1.Unlock();
+  mutex2.Unlock();
+}
+
+namespace {
+
+class AdderThread : public ::aos::util::Thread {
+ public:
+  AdderThread(int *counter, Mutex *mutex,
+              monotonic_clock::duration sleep_before_time,
+              monotonic_clock::duration sleep_after_time)
+      : counter_(counter),
+        mutex_(mutex),
+        sleep_before_time_(sleep_before_time),
+        sleep_after_time_(sleep_after_time) {}
+
+ private:
+  virtual void Run() override {
+    this_thread::sleep_for(sleep_before_time_);
+    MutexLocker locker(mutex_);
+    ++(*counter_);
+    this_thread::sleep_for(sleep_after_time_);
+  }
+
+  int *const counter_;
+  Mutex *const mutex_;
+  const monotonic_clock::duration sleep_before_time_, sleep_after_time_;
+};
+
+}  // namespace
+
+// Verifies that ThreadSanitizer understands that a contended mutex establishes
+// a happens-before relationship.
+TEST_F(MutexTest, ThreadSanitizerContended) {
+  int counter = 0;
+  AdderThread threads[2]{
+      {&counter, &test_mutex_, chrono::milliseconds(200),
+       chrono::milliseconds(0)},
+      {&counter, &test_mutex_, chrono::milliseconds(0),
+       chrono::milliseconds(0)},
+  };
+  for (auto &c : threads) {
+    c.Start();
+  }
+  for (auto &c : threads) {
+    c.WaitUntilDone();
+  }
+  EXPECT_EQ(2, counter);
+}
+
+// Verifiers that ThreadSanitizer understands how a mutex works.
+// For some reason this used to fail when the other tests didn't...
+// The loops make it fail more reliably when it's going to.
+TEST_F(MutexTest, ThreadSanitizerMutexLocker) {
+  for (int i = 0; i < 100; ++i) {
+    int counter = 0;
+    ::std::thread thread([&counter, this]() {
+      for (int i = 0; i < 300; ++i) {
+        MutexLocker locker(&test_mutex_);
+        ++counter;
+      }
+    });
+    for (int i = 0; i < 300; ++i) {
+      MutexLocker locker(&test_mutex_);
+      --counter;
+    }
+    thread.join();
+    EXPECT_EQ(0, counter);
+  }
+}
+
+// Verifies that ThreadSanitizer understands that an uncontended mutex
+// establishes a happens-before relationship.
+TEST_F(MutexTest, ThreadSanitizerUncontended) {
+  int counter = 0;
+  AdderThread threads[2]{
+      {&counter, &test_mutex_, chrono::milliseconds(0),
+       chrono::milliseconds(0)},
+      {&counter, &test_mutex_, chrono::milliseconds(200),
+       chrono::milliseconds(0)}, };
+  for (auto &c : threads) {
+    c.Start();
+  }
+  for (auto &c : threads) {
+    c.WaitUntilDone();
+  }
+  EXPECT_EQ(2, counter);
+}
+
+namespace {
+
+class LockerThread : public util::Thread {
+ public:
+  LockerThread(Mutex *mutex, bool lock, bool unlock)
+      : mutex_(mutex), lock_(lock), unlock_(unlock) {}
+
+ private:
+  virtual void Run() override {
+    if (lock_) ASSERT_FALSE(mutex_->Lock());
+    if (unlock_) mutex_->Unlock();
+  }
+
+  Mutex *const mutex_;
+  const bool lock_, unlock_;
+};
+
+}  // namespace
+
+// Makes sure that we don't SIGSEGV or something with multiple threads.
+TEST_F(MutexTest, MultiThreadedLock) {
+  LockerThread t(&test_mutex_, true, true);
+  t.Start();
+  ASSERT_FALSE(test_mutex_.Lock());
+  test_mutex_.Unlock();
+  t.Join();
+}
+
+TEST_F(MutexLockerTest, Basic) {
+  {
+    aos::MutexLocker locker(&test_mutex_);
+    EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+  }
+  EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+// Tests that MutexLocker behaves correctly when the previous owner dies.
+TEST_F(MutexLockerDeathTest, OwnerDied) {
+  testing::TestSharedMemory my_shm;
+  Mutex *mutex =
+      static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
+  new (mutex) Mutex();
+
+  util::FunctionThread::RunInOtherThread([&]() {
+    ASSERT_FALSE(mutex->Lock());
+  });
+  EXPECT_DEATH(
+      {
+        logging::AddImplementation(new util::DeathTestLogImplementation());
+        MutexLocker locker(mutex);
+      },
+      ".*previous owner of mutex [^ ]+ died.*");
+
+  mutex->~Mutex();
+}
+
+TEST_F(IPCMutexLockerTest, Basic) {
+  {
+    aos::IPCMutexLocker locker(&test_mutex_);
+    EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+    EXPECT_FALSE(locker.owner_died());
+  }
+  EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+// Tests what happens when the caller doesn't check if the previous owner died
+// with an IPCMutexLocker.
+TEST_F(IPCMutexLockerDeathTest, NoCheckOwnerDied) {
+  EXPECT_DEATH({ aos::IPCMutexLocker locker(&test_mutex_); },
+               "nobody checked if the previous owner of mutex [^ ]+ died.*");
+}
+
+TEST_F(IPCRecursiveMutexLockerTest, Basic) {
+  {
+    aos::IPCRecursiveMutexLocker locker(&test_mutex_);
+    EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+    EXPECT_FALSE(locker.owner_died());
+  }
+  EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+// Tests actually locking a mutex recursively with IPCRecursiveMutexLocker.
+TEST_F(IPCRecursiveMutexLockerTest, RecursiveLock) {
+  {
+    aos::IPCRecursiveMutexLocker locker(&test_mutex_);
+    EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+    {
+      aos::IPCRecursiveMutexLocker locker(&test_mutex_);
+      EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+      EXPECT_FALSE(locker.owner_died());
+    }
+    EXPECT_EQ(Mutex::State::kLockFailed, test_mutex_.TryLock());
+    EXPECT_FALSE(locker.owner_died());
+  }
+  EXPECT_EQ(Mutex::State::kLocked, test_mutex_.TryLock());
+
+  test_mutex_.Unlock();
+}
+
+// Tests that IPCMutexLocker behaves correctly when the previous owner dies.
+TEST_F(IPCMutexLockerTest, OwnerDied) {
+  testing::TestSharedMemory my_shm;
+  Mutex *mutex =
+      static_cast<Mutex *>(shm_malloc_aligned(sizeof(Mutex), alignof(Mutex)));
+  new (mutex) Mutex();
+
+  util::FunctionThread::RunInOtherThread([&]() {
+    ASSERT_FALSE(mutex->Lock());
+  });
+  {
+    aos::IPCMutexLocker locker(mutex);
+    EXPECT_EQ(Mutex::State::kLockFailed, mutex->TryLock());
+    EXPECT_TRUE(locker.owner_died());
+  }
+  EXPECT_EQ(Mutex::State::kLocked, mutex->TryLock());
+
+  mutex->Unlock();
+  mutex->~Mutex();
+}
+
+}  // namespace testing
+}  // namespace aos