Index: libcxx/include/shared_mutex =================================================================== --- libcxx/include/shared_mutex +++ libcxx/include/shared_mutex @@ -144,7 +144,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD -struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex")) +struct _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base { mutex __mut_; @@ -162,14 +162,14 @@ __shared_mutex_base& operator=(const __shared_mutex_base&) = delete; // Exclusive ownership - void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking - bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true)); - void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()); + void lock(); // blocking + bool try_lock(); + void unlock(); // Shared ownership - void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking - bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true)); - void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability()); + void lock_shared(); // blocking + bool try_lock_shared(); + void unlock_shared(); // typedef implementation-defined native_handle_type; // See 30.2.3 // native_handle_type native_handle(); // See 30.2.3 @@ -177,7 +177,7 @@ #if _LIBCPP_STD_VER > 14 -class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex +class _LIBCPP_TYPE_VIS _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex")) shared_mutex { __shared_mutex_base __base; public: @@ -188,14 +188,14 @@ shared_mutex& operator=(const shared_mutex&) = delete; // Exclusive ownership - _LIBCPP_INLINE_VISIBILITY void lock() { return __base.lock(); } - _LIBCPP_INLINE_VISIBILITY bool try_lock() { return __base.try_lock(); } - _LIBCPP_INLINE_VISIBILITY void unlock() { return __base.unlock(); } + _LIBCPP_INLINE_VISIBILITY void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()) { return __base.lock(); } + _LIBCPP_INLINE_VISIBILITY bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true)) { return __base.try_lock(); } + _LIBCPP_INLINE_VISIBILITY void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability()) { return __base.unlock(); } // Shared ownership - _LIBCPP_INLINE_VISIBILITY void lock_shared() { return __base.lock_shared(); } - _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() { return __base.try_lock_shared(); } - _LIBCPP_INLINE_VISIBILITY void unlock_shared() { return __base.unlock_shared(); } + _LIBCPP_INLINE_VISIBILITY void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()) { return __base.lock_shared(); } + _LIBCPP_INLINE_VISIBILITY bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true)) { return __base.try_lock_shared(); } + _LIBCPP_INLINE_VISIBILITY void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability()) { return __base.unlock_shared(); } // typedef __shared_mutex_base::native_handle_type native_handle_type; // _LIBCPP_INLINE_VISIBILITY native_handle_type native_handle() { return __base::unlock_shared(); } Index: libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_annotations_not_enabled.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_annotations_not_enabled.pass.cpp @@ -0,0 +1,29 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: libcpp-has-no-threads + +// + +// 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 + +#include "test_macros.h" + +int main(int, char**) { + std::shared_mutex m; + m.lock(); + { + std::shared_lock g(m, std::adopt_lock); + } + + return 0; +} Index: libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_lock_unlock.pass.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_lock_unlock.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + +// UNSUPPORTED: libcpp-has-no-threads +// REQUIRES: thread-safety + +// + +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include + +#include "test_macros.h" + +std::shared_mutex m; +int foo __attribute__((guarded_by(m))); + +int main(int, char**) { + m.lock(); + foo++; + m.unlock(); + + m.lock_shared(); + (void)foo; + m.unlock_shared(); + + return 0; +} Index: libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_missing_unlock.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_missing_unlock.fail.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + +// UNSUPPORTED: libcpp-has-no-threads +// REQUIRES: thread-safety + +// + +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include + +std::shared_mutex m; + +int main(int, char**) { + m.lock(); + + return 0; +} // expected-error {{mutex 'm' is still held at the end of function}} Index: libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_missing_unlock_shared.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_missing_unlock_shared.fail.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + +// UNSUPPORTED: libcpp-has-no-threads +// REQUIRES: thread-safety + +// + +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include +#include + +std::shared_mutex m; + +void lock() { + m.lock_shared(); +} // expected-error {{mutex 'm' is still held at the end of function}} + +int main(int, char**) { + std::thread t1(lock); + std::thread t2(lock); + + t1.join(); + t2.join(); + + return 0; +} Index: libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_requires_capability.fail.cpp =================================================================== --- /dev/null +++ libcxx/test/libcxx/thread/thread.shared_mutex/thread_safety_requires_capability.fail.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// On Windows Clang bugs out when both __declspec and __attribute__ are present, +// the processing goes awry preventing the definition of the types. +// XFAIL: LIBCXX-WINDOWS-FIXME + +// UNSUPPORTED: libcpp-has-no-threads +// REQUIRES: thread-safety + +// + +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS + +#include +#include + +#include "test_macros.h" + +std::shared_mutex m; +int foo __attribute__((guarded_by(m))); + +void increment() __attribute__((requires_shared_capability(m))) { + foo++; // expected-error {{writing variable 'foo' requires holding shared_mutex 'm' exclusively}} +} + +void run() { + m.lock_shared(); + increment(); + m.unlock_shared(); +} + +int main(int, char**) { + std::thread t1(run); + std::thread t2(run); + + t1.join(); + t2.join(); + + return 0; +}