/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/include/lldb/Utility/Predicate.h
Line | Count | Source |
1 | | //===-- Predicate.h ---------------------------------------------*- C++ -*-===// |
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 | | #ifndef LLDB_UTILITY_PREDICATE_H |
10 | | #define LLDB_UTILITY_PREDICATE_H |
11 | | |
12 | | #include <cstdint> |
13 | | #include <ctime> |
14 | | |
15 | | #include <condition_variable> |
16 | | #include <mutex> |
17 | | #include <optional> |
18 | | |
19 | | #include "lldb/Utility/Timeout.h" |
20 | | #include "lldb/lldb-defines.h" |
21 | | |
22 | | //#define DB_PTHREAD_LOG_EVENTS |
23 | | |
24 | | /// Enumerations for broadcasting. |
25 | | namespace lldb_private { |
26 | | |
27 | | enum PredicateBroadcastType { |
28 | | eBroadcastNever, ///< No broadcast will be sent when the value is modified. |
29 | | eBroadcastAlways, ///< Always send a broadcast when the value is modified. |
30 | | eBroadcastOnChange ///< Only broadcast if the value changes when the value is |
31 | | /// modified. |
32 | | }; |
33 | | |
34 | | /// \class Predicate Predicate.h "lldb/Utility/Predicate.h" |
35 | | /// A C++ wrapper class for providing threaded access to a value of |
36 | | /// type T. |
37 | | /// |
38 | | /// A templatized class that provides multi-threaded access to a value |
39 | | /// of type T. Threads can efficiently wait for bits within T to be set |
40 | | /// or reset, or wait for T to be set to be equal/not equal to a |
41 | | /// specified values. |
42 | | template <class T> class Predicate { |
43 | | public: |
44 | | /// Default constructor. |
45 | | /// |
46 | | /// Initializes the mutex, condition and value with their default |
47 | | /// constructors. |
48 | | Predicate() : m_value() {} |
49 | | |
50 | | /// Construct with initial T value \a initial_value. |
51 | | /// |
52 | | /// Initializes the mutex and condition with their default |
53 | | /// constructors, and initializes the value with \a initial_value. |
54 | | /// |
55 | | /// \param[in] initial_value |
56 | | /// The initial value for our T object. |
57 | 13.2k | Predicate(T initial_value) : m_value(initial_value) {} lldb_private::Predicate<bool>::Predicate(bool) Line | Count | Source | 57 | 10.5k | Predicate(T initial_value) : m_value(initial_value) {} |
lldb_private::Predicate<unsigned int>::Predicate(unsigned int) Line | Count | Source | 57 | 2.67k | Predicate(T initial_value) : m_value(initial_value) {} |
|
58 | | |
59 | | /// Destructor. |
60 | | /// |
61 | | /// Destroy the condition, mutex, and T objects. |
62 | 13.1k | ~Predicate() = default; lldb_private::Predicate<bool>::~Predicate() Line | Count | Source | 62 | 10.5k | ~Predicate() = default; |
lldb_private::Predicate<unsigned int>::~Predicate() Line | Count | Source | 62 | 2.56k | ~Predicate() = default; |
|
63 | | |
64 | | /// Value get accessor. |
65 | | /// |
66 | | /// Copies the current \a m_value in a thread safe manor and returns |
67 | | /// the copied value. |
68 | | /// |
69 | | /// \return |
70 | | /// A copy of the current value. |
71 | 8.43k | T GetValue() const { |
72 | 8.43k | std::lock_guard<std::mutex> guard(m_mutex); |
73 | 8.43k | T value = m_value; |
74 | 8.43k | return value; |
75 | 8.43k | } lldb_private::Predicate<unsigned int>::GetValue() const Line | Count | Source | 71 | 8.43k | T GetValue() const { | 72 | 8.43k | std::lock_guard<std::mutex> guard(m_mutex); | 73 | 8.43k | T value = m_value; | 74 | 8.43k | return value; | 75 | 8.43k | } |
lldb_private::Predicate<bool>::GetValue() const Line | Count | Source | 71 | 7 | T GetValue() const { | 72 | 7 | std::lock_guard<std::mutex> guard(m_mutex); | 73 | 7 | T value = m_value; | 74 | 7 | return value; | 75 | 7 | } |
|
76 | | |
77 | | /// Value set accessor. |
78 | | /// |
79 | | /// Set the contained \a m_value to \a new_value in a thread safe |
80 | | /// way and broadcast if needed. |
81 | | /// |
82 | | /// \param[in] value |
83 | | /// The new value to set. |
84 | | /// |
85 | | /// \param[in] broadcast_type |
86 | | /// A value indicating when and if to broadcast. See the |
87 | | /// PredicateBroadcastType enumeration for details. |
88 | | /// |
89 | | /// \see Predicate::Broadcast() |
90 | 30.3k | void SetValue(T value, PredicateBroadcastType broadcast_type) { |
91 | 30.3k | std::lock_guard<std::mutex> guard(m_mutex); |
92 | | #ifdef DB_PTHREAD_LOG_EVENTS |
93 | | printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, |
94 | | broadcast_type); |
95 | | #endif |
96 | 30.3k | const T old_value = m_value; |
97 | 30.3k | m_value = value; |
98 | | |
99 | 30.3k | Broadcast(old_value, broadcast_type); |
100 | 30.3k | } lldb_private::Predicate<bool>::SetValue(bool, lldb_private::PredicateBroadcastType) Line | Count | Source | 90 | 22.7k | void SetValue(T value, PredicateBroadcastType broadcast_type) { | 91 | 22.7k | std::lock_guard<std::mutex> guard(m_mutex); | 92 | | #ifdef DB_PTHREAD_LOG_EVENTS | 93 | | printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, | 94 | | broadcast_type); | 95 | | #endif | 96 | 22.7k | const T old_value = m_value; | 97 | 22.7k | m_value = value; | 98 | | | 99 | 22.7k | Broadcast(old_value, broadcast_type); | 100 | 22.7k | } |
lldb_private::Predicate<unsigned int>::SetValue(unsigned int, lldb_private::PredicateBroadcastType) Line | Count | Source | 90 | 7.64k | void SetValue(T value, PredicateBroadcastType broadcast_type) { | 91 | 7.64k | std::lock_guard<std::mutex> guard(m_mutex); | 92 | | #ifdef DB_PTHREAD_LOG_EVENTS | 93 | | printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, | 94 | | broadcast_type); | 95 | | #endif | 96 | 7.64k | const T old_value = m_value; | 97 | 7.64k | m_value = value; | 98 | | | 99 | 7.64k | Broadcast(old_value, broadcast_type); | 100 | 7.64k | } |
|
101 | | |
102 | | /// Wait for Cond(m_value) to be true. |
103 | | /// |
104 | | /// Waits in a thread safe way for Cond(m_value) to be true. If Cond(m_value) |
105 | | /// is already true, this function will return without waiting. |
106 | | /// |
107 | | /// It is possible for the value to be changed between the time the value is |
108 | | /// set and the time the waiting thread wakes up. If the value no longer |
109 | | /// satisfies the condition when the waiting thread wakes up, it will go back |
110 | | /// into a wait state. It may be necessary for the calling code to use |
111 | | /// additional thread synchronization methods to detect transitory states. |
112 | | /// |
113 | | /// \param[in] Cond |
114 | | /// The condition we want \a m_value satisfy. |
115 | | /// |
116 | | /// \param[in] timeout |
117 | | /// How long to wait for the condition to hold. |
118 | | /// |
119 | | /// \return |
120 | | /// m_value if Cond(m_value) is true, std::nullopt otherwise (timeout |
121 | | /// occurred). |
122 | | template <typename C> |
123 | 6.30k | std::optional<T> WaitFor(C Cond, const Timeout<std::micro> &timeout) { |
124 | 6.30k | std::unique_lock<std::mutex> lock(m_mutex); |
125 | 11.0k | auto RealCond = [&] { return Cond(m_value); }; std::__1::optional<bool> lldb_private::Predicate<bool>::WaitFor<lldb_private::Predicate<bool>::WaitForValueEqualTo(bool, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(bool)>(lldb_private::Predicate<bool>::WaitForValueEqualTo(bool, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(bool), lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'()::operator()() const Line | Count | Source | 125 | 9.59k | auto RealCond = [&] { return Cond(m_value); }; |
std::__1::optional<unsigned int> lldb_private::Predicate<unsigned int>::WaitFor<lldb_private::Predicate<unsigned int>::WaitForValueNotEqualTo(unsigned int, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(unsigned int)>(lldb_private::Predicate<unsigned int>::WaitForValueNotEqualTo(unsigned int, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(unsigned int), lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'()::operator()() const Line | Count | Source | 125 | 1.50k | auto RealCond = [&] { return Cond(m_value); }; |
|
126 | 6.30k | if (!timeout) { |
127 | 54 | m_condition.wait(lock, RealCond); |
128 | 54 | return m_value; |
129 | 54 | } |
130 | 6.24k | if (m_condition.wait_for(lock, *timeout, RealCond)) |
131 | 6.24k | return m_value; |
132 | 2 | return std::nullopt; |
133 | 6.24k | } std::__1::optional<bool> lldb_private::Predicate<bool>::WaitFor<lldb_private::Predicate<bool>::WaitForValueEqualTo(bool, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(bool)>(lldb_private::Predicate<bool>::WaitForValueEqualTo(bool, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(bool), lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&) Line | Count | Source | 123 | 4.79k | std::optional<T> WaitFor(C Cond, const Timeout<std::micro> &timeout) { | 124 | 4.79k | std::unique_lock<std::mutex> lock(m_mutex); | 125 | 4.79k | auto RealCond = [&] { return Cond(m_value); }; | 126 | 4.79k | if (!timeout) { | 127 | 54 | m_condition.wait(lock, RealCond); | 128 | 54 | return m_value; | 129 | 54 | } | 130 | 4.74k | if (m_condition.wait_for(lock, *timeout, RealCond)) | 131 | 4.74k | return m_value; | 132 | 0 | return std::nullopt; | 133 | 4.74k | } |
std::__1::optional<unsigned int> lldb_private::Predicate<unsigned int>::WaitFor<lldb_private::Predicate<unsigned int>::WaitForValueNotEqualTo(unsigned int, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(unsigned int)>(lldb_private::Predicate<unsigned int>::WaitForValueNotEqualTo(unsigned int, lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&)::'lambda'(unsigned int), lldb_private::Timeout<std::__1::ratio<1l, 1000000l> > const&) Line | Count | Source | 123 | 1.50k | std::optional<T> WaitFor(C Cond, const Timeout<std::micro> &timeout) { | 124 | 1.50k | std::unique_lock<std::mutex> lock(m_mutex); | 125 | 1.50k | auto RealCond = [&] { return Cond(m_value); }; | 126 | 1.50k | if (!timeout) { | 127 | 0 | m_condition.wait(lock, RealCond); | 128 | 0 | return m_value; | 129 | 0 | } | 130 | 1.50k | if (m_condition.wait_for(lock, *timeout, RealCond)) | 131 | 1.50k | return m_value; | 132 | 2 | return std::nullopt; | 133 | 1.50k | } |
|
134 | | /// Wait for \a m_value to be equal to \a value. |
135 | | /// |
136 | | /// Waits in a thread safe way for \a m_value to be equal to \a |
137 | | /// value. If \a m_value is already equal to \a value, this |
138 | | /// function will return without waiting. |
139 | | /// |
140 | | /// It is possible for the value to be changed between the time |
141 | | /// the value is set and the time the waiting thread wakes up. |
142 | | /// If the value no longer matches the requested value when the |
143 | | /// waiting thread wakes up, it will go back into a wait state. It |
144 | | /// may be necessary for the calling code to use additional thread |
145 | | /// synchronization methods to detect transitory states. |
146 | | /// |
147 | | /// \param[in] value |
148 | | /// The value we want \a m_value to be equal to. |
149 | | /// |
150 | | /// \param[in] timeout |
151 | | /// How long to wait for the condition to hold. |
152 | | /// |
153 | | /// \return |
154 | | /// true if the \a m_value is equal to \a value, false otherwise (timeout |
155 | | /// occurred). |
156 | | bool WaitForValueEqualTo(T value, |
157 | 4.79k | const Timeout<std::micro> &timeout = std::nullopt) { |
158 | 9.59k | return WaitFor([&value](T current) { return value == current; }, timeout) != |
159 | 4.79k | std::nullopt; |
160 | 4.79k | } |
161 | | |
162 | | /// Wait for \a m_value to not be equal to \a value. |
163 | | /// |
164 | | /// Waits in a thread safe way for \a m_value to not be equal to \a |
165 | | /// value. If \a m_value is already not equal to \a value, this |
166 | | /// function will return without waiting. |
167 | | /// |
168 | | /// It is possible for the value to be changed between the time |
169 | | /// the value is set and the time the waiting thread wakes up. |
170 | | /// If the value is equal to the test value when the waiting thread |
171 | | /// wakes up, it will go back into a wait state. It may be |
172 | | /// necessary for the calling code to use additional thread |
173 | | /// synchronization methods to detect transitory states. |
174 | | /// |
175 | | /// \param[in] value |
176 | | /// The value we want \a m_value to not be equal to. |
177 | | /// |
178 | | /// \param[in] timeout |
179 | | /// How long to wait for the condition to hold. |
180 | | /// |
181 | | /// \return |
182 | | /// m_value if m_value != value, std::nullopt otherwise (timeout |
183 | | /// occurred). |
184 | | std::optional<T> |
185 | | WaitForValueNotEqualTo(T value, |
186 | 1.50k | const Timeout<std::micro> &timeout = std::nullopt) { |
187 | 1.50k | return WaitFor([&value](T current) { return value != current; }, timeout); |
188 | 1.50k | } |
189 | | |
190 | | protected: |
191 | | // pthread condition and mutex variable to control access and allow blocking |
192 | | // between the main thread and the spotlight index thread. |
193 | | T m_value; ///< The templatized value T that we are protecting access to |
194 | | mutable std::mutex m_mutex; ///< The mutex to use when accessing the data |
195 | | std::condition_variable m_condition; ///< The pthread condition variable to |
196 | | /// use for signaling that data available |
197 | | /// or changed. |
198 | | |
199 | | private: |
200 | | /// Broadcast if needed. |
201 | | /// |
202 | | /// Check to see if we need to broadcast to our condition variable |
203 | | /// depending on the \a old_value and on the \a broadcast_type. |
204 | | /// |
205 | | /// If \a broadcast_type is eBroadcastNever, no broadcast will be |
206 | | /// sent. |
207 | | /// |
208 | | /// If \a broadcast_type is eBroadcastAlways, the condition variable |
209 | | /// will always be broadcast. |
210 | | /// |
211 | | /// If \a broadcast_type is eBroadcastOnChange, the condition |
212 | | /// variable be broadcast if the owned value changes. |
213 | 30.3k | void Broadcast(T old_value, PredicateBroadcastType broadcast_type) { |
214 | 30.3k | bool broadcast = |
215 | 30.3k | (broadcast_type == eBroadcastAlways) || |
216 | 30.3k | (17.9k (broadcast_type == eBroadcastOnChange)17.9k && old_value != m_value17.9k ); |
217 | | #ifdef DB_PTHREAD_LOG_EVENTS |
218 | | printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, " |
219 | | "broadcast = %u\n", |
220 | | __FUNCTION__, old_value, broadcast_type, m_value, broadcast); |
221 | | #endif |
222 | 30.3k | if (broadcast) |
223 | 26.8k | m_condition.notify_all(); |
224 | 30.3k | } lldb_private::Predicate<bool>::Broadcast(bool, lldb_private::PredicateBroadcastType) Line | Count | Source | 213 | 22.7k | void Broadcast(T old_value, PredicateBroadcastType broadcast_type) { | 214 | 22.7k | bool broadcast = | 215 | 22.7k | (broadcast_type == eBroadcastAlways) || | 216 | 22.7k | (17.9k (broadcast_type == eBroadcastOnChange)17.9k && old_value != m_value17.9k ); | 217 | | #ifdef DB_PTHREAD_LOG_EVENTS | 218 | | printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, " | 219 | | "broadcast = %u\n", | 220 | | __FUNCTION__, old_value, broadcast_type, m_value, broadcast); | 221 | | #endif | 222 | 22.7k | if (broadcast) | 223 | 19.1k | m_condition.notify_all(); | 224 | 22.7k | } |
lldb_private::Predicate<unsigned int>::Broadcast(unsigned int, lldb_private::PredicateBroadcastType) Line | Count | Source | 213 | 7.64k | void Broadcast(T old_value, PredicateBroadcastType broadcast_type) { | 214 | 7.64k | bool broadcast = | 215 | 7.64k | (broadcast_type == eBroadcastAlways) || | 216 | 7.64k | (0 (broadcast_type == eBroadcastOnChange)0 && old_value != m_value0 ); | 217 | | #ifdef DB_PTHREAD_LOG_EVENTS | 218 | | printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, " | 219 | | "broadcast = %u\n", | 220 | | __FUNCTION__, old_value, broadcast_type, m_value, broadcast); | 221 | | #endif | 222 | 7.64k | if (broadcast) | 223 | 7.64k | m_condition.notify_all(); | 224 | 7.64k | } |
|
225 | | |
226 | | Predicate(const Predicate &) = delete; |
227 | | const Predicate &operator=(const Predicate &) = delete; |
228 | | }; |
229 | | |
230 | | } // namespace lldb_private |
231 | | |
232 | | #endif // LLDB_UTILITY_PREDICATE_H |