Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:42:57

0001 //===-- Predicate.h ---------------------------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 
0009 #ifndef LLDB_UTILITY_PREDICATE_H
0010 #define LLDB_UTILITY_PREDICATE_H
0011 
0012 #include <cstdint>
0013 #include <ctime>
0014 
0015 #include <condition_variable>
0016 #include <mutex>
0017 #include <optional>
0018 
0019 #include "lldb/Utility/Timeout.h"
0020 #include "lldb/lldb-defines.h"
0021 
0022 //#define DB_PTHREAD_LOG_EVENTS
0023 
0024 /// Enumerations for broadcasting.
0025 namespace lldb_private {
0026 
0027 enum PredicateBroadcastType {
0028   eBroadcastNever,   ///< No broadcast will be sent when the value is modified.
0029   eBroadcastAlways,  ///< Always send a broadcast when the value is modified.
0030   eBroadcastOnChange ///< Only broadcast if the value changes when the value is
0031                      /// modified.
0032 };
0033 
0034 /// \class Predicate Predicate.h "lldb/Utility/Predicate.h"
0035 /// A C++ wrapper class for providing threaded access to a value of
0036 /// type T.
0037 ///
0038 /// A templatized class that provides multi-threaded access to a value
0039 /// of type T. Threads can efficiently wait for bits within T to be set
0040 /// or reset, or wait for T to be set to be equal/not equal to a
0041 /// specified values.
0042 template <class T> class Predicate {
0043 public:
0044   /// Default constructor.
0045   ///
0046   /// Initializes the mutex, condition and value with their default
0047   /// constructors.
0048   Predicate() : m_value() {}
0049 
0050   /// Construct with initial T value \a initial_value.
0051   ///
0052   /// Initializes the mutex and condition with their default
0053   /// constructors, and initializes the value with \a initial_value.
0054   ///
0055   /// \param[in] initial_value
0056   ///     The initial value for our T object.
0057   Predicate(T initial_value) : m_value(initial_value) {}
0058 
0059   /// Destructor.
0060   ///
0061   /// Destroy the condition, mutex, and T objects.
0062   ~Predicate() = default;
0063 
0064   /// Value get accessor.
0065   ///
0066   /// Copies the current \a m_value in a thread safe manor and returns
0067   /// the copied value.
0068   ///
0069   /// \return
0070   ///     A copy of the current value.
0071   T GetValue() const {
0072     std::lock_guard<std::mutex> guard(m_mutex);
0073     T value = m_value;
0074     return value;
0075   }
0076 
0077   /// Value set accessor.
0078   ///
0079   /// Set the contained \a m_value to \a new_value in a thread safe
0080   /// way and broadcast if needed.
0081   ///
0082   /// \param[in] value
0083   ///     The new value to set.
0084   ///
0085   /// \param[in] broadcast_type
0086   ///     A value indicating when and if to broadcast. See the
0087   ///     PredicateBroadcastType enumeration for details.
0088   ///
0089   /// \see Predicate::Broadcast()
0090   void SetValue(T value, PredicateBroadcastType broadcast_type) {
0091     std::lock_guard<std::mutex> guard(m_mutex);
0092 #ifdef DB_PTHREAD_LOG_EVENTS
0093     printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value,
0094            broadcast_type);
0095 #endif
0096     const T old_value = m_value;
0097     m_value = value;
0098 
0099     Broadcast(old_value, broadcast_type);
0100   }
0101 
0102   /// Wait for Cond(m_value) to be true.
0103   ///
0104   /// Waits in a thread safe way for Cond(m_value) to be true. If Cond(m_value)
0105   /// is already true, this function will return without waiting.
0106   ///
0107   /// It is possible for the value to be changed between the time the value is
0108   /// set and the time the waiting thread wakes up. If the value no longer
0109   /// satisfies the condition when the waiting thread wakes up, it will go back
0110   /// into a wait state. It may be necessary for the calling code to use
0111   /// additional thread synchronization methods to detect transitory states.
0112   ///
0113   /// \param[in] Cond
0114   ///     The condition we want \a m_value satisfy.
0115   ///
0116   /// \param[in] timeout
0117   ///     How long to wait for the condition to hold.
0118   ///
0119   /// \return
0120   ///     m_value if Cond(m_value) is true, std::nullopt otherwise (timeout
0121   ///     occurred).
0122   template <typename C>
0123   std::optional<T> WaitFor(C Cond, const Timeout<std::micro> &timeout) {
0124     std::unique_lock<std::mutex> lock(m_mutex);
0125     auto RealCond = [&] { return Cond(m_value); };
0126     if (!timeout) {
0127       m_condition.wait(lock, RealCond);
0128       return m_value;
0129     }
0130     if (m_condition.wait_for(lock, *timeout, RealCond))
0131       return m_value;
0132     return std::nullopt;
0133   }
0134   /// Wait for \a m_value to be equal to \a value.
0135   ///
0136   /// Waits in a thread safe way for \a m_value to be equal to \a
0137   /// value. If \a m_value is already equal to \a value, this
0138   /// function will return without waiting.
0139   ///
0140   /// It is possible for the value to be changed between the time
0141   /// the value is set and the time the waiting thread wakes up.
0142   /// If the value no longer matches the requested value when the
0143   /// waiting thread wakes up, it will go back into a wait state.  It
0144   /// may be necessary for the calling code to use additional thread
0145   /// synchronization methods to detect transitory states.
0146   ///
0147   /// \param[in] value
0148   ///     The value we want \a m_value to be equal to.
0149   ///
0150   /// \param[in] timeout
0151   ///     How long to wait for the condition to hold.
0152   ///
0153   /// \return
0154   ///     true if the \a m_value is equal to \a value, false otherwise (timeout
0155   ///     occurred).
0156   bool WaitForValueEqualTo(T value,
0157                            const Timeout<std::micro> &timeout = std::nullopt) {
0158     return WaitFor([&value](T current) { return value == current; }, timeout) !=
0159            std::nullopt;
0160   }
0161 
0162   /// Wait for \a m_value to not be equal to \a value.
0163   ///
0164   /// Waits in a thread safe way for \a m_value to not be equal to \a
0165   /// value. If \a m_value is already not equal to \a value, this
0166   /// function will return without waiting.
0167   ///
0168   /// It is possible for the value to be changed between the time
0169   /// the value is set and the time the waiting thread wakes up.
0170   /// If the value is equal to the test value when the waiting thread
0171   /// wakes up, it will go back into a wait state.  It may be
0172   /// necessary for the calling code to use additional thread
0173   /// synchronization methods to detect transitory states.
0174   ///
0175   /// \param[in] value
0176   ///     The value we want \a m_value to not be equal to.
0177   ///
0178   /// \param[in] timeout
0179   ///     How long to wait for the condition to hold.
0180   ///
0181   /// \return
0182   ///     m_value if m_value != value, std::nullopt otherwise (timeout
0183   ///     occurred).
0184   std::optional<T>
0185   WaitForValueNotEqualTo(T value,
0186                          const Timeout<std::micro> &timeout = std::nullopt) {
0187     return WaitFor([&value](T current) { return value != current; }, timeout);
0188   }
0189 
0190 protected:
0191   // pthread condition and mutex variable to control access and allow blocking
0192   // between the main thread and the spotlight index thread.
0193   T m_value; ///< The templatized value T that we are protecting access to
0194   mutable std::mutex m_mutex; ///< The mutex to use when accessing the data
0195   std::condition_variable m_condition; ///< The pthread condition variable to
0196                                        /// use for signaling that data available
0197                                        /// or changed.
0198 
0199 private:
0200   /// Broadcast if needed.
0201   ///
0202   /// Check to see if we need to broadcast to our condition variable
0203   /// depending on the \a old_value and on the \a broadcast_type.
0204   ///
0205   /// If \a broadcast_type is eBroadcastNever, no broadcast will be
0206   /// sent.
0207   ///
0208   /// If \a broadcast_type is eBroadcastAlways, the condition variable
0209   /// will always be broadcast.
0210   ///
0211   /// If \a broadcast_type is eBroadcastOnChange, the condition
0212   /// variable be broadcast if the owned value changes.
0213   void Broadcast(T old_value, PredicateBroadcastType broadcast_type) {
0214     bool broadcast =
0215         (broadcast_type == eBroadcastAlways) ||
0216         ((broadcast_type == eBroadcastOnChange) && old_value != m_value);
0217 #ifdef DB_PTHREAD_LOG_EVENTS
0218     printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, "
0219            "broadcast = %u\n",
0220            __FUNCTION__, old_value, broadcast_type, m_value, broadcast);
0221 #endif
0222     if (broadcast)
0223       m_condition.notify_all();
0224   }
0225 
0226   Predicate(const Predicate &) = delete;
0227   const Predicate &operator=(const Predicate &) = delete;
0228 };
0229 
0230 } // namespace lldb_private
0231 
0232 #endif // LLDB_UTILITY_PREDICATE_H