llmutex.h 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /**
  2. * @file llmutex.h
  3. * @brief Base classes for mutex and condition handling.
  4. *
  5. * $LicenseInfo:firstyear=2004&license=viewergpl$
  6. *
  7. * Copyright (c) 2004-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #ifndef LL_LLMUTEX_H
  33. #define LL_LLMUTEX_H
  34. // For now disable the fibers-aware mutexes unconditionnaly since they cause a
  35. // weird issue with "Illegal deletion of LLDrawable" (and even though I plugged
  36. // the cases where it could cause crashes, it is an abnormal condition, hinting
  37. // for an issue in how mutexes may fail when taken across fibers). HB
  38. #define LL_USE_FIBER_AWARE_MUTEX 0
  39. #include <mutex>
  40. #if LL_USE_FIBER_AWARE_MUTEX
  41. # include "boost/fiber/mutex.hpp"
  42. # include "boost/fiber/recursive_mutex.hpp"
  43. # include "boost/fiber/condition_variable.hpp"
  44. # define LL_MUTEX_TYPE boost::fibers::mutex
  45. # define LL_REC_MUTEX_TYPE boost::fibers::recursive_mutex
  46. # define LL_UNIQ_LOCK_TYPE std::unique_lock<boost::fibers::mutex>
  47. # define LL_UNIQ_LOCK_REC_TYPE std::unique_lock<boost::fibers::recursive_mutex>
  48. # define LL_COND_TYPE boost::fibers::condition_variable
  49. # define LL_COND_ANY_TYPE boost::fibers::condition_variable_any
  50. #else
  51. # include <condition_variable>
  52. # define LL_MUTEX_TYPE std::mutex
  53. # define LL_REC_MUTEX_TYPE std::recursive_mutex
  54. # define LL_UNIQ_LOCK_TYPE std::unique_lock<std::mutex>
  55. # define LL_UNIQ_LOCK_REC_TYPE std::unique_lock<std::recursive_mutex>
  56. # define LL_COND_TYPE std::condition_variable
  57. # define LL_COND_ANY_TYPE std::condition_variable_any
  58. #endif
  59. #include "llerror.h"
  60. class LLMutex
  61. {
  62. protected:
  63. LOG_CLASS(LLMutex);
  64. public:
  65. LLMutex() = default;
  66. virtual ~LLMutex() = default;
  67. LL_INLINE void lock() { mMutex.lock(); }
  68. LL_INLINE void unlock() { mMutex.unlock(); }
  69. LL_INLINE bool trylock() { return mMutex.try_lock(); }
  70. bool isLocked();
  71. protected:
  72. LL_REC_MUTEX_TYPE mMutex;
  73. };
  74. // Actually a condition/mutex pair (since each condition needs to be associated
  75. // with a mutex).
  76. class LLCondition : public LLMutex
  77. {
  78. public:
  79. LLCondition() = default;
  80. ~LLCondition() override = default;
  81. // This method blocks
  82. LL_INLINE void wait()
  83. {
  84. LL_UNIQ_LOCK_REC_TYPE lock(mMutex);
  85. mCond.wait(lock);
  86. }
  87. LL_INLINE void signal()
  88. {
  89. mCond.notify_one();
  90. }
  91. LL_INLINE void broadcast()
  92. {
  93. mCond.notify_all();
  94. }
  95. protected:
  96. LL_COND_ANY_TYPE mCond;
  97. };
  98. // Scoped locking class
  99. class LLMutexLock
  100. {
  101. public:
  102. LL_INLINE LLMutexLock(LLMutex* mutexp)
  103. : mMutex(mutexp)
  104. {
  105. if (mMutex)
  106. {
  107. mMutex->lock();
  108. }
  109. }
  110. LL_INLINE LLMutexLock(LLMutex& mutex)
  111. : mMutex(&mutex)
  112. {
  113. mMutex->lock();
  114. }
  115. LL_INLINE ~LLMutexLock()
  116. {
  117. if (mMutex)
  118. {
  119. mMutex->unlock();
  120. }
  121. }
  122. private:
  123. LLMutex* mMutex;
  124. };
  125. // Scoped locking class similar in function to LLMutexLock but uses the
  126. // trylock() method to conditionally acquire lock without blocking. Caller
  127. // resolves the resulting condition by calling the isLocked() method and either
  128. // punts or continues as indicated.
  129. //
  130. // Mostly of interest to callers needing to avoid stalls and that can guarantee
  131. // another attempt at a later time.
  132. class LLMutexTrylock
  133. {
  134. public:
  135. LL_INLINE LLMutexTrylock(LLMutex* mutex)
  136. : mMutex(mutex)
  137. {
  138. mLocked = mMutex && mMutex->trylock();
  139. }
  140. LL_INLINE LLMutexTrylock(LLMutex& mutex)
  141. : mMutex(&mutex)
  142. {
  143. mLocked = mMutex->trylock();
  144. }
  145. // Tries locking 'attempts' times, with 10ms sleep delays between each try.
  146. LLMutexTrylock(LLMutex* mutex, U32 attempts);
  147. LL_INLINE ~LLMutexTrylock()
  148. {
  149. if (mLocked)
  150. {
  151. mMutex->unlock();
  152. }
  153. }
  154. LL_INLINE void unlock()
  155. {
  156. if (mLocked)
  157. {
  158. mLocked = false;
  159. mMutex->unlock();
  160. }
  161. }
  162. LL_INLINE bool isLocked() const { return mLocked; }
  163. private:
  164. LLMutex* mMutex;
  165. // 'true' when the mutex is actually locked by this class
  166. bool mLocked;
  167. };
  168. #endif // LL_LLMUTEX_H