Coverage Report

Created: 2022-01-15 10:30

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