Clean up Mutex a little and add the missing pieces for Mac OS.

This -- as you'd expect, given that we're fine on bionic and glibc --
didn't find any bugs. But it's another step towards completeness and
lets me rule out Mac pthread_mutex_t weirdness as a potential cause of
our Mac dex2oat crashes.

Change-Id: If3f4aacf8dbc7c7b9fd6b8932bc01616ccf86b47
diff --git a/src/mutex.cc b/src/mutex.cc
index 5a9df17..71b0ba8 100644
--- a/src/mutex.cc
+++ b/src/mutex.cc
@@ -27,6 +27,22 @@
 
 namespace art {
 
+// This works on Mac OS 10.7, but hasn't been tested on older releases.
+struct __attribute__((__may_alias__)) darwin_pthread_mutex_t {
+  uint32_t padding0[2];
+  uint32_t value;
+  uint32_t padding1[5];
+  uint64_t owner_tid;
+  // ...other stuff we don't care about.
+};
+
+struct __attribute__((__may_alias__)) glibc_pthread_mutex_t {
+  int lock;
+  unsigned int count;
+  int owner;
+  // ...other stuff we don't care about.
+};
+
 static inline void CheckSafeToLockOrUnlock(MutexRank rank, bool is_locking) {
   if (!kIsDebugBuild) {
     return;
@@ -95,28 +111,30 @@
   CHECK_MUTEX_CALL(pthread_mutex_unlock, (&mutex_));
 }
 
-pid_t Mutex::GetOwner() {
+#if !defined(NDEBUG)
+void Mutex::AssertHeld() {
+  DCHECK_EQ(GetOwner(), static_cast<uint64_t>(GetTid()));
+}
+
+void Mutex::AssertNotHeld() {
+  DCHECK_NE(GetOwner(), static_cast<uint64_t>(GetTid()));
+}
+#endif
+
+uint64_t Mutex::GetOwner() {
 #if defined(__BIONIC__)
-  return static_cast<pid_t>((mutex_.value >> 16) & 0xffff);
+  return static_cast<uint64_t>((mutex_.value >> 16) & 0xffff);
 #elif defined(__GLIBC__)
-  struct __attribute__((__may_alias__)) glibc_pthread_t {
-    int lock;
-    unsigned int count;
-    int owner;
-    // ...other stuff we don't care about.
-  };
-  return reinterpret_cast<glibc_pthread_t*>(&mutex_)->owner;
+  return reinterpret_cast<glibc_pthread_mutex_t*>(&mutex_)->owner;
 #elif defined(__APPLE__)
-  // We don't know a way to implement this for Mac OS.
-  return 0;
+  return reinterpret_cast<darwin_pthread_mutex_t*>(&mutex_)->owner_tid;
 #else
-  UNIMPLEMENTED(FATAL);
-  return 0;
+#error unsupported C library
 #endif
 }
 
 uint32_t Mutex::GetDepth() {
-  bool held = (GetOwner() == GetTid());
+  bool held = (GetOwner() == static_cast<uint64_t>(GetTid()));
   if (!held) {
     return 0;
   }
@@ -124,28 +142,17 @@
 #if defined(__BIONIC__)
   depth = static_cast<uint32_t>((mutex_.value >> 2) & 0x7ff) + 1;
 #elif defined(__GLIBC__)
-  struct __attribute__((__may_alias__)) glibc_pthread_t {
-    int lock;
-    unsigned int count;
-    int owner;
-    // ...other stuff we don't care about.
-  };
-  depth = reinterpret_cast<glibc_pthread_t*>(&mutex_)->count;
+  depth = reinterpret_cast<glibc_pthread_mutex_t*>(&mutex_)->count;
 #elif defined(__APPLE__)
-  // We don't know a way to implement this for Mac OS.
-  return 0;
+  darwin_pthread_mutex_t* darwin_mutex = reinterpret_cast<darwin_pthread_mutex_t*>(&mutex_);
+  depth = ((darwin_mutex->value >> 16) & 0xffff);
 #else
-  UNIMPLEMENTED(FATAL);
-  return 0;
+#error unsupported C library
 #endif
-  CHECK_NE(0U, depth) << "owner=" << GetOwner() << " tid=" << GetTid();
+  CHECK_NE(depth, 0U) << "owner=" << GetOwner() << " tid=" << GetTid();
   return depth;
 }
 
-pid_t Mutex::GetTid() {
-  return ::art::GetTid();
-}
-
 ConditionVariable::ConditionVariable(const std::string& name) : name_(name) {
   CHECK_MUTEX_CALL(pthread_cond_init, (&cond_, NULL));
 }
@@ -163,8 +170,8 @@
 }
 
 void ConditionVariable::Wait(Mutex& mutex) {
-  CheckSafeToWait(mutex.GetRank());
-  CHECK_MUTEX_CALL(pthread_cond_wait, (&cond_, mutex.GetImpl()));
+  CheckSafeToWait(mutex.rank_);
+  CHECK_MUTEX_CALL(pthread_cond_wait, (&cond_, &mutex.mutex_));
 }
 
 void ConditionVariable::TimedWait(Mutex& mutex, const timespec& ts) {
@@ -173,8 +180,8 @@
 #else
 #define TIMEDWAIT pthread_cond_timedwait
 #endif
-  CheckSafeToWait(mutex.GetRank());
-  int rc = TIMEDWAIT(&cond_, mutex.GetImpl(), &ts);
+  CheckSafeToWait(mutex.rank_);
+  int rc = TIMEDWAIT(&cond_, &mutex.mutex_, &ts);
   if (rc != 0 && rc != ETIMEDOUT) {
     errno = rc;
     PLOG(FATAL) << "TimedWait failed for " << name_;
diff --git a/src/mutex.h b/src/mutex.h
index 02d127f..b019f68 100644
--- a/src/mutex.h
+++ b/src/mutex.h
@@ -49,41 +49,24 @@
 
   void Unlock();
 
-  const char* GetName() {
-    return name_.c_str();
-  }
-
-  pthread_mutex_t* GetImpl() {
-    return &mutex_;
-  }
-
-  MutexRank GetRank() const {
-    return rank_;
-  }
-
-  void AssertHeld() {
-#if !defined(__APPLE__)
-    DCHECK_EQ(GetOwner(), GetTid());
+#if !defined(NDEBUG)
+  void AssertHeld();
+  void AssertNotHeld();
+#else
+  void AssertHeld() {}
+  void AssertNotHeld() {}
 #endif
-  }
 
-  void AssertNotHeld() {
-#if !defined(__APPLE__)
-    DCHECK_NE(GetOwner(), GetTid());
-#endif
-  }
-
-  pid_t GetOwner();
+  uint64_t GetOwner();
 
  private:
-  static pid_t GetTid();
-
   uint32_t GetDepth();
 
   pthread_mutex_t mutex_;
   std::string name_;
   MutexRank rank_;
 
+  friend class ConditionVariable;
   friend class MutexTester;
   DISALLOW_COPY_AND_ASSIGN(Mutex);
 };
diff --git a/src/mutex_test.cc b/src/mutex_test.cc
index b59b305..7c7189b 100644
--- a/src/mutex_test.cc
+++ b/src/mutex_test.cc
@@ -20,10 +20,16 @@
 
 namespace art {
 
-#if !defined(__APPLE__)
 struct MutexTester {
   static void AssertDepth(Mutex& mu, uint32_t expected_depth) {
     ASSERT_EQ(expected_depth, mu.GetDepth());
+
+    // This test is single-threaded, so we also know _who_ should hold the lock.
+    if (expected_depth == 0) {
+      mu.AssertNotHeld();
+    } else {
+      mu.AssertHeld();
+    }
   }
 };
 
@@ -70,6 +76,5 @@
   mu.Unlock();
   MutexTester::AssertDepth(mu, 0U);
 }
-#endif
 
 }  // namespace art
diff --git a/src/utils.cc b/src/utils.cc
index 190cf4a..01fdac2 100644
--- a/src/utils.cc
+++ b/src/utils.cc
@@ -40,6 +40,7 @@
 
 #if defined(__APPLE__)
 #include "AvailabilityMacros.h"
+#include <sys/syscall.h>
 #endif
 
 #if defined(__linux__)
@@ -50,8 +51,9 @@
 
 pid_t GetTid() {
 #if defined(__APPLE__)
-  // Mac OS doesn't have gettid(2).
-  return getpid();
+  // gettid(2) returns -1 on Darwin, but thread_selfid(2) works, and seems to be what their
+  // pthreads implementation uses.
+  return syscall(SYS_thread_selfid);
 #else
   // Neither bionic nor glibc exposes gettid(2).
   return syscall(__NR_gettid);