jamesr updated this revision to Diff 50481.
jamesr added a comment.

This patch guards the new annotations with 
_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS and adds a number of tests to check 
that the annotations produce errors when the annotations are enabled that code 
violates the thread safety rules, that correct code does not produce errors, 
and that code that does not enable the annotations does not produce errors even 
in code that the thread-safety feature in Clang does not understand.

The feature guard is state in the positive as opposed to the negative as the 
annotations may be incompatible with correct code in some situations.


http://reviews.llvm.org/D14731

Files:
  include/__config
  include/__mutex_base
  test/libcxx/test/format.py
  
test/libcxx/thread/thread.mutex/thread_safety_access_guarded_without_lock.fail.cpp
  test/libcxx/thread/thread.mutex/thread_safety_annotations_not_enabled.cpp
  
test/libcxx/thread/thread.mutex/thread_safety_call_requires_capability_without_having.fail.cpp
  test/libcxx/thread/thread.mutex/thread_safety_lock_guard.cpp
  test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.cpp
  test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp
  test/libcxx/thread/thread.mutex/thread_safety_requires_capability.cpp

Index: test/libcxx/thread/thread.mutex/thread_safety_requires_capability.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_requires_capability.cpp
@@ -0,0 +1,22 @@
+#if !defined(__clang__) || !__has_attribute(acquire_capability)
+// This test is only meaningful on versions of clang that understand thread
+// safety annotations.
+
+#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+
+#include <mutex>
+
+std::mutex m;
+int foo __attribute__((guarded_by(m)));
+
+void increment() __attribute__((requires_capability(m))) {
+  foo++;
+}
+
+int main() {
+  m.lock();
+  increment();
+  m.unlock();
+}
+
+#endif
Index: test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_missing_unlock.fail.cpp
@@ -0,0 +1,15 @@
+#if !defined(__clang__) || !__has_attribute(acquire_capability)
+// This test is only meaningful on versions of clang that understand thread
+// safety annotations.
+#error Test only supported on clang versions that support the acquire_capability annotation
+#endif
+
+#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+
+#include <mutex>
+
+std::mutex m;
+
+int main() {
+  m.lock();
+} // expected-error {{mutex 'm' is still held at the end of function}}
Index: test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.cpp
@@ -0,0 +1,18 @@
+#if !defined(__clang__) || !__has_attribute(acquire_capability)
+// This test is only meaningful on versions of clang that understand thread
+// safety annotations.
+
+#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+
+#include <mutex>
+
+std::mutex m;
+int foo __attribute__((guarded_by(m)));
+
+int main() {
+  m.lock();
+  foo++;
+  m.unlock();
+}
+
+#endif
Index: test/libcxx/thread/thread.mutex/thread_safety_lock_guard.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_lock_guard.cpp
@@ -0,0 +1,17 @@
+#if !defined(__clang__) || !__has_attribute(acquire_capability)
+// This test is only meaningful on versions of clang that understand thread
+// safety annotations.
+
+#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+
+#include <mutex>
+
+std::mutex m;
+int foo __attribute__((guarded_by(m)));
+
+int main() {
+  std::lock_guard<std::mutex> lock(m);
+  foo++;
+}
+
+#endif
Index: test/libcxx/thread/thread.mutex/thread_safety_call_requires_capability_without_having.fail.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_call_requires_capability_without_having.fail.cpp
@@ -0,0 +1,20 @@
+#if !defined(__clang__) || !__has_attribute(acquire_capability)
+// This test is only meaningful on versions of clang that understand thread
+// safety annotations.
+#error Test only supported on clang versions that support the acquire_capability annotation
+#endif
+
+#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+
+#include <mutex>
+
+std::mutex m;
+int foo __attribute__((guarded_by(m)));
+
+void increment() __attribute__((requires_capability(m))) {
+  foo++;
+}
+
+int main() {
+  increment();  // expected-error{{calling function 'increment' requires holding mutex 'm' exclusively}}
+}
Index: test/libcxx/thread/thread.mutex/thread_safety_annotations_not_enabled.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_annotations_not_enabled.cpp
@@ -0,0 +1,13 @@
+// This test does not define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS so it
+// should compile without any warnings or errors even though this pattern is not
+// understood by the thread safety annotations.
+
+#include <mutex>
+
+int main() {
+  std::mutex m;
+  m.lock();
+  {
+    std::unique_lock<std::mutex> g(m, std::adopt_lock);
+  }
+}
Index: test/libcxx/thread/thread.mutex/thread_safety_access_guarded_without_lock.fail.cpp
===================================================================
--- /dev/null
+++ test/libcxx/thread/thread.mutex/thread_safety_access_guarded_without_lock.fail.cpp
@@ -0,0 +1,16 @@
+#if !defined(__clang__) || !__has_attribute(acquire_capability)
+// This test is only meaningful on versions of clang that understand thread
+// safety annotations.
+#error Test only supported on clang versions that support the acquire_capability annotation
+#endif
+
+#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
+
+#include <mutex>
+
+std::mutex m;
+int foo __attribute__((guarded_by(m)));
+
+int main() {
+  foo++;  // expected-error{{writing variable 'foo' requires holding mutex 'm' exclusively}}
+}
Index: test/libcxx/test/format.py
===================================================================
--- test/libcxx/test/format.py
+++ test/libcxx/test/format.py
@@ -167,7 +167,7 @@
         # when using Clang.
         extra_flags = []
         if self.cxx.type != 'gcc':
-            extra_flags += ['-fsyntax-only']
+            extra_flags += ['-fsyntax-only', '-Werror=thread-safety']
         if use_verify:
             extra_flags += ['-Xclang', '-verify',
                             '-Xclang', '-verify-ignore-unexpected=note']
Index: include/__mutex_base
===================================================================
--- include/__mutex_base
+++ include/__mutex_base
@@ -26,7 +26,15 @@
 
 #ifndef _LIBCPP_HAS_NO_THREADS
 
-class _LIBCPP_TYPE_VIS mutex
+#ifndef _LIBCPP_THREAD_SAFETY_ANNOTATION
+#  ifdef _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
+#    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x) __attribute__((x))
+#  else
+#    define _LIBCPP_THREAD_SAFETY_ANNOTATION(x)
+#  endif
+#endif  // _LIBCPP_THREAD_SAFETY_ANNOTATION
+
+class _LIBCPP_TYPE_VIS _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("mutex")) mutex
 {
     pthread_mutex_t __m_;
 
@@ -44,9 +52,9 @@
     mutex& operator=(const mutex&);// = delete;
 
 public:
-    void lock();
-    bool try_lock() _NOEXCEPT;
-    void unlock() _NOEXCEPT;
+    void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability());
+    bool try_lock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
+    void unlock() _NOEXCEPT _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
 
     typedef pthread_mutex_t* native_handle_type;
     _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() {return &__m_;}
@@ -71,7 +79,7 @@
 #endif
 
 template <class _Mutex>
-class _LIBCPP_TYPE_VIS_ONLY lock_guard
+class _LIBCPP_TYPE_VIS_ONLY _LIBCPP_THREAD_SAFETY_ANNOTATION(scoped_lockable) lock_guard
 {
 public:
     typedef _Mutex mutex_type;
@@ -81,13 +89,13 @@
 public:
 
     _LIBCPP_INLINE_VISIBILITY
-    explicit lock_guard(mutex_type& __m)
+    explicit lock_guard(mutex_type& __m) _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability(__m))
         : __m_(__m) {__m_.lock();}
     _LIBCPP_INLINE_VISIBILITY
-    lock_guard(mutex_type& __m, adopt_lock_t)
+    lock_guard(mutex_type& __m, adopt_lock_t) _LIBCPP_THREAD_SAFETY_ANNOTATION(requires_capability(__m))
         : __m_(__m) {}
     _LIBCPP_INLINE_VISIBILITY
-    ~lock_guard() {__m_.unlock();}
+    ~lock_guard() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) {__m_.unlock();}
 
 private:
     lock_guard(lock_guard const&);// = delete;
Index: include/__config
===================================================================
--- include/__config
+++ include/__config
@@ -859,6 +859,11 @@
 #endif
 #endif
 
+#if (defined(_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS) && defined(__clang__) \
+      && __has_attribute(acquire_capability))
+#define _LIBCPP_HAS_THREAD_SAFETY_ANNOTATIONS
+#endif
+
 #endif // __cplusplus
 
 #endif // _LIBCPP_CONFIG
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to