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 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 _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: test/libcxx/test/config.py =================================================================== --- test/libcxx/test/config.py +++ test/libcxx/test/config.py @@ -98,6 +98,7 @@ self.configure_cxx_library_root() self.configure_use_system_cxx_lib() self.configure_use_clang_verify() + self.configure_use_thread_safety() self.configure_execute_external() self.configure_ccache() self.configure_compile_flags() @@ -218,6 +219,14 @@ self.lit_config.note( "inferred use_clang_verify as: %r" % self.use_clang_verify) + def configure_use_thread_safety(self): + '''If set, run clang with -verify on failing tests.''' + has_thread_safety = self.cxx.hasCompileFlag('-Werror=thread-safety') + if has_thread_safety: + self.cxx.compile_flags += ['-Werror=thread-safety'] + self.config.available_features.add('thread-safety') + self.lit_config.note("enabling thread-safety annotations") + def configure_execute_external(self): # Choose between lit's internal shell pipeline runner and a real shell. # If LIT_USE_INTERNAL_SHELL is in the environment, we use that as the Index: test/libcxx/thread/thread.mutex/thread_safety_annotations_not_enabled.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/thread/thread.mutex/thread_safety_annotations_not_enabled.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// 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 + +int main() { + std::mutex m; + m.lock(); + { + std::unique_lock g(m, std::adopt_lock); + } +} Index: test/libcxx/thread/thread.mutex/thread_safety_lock_guard.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/thread/thread.mutex/thread_safety_lock_guard.pass.cpp @@ -0,0 +1,24 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: thread-safety + +// + +#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include + +std::mutex m; +int foo __attribute__((guarded_by(m))); + +int main() { + std::lock_guard lock(m); + foo++; +} Index: test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/thread/thread.mutex/thread_safety_lock_unlock.pass.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: thread-safety + +// + +#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include + +std::mutex m; +int foo __attribute__((guarded_by(m))); + +int main() { + m.lock(); + foo++; + m.unlock(); +} 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,22 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: thread-safety + +// + +#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include + +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_requires_capability.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/thread/thread.mutex/thread_safety_requires_capability.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: thread-safety + +// + +#define _LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include + +std::mutex m; +int foo __attribute__((guarded_by(m))); + +void increment() __attribute__((requires_capability(m))) { + foo++; +} + +int main() { + m.lock(); + increment(); + m.unlock(); +}