Skip to content

Commit 5b666cf

Browse files
committed
[libc++] Fix thread annotations on shared_mutex and shared_timed_mutex
Based on the comment in https://reviews.llvm.org/D54290#4418958, these attributes need to be on the top-level functions in order to work properly. Also, add tests. Fixes http://llvm.org/PR57035. Differential Revision: https://reviews.llvm.org/D154354
1 parent 619c6c0 commit 5b666cf

File tree

4 files changed

+206
-26
lines changed

4 files changed

+206
-26
lines changed

Diff for: libcxx/.clang-format

+1
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ AttributeMacros: [
5252
'_LIBCPP_STANDALONE_DEBUG',
5353
'_LIBCPP_TEMPLATE_DATA_VIS',
5454
'_LIBCPP_TEMPLATE_VIS',
55+
'_LIBCPP_THREAD_SAFETY_ANNOTATION',
5556
'_LIBCPP_USING_IF_EXISTS',
5657
'_LIBCPP_WEAK',
5758
]

Diff for: libcxx/include/shared_mutex

+44-26
Original file line numberDiff line numberDiff line change
@@ -153,8 +153,7 @@ _LIBCPP_PUSH_MACROS
153153

154154
_LIBCPP_BEGIN_NAMESPACE_STD
155155

156-
struct _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX
157-
_LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex")) __shared_mutex_base {
156+
struct _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX __shared_mutex_base {
158157
mutex __mut_;
159158
condition_variable __gate1_;
160159
condition_variable __gate2_;
@@ -170,21 +169,22 @@ _LIBCPP_THREAD_SAFETY_ANNOTATION(capability("shared_mutex")) __shared_mutex_base
170169
__shared_mutex_base& operator=(const __shared_mutex_base&) = delete;
171170

172171
// Exclusive ownership
173-
void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_capability()); // blocking
174-
bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_capability(true));
175-
void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_capability());
172+
void lock(); // blocking
173+
bool try_lock();
174+
void unlock();
176175

177176
// Shared ownership
178-
void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(acquire_shared_capability()); // blocking
179-
bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(try_acquire_shared_capability(true));
180-
void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(release_shared_capability());
177+
void lock_shared(); // blocking
178+
bool try_lock_shared();
179+
void unlock_shared();
181180

182181
// typedef implementation-defined native_handle_type; // See 30.2.3
183182
// native_handle_type native_handle(); // See 30.2.3
184183
};
185184

186185
# if _LIBCPP_STD_VER >= 17
187-
class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_mutex {
186+
class _LIBCPP_EXPORTED_FROM_ABI
187+
_LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(__capability__("shared_mutex")) shared_mutex {
188188
__shared_mutex_base __base_;
189189

190190
public:
@@ -195,21 +195,35 @@ public:
195195
shared_mutex& operator=(const shared_mutex&) = delete;
196196

197197
// Exclusive ownership
198-
_LIBCPP_HIDE_FROM_ABI void lock() { return __base_.lock(); }
199-
_LIBCPP_HIDE_FROM_ABI bool try_lock() { return __base_.try_lock(); }
200-
_LIBCPP_HIDE_FROM_ABI void unlock() { return __base_.unlock(); }
198+
_LIBCPP_HIDE_FROM_ABI void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__()) {
199+
return __base_.lock();
200+
}
201+
_LIBCPP_HIDE_FROM_ABI bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
202+
return __base_.try_lock();
203+
}
204+
_LIBCPP_HIDE_FROM_ABI void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__()) {
205+
return __base_.unlock();
206+
}
201207

202208
// Shared ownership
203-
_LIBCPP_HIDE_FROM_ABI void lock_shared() { return __base_.lock_shared(); }
204-
_LIBCPP_HIDE_FROM_ABI bool try_lock_shared() { return __base_.try_lock_shared(); }
205-
_LIBCPP_HIDE_FROM_ABI void unlock_shared() { return __base_.unlock_shared(); }
209+
_LIBCPP_HIDE_FROM_ABI void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__()) {
210+
return __base_.lock_shared();
211+
}
212+
_LIBCPP_HIDE_FROM_ABI bool try_lock_shared()
213+
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
214+
return __base_.try_lock_shared();
215+
}
216+
_LIBCPP_HIDE_FROM_ABI void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__()) {
217+
return __base_.unlock_shared();
218+
}
206219

207220
// typedef __shared_mutex_base::native_handle_type native_handle_type;
208221
// _LIBCPP_HIDE_FROM_ABI native_handle_type native_handle() { return __base::unlock_shared(); }
209222
};
210223
# endif
211224

212-
class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX shared_timed_mutex {
225+
class _LIBCPP_EXPORTED_FROM_ABI _LIBCPP_AVAILABILITY_SHARED_MUTEX _LIBCPP_THREAD_SAFETY_ANNOTATION(
226+
__capability__("shared_timed_mutex")) shared_timed_mutex {
213227
__shared_mutex_base __base_;
214228

215229
public:
@@ -220,28 +234,32 @@ public:
220234
shared_timed_mutex& operator=(const shared_timed_mutex&) = delete;
221235

222236
// Exclusive ownership
223-
void lock();
224-
bool try_lock();
237+
void lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_capability__());
238+
bool try_lock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
225239
template <class _Rep, class _Period>
226-
_LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time) {
240+
_LIBCPP_HIDE_FROM_ABI bool try_lock_for(const chrono::duration<_Rep, _Period>& __rel_time)
241+
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true)) {
227242
return try_lock_until(chrono::steady_clock::now() + __rel_time);
228243
}
229244
template <class _Clock, class _Duration>
230245
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
231-
try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
232-
void unlock();
246+
try_lock_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
247+
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_capability__(true));
248+
void unlock() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_capability__());
233249

234250
// Shared ownership
235-
void lock_shared();
236-
bool try_lock_shared();
251+
void lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__acquire_shared_capability__());
252+
bool try_lock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
237253
template <class _Rep, class _Period>
238-
_LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time) {
254+
_LIBCPP_HIDE_FROM_ABI bool try_lock_shared_for(const chrono::duration<_Rep, _Period>& __rel_time)
255+
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true)) {
239256
return try_lock_shared_until(chrono::steady_clock::now() + __rel_time);
240257
}
241258
template <class _Clock, class _Duration>
242259
_LIBCPP_METHOD_TEMPLATE_IMPLICIT_INSTANTIATION_VIS bool
243-
try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time);
244-
void unlock_shared();
260+
try_lock_shared_until(const chrono::time_point<_Clock, _Duration>& __abs_time)
261+
_LIBCPP_THREAD_SAFETY_ANNOTATION(__try_acquire_shared_capability__(true));
262+
void unlock_shared() _LIBCPP_THREAD_SAFETY_ANNOTATION(__release_shared_capability__());
245263
};
246264

247265
template <class _Clock, class _Duration>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11, c++14
10+
// UNSUPPORTED: no-threads
11+
// UNSUPPORTED: availability-shared_mutex-missing
12+
// REQUIRES: thread-safety
13+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
14+
15+
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
16+
// the processing goes awry preventing the definition of the types.
17+
// XFAIL: msvc
18+
19+
// <shared_mutex>
20+
//
21+
// class shared_mutex;
22+
//
23+
// void lock();
24+
// bool try_lock();
25+
// void unlock();
26+
//
27+
// void lock_shared();
28+
// bool try_lock_shared();
29+
// void unlock_shared();
30+
31+
#include <shared_mutex>
32+
33+
std::shared_mutex m;
34+
int data __attribute__((guarded_by(m))) = 0;
35+
void read(int);
36+
37+
void f() {
38+
// Exclusive locking
39+
{
40+
m.lock();
41+
++data; // ok
42+
m.unlock();
43+
}
44+
{
45+
if (m.try_lock()) {
46+
++data; // ok
47+
m.unlock();
48+
}
49+
}
50+
51+
// Shared locking
52+
{
53+
m.lock_shared();
54+
read(data); // ok
55+
++data; // expected-error {{writing variable 'data' requires holding shared_mutex 'm' exclusively}}
56+
m.unlock_shared();
57+
}
58+
{
59+
if (m.try_lock_shared()) {
60+
read(data); // ok
61+
++data; // expected-error {{writing variable 'data' requires holding shared_mutex 'm' exclusively}}
62+
m.unlock_shared();
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
// UNSUPPORTED: c++03, c++11
10+
// UNSUPPORTED: no-threads
11+
// UNSUPPORTED: availability-shared_mutex-missing
12+
// REQUIRES: thread-safety
13+
// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_THREAD_SAFETY_ANNOTATIONS
14+
15+
// On Windows Clang bugs out when both __declspec and __attribute__ are present,
16+
// the processing goes awry preventing the definition of the types.
17+
// XFAIL: msvc
18+
19+
// <shared_mutex>
20+
//
21+
// class shared_timed_mutex;
22+
//
23+
// void lock();
24+
// bool try_lock();
25+
// bool try_lock_for(const std::chrono::duration<Rep, Period>&);
26+
// bool try_lock_until(const std::chrono::time_point<Clock, Duration>&);
27+
// void unlock();
28+
//
29+
// void lock_shared();
30+
// bool try_lock_shared();
31+
// bool try_lock_shared_for(const std::chrono::duration<Rep, Period>&);
32+
// bool try_lock_shared_until(const std::chrono::time_point<Clock, Duration>&);
33+
// void unlock_shared();
34+
35+
#include <chrono>
36+
#include <shared_mutex>
37+
38+
std::shared_timed_mutex m;
39+
int data __attribute__((guarded_by(m))) = 0;
40+
void read(int);
41+
42+
void f(std::chrono::time_point<std::chrono::steady_clock> tp, std::chrono::milliseconds d) {
43+
// Exclusive locking
44+
{
45+
m.lock();
46+
++data; // ok
47+
m.unlock();
48+
}
49+
{
50+
if (m.try_lock()) {
51+
++data; // ok
52+
m.unlock();
53+
}
54+
}
55+
{
56+
if (m.try_lock_for(d)) {
57+
++data; // ok
58+
m.unlock();
59+
}
60+
}
61+
{
62+
if (m.try_lock_until(tp)) {
63+
++data; // ok
64+
m.unlock();
65+
}
66+
}
67+
68+
// Shared locking
69+
{
70+
m.lock_shared();
71+
read(data); // ok
72+
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
73+
m.unlock_shared();
74+
}
75+
{
76+
if (m.try_lock_shared()) {
77+
read(data); // ok
78+
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
79+
m.unlock_shared();
80+
}
81+
}
82+
{
83+
if (m.try_lock_shared_for(d)) {
84+
read(data); // ok
85+
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
86+
m.unlock_shared();
87+
}
88+
}
89+
{
90+
if (m.try_lock_shared_until(tp)) {
91+
read(data); // ok
92+
++data; // expected-error {{writing variable 'data' requires holding shared_timed_mutex 'm' exclusively}}
93+
m.unlock_shared();
94+
}
95+
}
96+
}

0 commit comments

Comments
 (0)