1 | // Copyright 2020 The Marl Authors. |
2 | // |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | // you may not use this file except in compliance with the License. |
5 | // You may obtain a copy of the License at |
6 | // |
7 | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | // |
9 | // Unless required by applicable law or agreed to in writing, software |
10 | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | // See the License for the specific language governing permissions and |
13 | // limitations under the License. |
14 | |
15 | // Wrappers around std::mutex and std::unique_lock that provide clang's |
16 | // Thread Safety Analysis annotations. |
17 | // See: https://clang.llvm.org/docs/ThreadSafetyAnalysis.html |
18 | |
19 | #ifndef marl_mutex_h |
20 | #define marl_mutex_h |
21 | |
22 | #include "export.h" |
23 | #include "tsa.h" |
24 | |
25 | #include <condition_variable> |
26 | #include <mutex> |
27 | |
28 | namespace marl { |
29 | |
30 | // mutex is a wrapper around std::mutex that offers Thread Safety Analysis |
31 | // annotations. |
32 | // mutex also holds methods for performing std::condition_variable::wait() calls |
33 | // as these require a std::unique_lock<> which are unsupported by the TSA. |
34 | class CAPABILITY("mutex" ) mutex { |
35 | public: |
36 | MARL_NO_EXPORT inline void lock() ACQUIRE() { _.lock(); } |
37 | |
38 | MARL_NO_EXPORT inline void unlock() RELEASE() { _.unlock(); } |
39 | |
40 | MARL_NO_EXPORT inline bool try_lock() TRY_ACQUIRE(true) { |
41 | return _.try_lock(); |
42 | } |
43 | |
44 | // wait_locked calls cv.wait() on this already locked mutex. |
45 | template <typename Predicate> |
46 | MARL_NO_EXPORT inline void wait_locked(std::condition_variable& cv, |
47 | Predicate&& p) REQUIRES(this) { |
48 | std::unique_lock<std::mutex> lock(_, std::adopt_lock); |
49 | cv.wait(lock, std::forward<Predicate>(p)); |
50 | lock.release(); // Keep lock held. |
51 | } |
52 | |
53 | // wait_until_locked calls cv.wait() on this already locked mutex. |
54 | template <typename Predicate, typename Time> |
55 | MARL_NO_EXPORT inline bool wait_until_locked(std::condition_variable& cv, |
56 | Time&& time, |
57 | Predicate&& p) REQUIRES(this) { |
58 | std::unique_lock<std::mutex> lock(_, std::adopt_lock); |
59 | auto res = cv.wait_until(lock, std::forward<Time>(time), |
60 | std::forward<Predicate>(p)); |
61 | lock.release(); // Keep lock held. |
62 | return res; |
63 | } |
64 | |
65 | private: |
66 | friend class lock; |
67 | std::mutex _; |
68 | }; |
69 | |
70 | // lock is a RAII lock helper that offers Thread Safety Analysis annotations. |
71 | // lock also holds methods for performing std::condition_variable::wait() |
72 | // calls as these require a std::unique_lock<> which are unsupported by the TSA. |
73 | class SCOPED_CAPABILITY lock { |
74 | public: |
75 | inline lock(mutex& m) ACQUIRE(m) : _(m._) {} |
76 | inline ~lock() RELEASE() {} |
77 | |
78 | // wait calls cv.wait() on this lock. |
79 | template <typename Predicate> |
80 | inline void wait(std::condition_variable& cv, Predicate&& p) { |
81 | cv.wait(_, std::forward<Predicate>(p)); |
82 | } |
83 | |
84 | // wait_until calls cv.wait() on this lock. |
85 | template <typename Predicate, typename Time> |
86 | inline bool wait_until(std::condition_variable& cv, |
87 | Time&& time, |
88 | Predicate&& p) { |
89 | return cv.wait_until(_, std::forward<Time>(time), |
90 | std::forward<Predicate>(p)); |
91 | } |
92 | |
93 | inline bool owns_lock() const { return _.owns_lock(); } |
94 | |
95 | // lock_no_tsa locks the mutex outside of the visiblity of the thread |
96 | // safety analysis. Use with caution. |
97 | inline void lock_no_tsa() { _.lock(); } |
98 | |
99 | // unlock_no_tsa unlocks the mutex outside of the visiblity of the thread |
100 | // safety analysis. Use with caution. |
101 | inline void unlock_no_tsa() { _.unlock(); } |
102 | |
103 | private: |
104 | std::unique_lock<std::mutex> _; |
105 | }; |
106 | |
107 | } // namespace marl |
108 | |
109 | #endif // marl_mutex_h |
110 | |