Add a new LIBUNWIND_WEAK_PTHREAD Cmake option to force
calls into the pthread library use weak symbols.

This option allows libpthread to be a weak dependency rather
than a hard one.

Differential Revision: https://reviews.llvm.org/D60285

git-svn-id: https://llvm.org/svn/llvm-project/libunwind/trunk@360610 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/CMakeLists.txt b/CMakeLists.txt
index debc847..8d48167 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -134,6 +134,7 @@
 option(LIBUNWIND_ENABLE_CROSS_UNWINDING "Enable cross-platform unwinding support." OFF)
 option(LIBUNWIND_ENABLE_ARM_WMMX "Enable unwinding support for ARM WMMX registers." OFF)
 option(LIBUNWIND_ENABLE_THREADS "Build libunwind with threading support." ON)
+option(LIBUNWIND_WEAK_PTHREAD_LIB "Use weak references to refer to pthread functions." OFF)
 option(LIBUNWIND_USE_COMPILER_RT "Use compiler-rt instead of libgcc" OFF)
 option(LIBUNWIND_INCLUDE_DOCS "Build the libunwind documentation." ${LLVM_INCLUDE_DOCS})
 
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 191f167..9ca773b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -67,6 +67,7 @@
 unwind_append_if(libraries LIBUNWIND_HAS_DL_LIB dl)
 if (LIBUNWIND_ENABLE_THREADS)
   unwind_append_if(libraries LIBUNWIND_HAS_PTHREAD_LIB pthread)
+  unwind_append_if(LIBUNWIND_COMPILE_FLAGS LIBUNWIND_WEAK_PTHREAD_LIB -DLIBUNWIND_USE_WEAK_PTHREAD=1)
 endif()
 
 # Setup flags.
diff --git a/src/RWMutex.hpp b/src/RWMutex.hpp
index 92c8db3..7a08bb2 100644
--- a/src/RWMutex.hpp
+++ b/src/RWMutex.hpp
@@ -56,11 +56,11 @@
   SRWLOCK _lock = SRWLOCK_INIT;
 };
 
-#else
+#elif !defined(LIBUNWIND_USE_WEAK_PTHREAD)
 
 class _LIBUNWIND_HIDDEN RWMutex {
 public:
-  bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0; }
+  bool lock_shared() { return pthread_rwlock_rdlock(&_lock) == 0;  }
   bool unlock_shared() { return pthread_rwlock_unlock(&_lock) == 0; }
   bool lock() { return pthread_rwlock_wrlock(&_lock) == 0; }
   bool unlock() { return pthread_rwlock_unlock(&_lock) == 0; }
@@ -69,6 +69,41 @@
   pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
 };
 
+#else
+
+extern "C" int __attribute__((weak))
+pthread_create(pthread_t *thread, const pthread_attr_t *attr,
+               void *(*start_routine)(void *), void *arg);
+extern "C" int __attribute__((weak))
+pthread_rwlock_rdlock(pthread_rwlock_t *lock);
+extern "C" int __attribute__((weak))
+pthread_rwlock_wrlock(pthread_rwlock_t *lock);
+extern "C" int __attribute__((weak))
+pthread_rwlock_unlock(pthread_rwlock_t *lock);
+
+// Calls to the locking functions are gated on pthread_create, and not the
+// functions themselves, because the data structure should only be locked if
+// another thread has been created. This is what similar libraries do.
+
+class _LIBUNWIND_HIDDEN RWMutex {
+public:
+  bool lock_shared() {
+    return !pthread_create || (pthread_rwlock_rdlock(&_lock) == 0);
+  }
+  bool unlock_shared() {
+    return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0);
+  }
+  bool lock() {
+    return !pthread_create || (pthread_rwlock_wrlock(&_lock) == 0);
+  }
+  bool unlock() {
+    return !pthread_create || (pthread_rwlock_unlock(&_lock) == 0);
+  }
+
+private:
+  pthread_rwlock_t _lock = PTHREAD_RWLOCK_INITIALIZER;
+};
+
 #endif
 
 } // namespace libunwind