Predicate.h revision 1b584ebc1de8b50fe375cffb5fb33ad13be10046
1//===-- Predicate.h ---------------------------------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10#ifndef liblldb_Predicate_h_ 11#define liblldb_Predicate_h_ 12#if defined(__cplusplus) 13 14#include "lldb/Host/Mutex.h" 15#include "lldb/Host/Condition.h" 16#include <stdint.h> 17#include <time.h> 18 19//#define DB_PTHREAD_LOG_EVENTS 20 21//---------------------------------------------------------------------- 22/// Enumerations for broadcasting. 23//---------------------------------------------------------------------- 24namespace lldb_private { 25 26typedef enum 27{ 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 modified. 31 32} PredicateBroadcastType; 33 34//---------------------------------------------------------------------- 35/// @class Predicate Predicate.h "lldb/Host/Predicate.h" 36/// @brief A C++ wrapper class for providing threaded access to a value 37/// of type T. 38/// 39/// A templatized class that provides multi-threaded access to a value 40/// of type T. Threads can efficiently wait for bits within T to be set 41/// or reset, or wait for T to be set to be equal/not equal to a 42/// specified values. 43//---------------------------------------------------------------------- 44template <class T> 45class Predicate 46{ 47public: 48 49 //------------------------------------------------------------------ 50 /// Default constructor. 51 /// 52 /// Initializes the mutex, condition and value with their default 53 /// constructors. 54 //------------------------------------------------------------------ 55 Predicate () : 56 m_value(), 57 m_mutex(), 58 m_condition() 59 { 60 } 61 62 //------------------------------------------------------------------ 63 /// Construct with initial T value \a initial_value. 64 /// 65 /// Initializes the mutex and condition with their default 66 /// constructors, and initializes the value with \a initial_value. 67 /// 68 /// @param[in] initial_value 69 /// The initial value for our T object. 70 //------------------------------------------------------------------ 71 Predicate (T initial_value) : 72 m_value(initial_value), 73 m_mutex(), 74 m_condition() 75 { 76 } 77 78 //------------------------------------------------------------------ 79 /// Destructor. 80 /// 81 /// Destrory the condition, mutex, and T objects. 82 //------------------------------------------------------------------ 83 ~Predicate () 84 { 85 } 86 87 88 //------------------------------------------------------------------ 89 /// Value get accessor. 90 /// 91 /// Copies the current \a m_value in a thread safe manor and returns 92 /// the copied value. 93 /// 94 /// @return 95 /// A copy of the current value. 96 //------------------------------------------------------------------ 97 T 98 GetValue () const 99 { 100 Mutex::Locker locker(m_mutex); 101 T value = m_value; 102 return value; 103 } 104 105 //------------------------------------------------------------------ 106 /// Value set accessor. 107 /// 108 /// Set the contained \a m_value to \a new_value in a thread safe 109 /// way and broadcast if needed. 110 /// 111 /// @param[in] value 112 /// The new value to set. 113 /// 114 /// @param[in] broadcast_type 115 /// A value indicating when and if to broadast. See the 116 /// PredicateBroadcastType enumeration for details. 117 /// 118 /// @see Predicate::Broadcast() 119 //------------------------------------------------------------------ 120 void 121 SetValue (T value, PredicateBroadcastType broadcast_type) 122 { 123 Mutex::Locker locker(m_mutex); 124#ifdef DB_PTHREAD_LOG_EVENTS 125 printf("%s (value = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, value, broadcast_type); 126#endif 127 const T old_value = m_value; 128 m_value = value; 129 130 Broadcast(old_value, broadcast_type); 131 } 132 133 //------------------------------------------------------------------ 134 /// Set some bits in \a m_value. 135 /// 136 /// Logically set the bits \a bits in the contained \a m_value in a 137 /// thread safe way and broadcast if needed. 138 /// 139 /// @param[in] bits 140 /// The bits to set in \a m_value. 141 /// 142 /// @param[in] broadcast_type 143 /// A value indicating when and if to broadast. See the 144 /// PredicateBroadcastType enumeration for details. 145 /// 146 /// @see Predicate::Broadcast() 147 //------------------------------------------------------------------ 148 void 149 SetValueBits (T bits, PredicateBroadcastType broadcast_type) 150 { 151 Mutex::Locker locker(m_mutex); 152#ifdef DB_PTHREAD_LOG_EVENTS 153 printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, broadcast_type); 154#endif 155 const T old_value = m_value; 156 m_value |= bits; 157 158 Broadcast(old_value, broadcast_type); 159 } 160 161 //------------------------------------------------------------------ 162 /// Reset some bits in \a m_value. 163 /// 164 /// Logically reset (clear) the bits \a bits in the contained 165 /// \a m_value in a thread safe way and broadcast if needed. 166 /// 167 /// @param[in] bits 168 /// The bits to clear in \a m_value. 169 /// 170 /// @param[in] broadcast_type 171 /// A value indicating when and if to broadast. See the 172 /// PredicateBroadcastType enumeration for details. 173 /// 174 /// @see Predicate::Broadcast() 175 //------------------------------------------------------------------ 176 void 177 ResetValueBits (T bits, PredicateBroadcastType broadcast_type) 178 { 179 Mutex::Locker locker(m_mutex); 180#ifdef DB_PTHREAD_LOG_EVENTS 181 printf("%s (bits = 0x%8.8x, broadcast_type = %i)\n", __FUNCTION__, bits, broadcast_type); 182#endif 183 const T old_value = m_value; 184 m_value &= ~bits; 185 186 Broadcast(old_value, broadcast_type); 187 } 188 189 //------------------------------------------------------------------ 190 /// Wait for bits to be set in \a m_value. 191 /// 192 /// Waits in a thread safe way for any bits in \a bits to get 193 /// logically set in \a m_value. If any bits are already set in 194 /// \a m_value, this function will return without waiting. 195 /// 196 /// @param[in] bits 197 /// The bits we are waiting to be set in \a m_value. 198 /// 199 /// @param[in] abstime 200 /// If non-NULL, the absolute time at which we should stop 201 /// waiting, else wait an infinite amount of time. 202 /// 203 /// @return 204 /// Any bits of the requested bits that actually were set within 205 /// the time specified. Zero if a timeout or unrecoverable error 206 /// occurred. 207 //------------------------------------------------------------------ 208 T 209 WaitForSetValueBits (T bits, const TimeValue *abstime = NULL) 210 { 211 int err = 0; 212 // pthread_cond_timedwait() or pthread_cond_wait() will atomically 213 // unlock the mutex and wait for the condition to be set. When either 214 // function returns, they will re-lock the mutex. We use an auto lock/unlock 215 // class (Mutex::Locker) to allow us to return at any point in this 216 // function and not have to worry about unlocking the mutex. 217 Mutex::Locker locker(m_mutex); 218#ifdef DB_PTHREAD_LOG_EVENTS 219 printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, bits, abstime, m_value); 220#endif 221 while (err == 0 && ((m_value & bits) == 0)) 222 { 223 err = m_condition.Wait (m_mutex.GetMutex(), abstime); 224 } 225#ifdef DB_PTHREAD_LOG_EVENTS 226 printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", __FUNCTION__, bits, m_value, m_value & bits); 227#endif 228 229 return m_value & bits; 230 } 231 232 //------------------------------------------------------------------ 233 /// Wait for bits to be reset in \a m_value. 234 /// 235 /// Waits in a thread safe way for any bits in \a bits to get 236 /// logically reset in \a m_value. If all bits are already reset in 237 /// \a m_value, this function will return without waiting. 238 /// 239 /// @param[in] bits 240 /// The bits we are waiting to be reset in \a m_value. 241 /// 242 /// @param[in] abstime 243 /// If non-NULL, the absolute time at which we should stop 244 /// waiting, else wait an infinite amount of time. 245 /// 246 /// @return 247 /// Zero on successful waits, or non-zero if a timeout or 248 /// unrecoverable error occurs. 249 //------------------------------------------------------------------ 250 T 251 WaitForResetValueBits (T bits, const TimeValue *abstime = NULL) 252 { 253 int err = 0; 254 255 // pthread_cond_timedwait() or pthread_cond_wait() will atomically 256 // unlock the mutex and wait for the condition to be set. When either 257 // function returns, they will re-lock the mutex. We use an auto lock/unlock 258 // class (Mutex::Locker) to allow us to return at any point in this 259 // function and not have to worry about unlocking the mutex. 260 Mutex::Locker locker(m_mutex); 261 262#ifdef DB_PTHREAD_LOG_EVENTS 263 printf("%s (bits = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, bits, abstime, m_value); 264#endif 265 while (err == 0 && ((m_value & bits) != 0)) 266 { 267 err = m_condition.Wait (m_mutex.GetMutex(), abstime); 268 } 269 270#ifdef DB_PTHREAD_LOG_EVENTS 271 printf("%s (bits = 0x%8.8x), m_value = 0x%8.8x, returning 0x%8.8x\n", __FUNCTION__, bits, m_value, m_value & bits); 272#endif 273 return m_value & bits; 274 } 275 276 //------------------------------------------------------------------ 277 /// Wait for \a m_value to be equal to \a value. 278 /// 279 /// Waits in a thread safe way for \a m_value to be equal to \a 280 /// value. If \a m_value is already equal to \a value, this 281 /// function will return without waiting. 282 /// 283 /// @param[in] value 284 /// The value we want \a m_value to be equal to. 285 /// 286 /// @param[in] abstime 287 /// If non-NULL, the absolute time at which we should stop 288 /// waiting, else wait an infinite amount of time. 289 /// 290 /// @param[out] timed_out 291 /// If not null, set to true if we return because of a time out, 292 /// and false if the value was set. 293 /// 294 /// @return 295 /// @li \b true if the \a m_value is equal to \a value 296 /// @li \b false otherwise 297 //------------------------------------------------------------------ 298 bool 299 WaitForValueEqualTo (T value, const TimeValue *abstime = NULL, bool *timed_out = NULL) 300 { 301 int err = 0; 302 // pthread_cond_timedwait() or pthread_cond_wait() will atomically 303 // unlock the mutex and wait for the condition to be set. When either 304 // function returns, they will re-lock the mutex. We use an auto lock/unlock 305 // class (Mutex::Locker) to allow us to return at any point in this 306 // function and not have to worry about unlocking the mutex. 307 Mutex::Locker locker(m_mutex); 308 309#ifdef DB_PTHREAD_LOG_EVENTS 310 printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, value, abstime, m_value); 311#endif 312 if (timed_out) 313 *timed_out = false; 314 315 while (err == 0 && m_value != value) 316 { 317 err = m_condition.Wait (m_mutex, abstime, timed_out); 318 } 319 320 return m_value == value; 321 } 322 323 bool 324 WaitForValueEqualToAndSetValueTo (T wait_value, T new_value, const TimeValue *abstime = NULL, bool *timed_out = NULL) 325 { 326 int err = 0; 327 // pthread_cond_timedwait() or pthread_cond_wait() will atomically 328 // unlock the mutex and wait for the condition to be set. When either 329 // function returns, they will re-lock the mutex. We use an auto lock/unlock 330 // class (Mutex::Locker) to allow us to return at any point in this 331 // function and not have to worry about unlocking the mutex. 332 Mutex::Locker locker(m_mutex); 333 334#ifdef DB_PTHREAD_LOG_EVENTS 335 printf("%s (wait_value = 0x%8.8x, new_value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, wait_value, new_value, abstime, m_value); 336#endif 337 if (timed_out) 338 *timed_out = false; 339 340 while (err == 0 && m_value != wait_value) 341 { 342 err = m_condition.Wait (m_mutex, abstime, timed_out); 343 } 344 345 if (m_value == wait_value) 346 { 347 m_value = new_value; 348 return true; 349 } 350 351 return false; 352 } 353 354 355 //------------------------------------------------------------------ 356 /// Wait for \a m_value to not be equal to \a value. 357 /// 358 /// Waits in a thread safe way for \a m_value to not be equal to \a 359 /// value. If \a m_value is already not equal to \a value, this 360 /// function will return without waiting. 361 /// 362 /// @param[in] value 363 /// The value we want \a m_value to not be equal to. 364 /// 365 /// @param[out] new_value 366 /// The new value if \b true is returned. 367 /// 368 /// @param[in] abstime 369 /// If non-NULL, the absolute time at which we should stop 370 /// waiting, else wait an infinite amount of time. 371 /// 372 /// @return 373 /// @li \b true if the \a m_value is equal to \a value 374 /// @li \b false otherwise 375 //------------------------------------------------------------------ 376 bool 377 WaitForValueNotEqualTo (T value, T &new_value, const TimeValue *abstime = NULL) 378 { 379 int err = 0; 380 // pthread_cond_timedwait() or pthread_cond_wait() will atomically 381 // unlock the mutex and wait for the condition to be set. When either 382 // function returns, they will re-lock the mutex. We use an auto lock/unlock 383 // class (Mutex::Locker) to allow us to return at any point in this 384 // function and not have to worry about unlocking the mutex. 385 Mutex::Locker locker(m_mutex); 386#ifdef DB_PTHREAD_LOG_EVENTS 387 printf("%s (value = 0x%8.8x, abstime = %p), m_value = 0x%8.8x\n", __FUNCTION__, value, abstime, m_value); 388#endif 389 while (err == 0 && m_value == value) 390 { 391 err = m_condition.Wait (m_mutex.GetMutex(), abstime); 392 } 393 394 if (m_value != value) 395 { 396 new_value = m_value; 397 return true; 398 } 399 return false; 400 } 401 402protected: 403 //---------------------------------------------------------------------- 404 // pthread condition and mutex variable to controll access and allow 405 // blocking between the main thread and the spotlight index thread. 406 //---------------------------------------------------------------------- 407 T m_value; ///< The templatized value T that we are protecting access to 408 mutable Mutex m_mutex; ///< The mutex to use when accessing the data 409 Condition m_condition; ///< The pthread condition variable to use for signaling that data available or changed. 410 411private: 412 413 //------------------------------------------------------------------ 414 /// Broadcast if needed. 415 /// 416 /// Check to see if we need to broadcast to our condition variable 417 /// depedning on the \a old_value and on the \a broadcast_type. 418 /// 419 /// If \a broadcast_type is eBroadcastNever, no broadcast will be 420 /// sent. 421 /// 422 /// If \a broadcast_type is eBroadcastAlways, the condition variable 423 /// will always be broadcast. 424 /// 425 /// If \a broadcast_type is eBroadcastOnChange, the condition 426 /// variable be broadcast if the owned value changes. 427 //------------------------------------------------------------------ 428 void 429 Broadcast (T old_value, PredicateBroadcastType broadcast_type) 430 { 431 bool broadcast = (broadcast_type == eBroadcastAlways) || ((broadcast_type == eBroadcastOnChange) && old_value != m_value); 432#ifdef DB_PTHREAD_LOG_EVENTS 433 printf("%s (old_value = 0x%8.8x, broadcast_type = %i) m_value = 0x%8.8x, broadcast = %u\n", __FUNCTION__, old_value, broadcast_type, m_value, broadcast); 434#endif 435 if (broadcast) 436 m_condition.Broadcast(); 437 } 438 439 440 DISALLOW_COPY_AND_ASSIGN(Predicate); 441}; 442 443} // namespace lldb_private 444 445#endif // #if defined(__cplusplus) 446#endif // #ifndef liblldb_Predicate_h_ 447