mutex.h 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. /*
  2. * Copyright 2020 The WebRTC Project Authors. All rights reserved.
  3. *
  4. * Use of this source code is governed by a BSD-style license
  5. * that can be found in the LICENSE file in the root of the source
  6. * tree. An additional intellectual property rights grant can be found
  7. * in the file PATENTS. All contributing project authors may
  8. * be found in the AUTHORS file in the root of the source tree.
  9. */
  10. #ifndef RTC_BASE_SYNCHRONIZATION_MUTEX_H_
  11. #define RTC_BASE_SYNCHRONIZATION_MUTEX_H_
  12. #include <atomic>
  13. #include "absl/base/const_init.h"
  14. #include "rtc_base/checks.h"
  15. #include "rtc_base/platform_thread_types.h"
  16. #include "rtc_base/system/unused.h"
  17. #include "rtc_base/thread_annotations.h"
  18. #if defined(WEBRTC_ABSL_MUTEX)
  19. #include "rtc_base/synchronization/mutex_abseil.h" // nogncheck
  20. #elif defined(WEBRTC_WIN)
  21. #include "rtc_base/synchronization/mutex_critical_section.h"
  22. #elif defined(WEBRTC_POSIX)
  23. #include "rtc_base/synchronization/mutex_pthread.h"
  24. #else
  25. #error Unsupported platform.
  26. #endif
  27. namespace webrtc {
  28. // The Mutex guarantees exclusive access and aims to follow Abseil semantics
  29. // (i.e. non-reentrant etc).
  30. class RTC_LOCKABLE Mutex final {
  31. public:
  32. Mutex() = default;
  33. Mutex(const Mutex&) = delete;
  34. Mutex& operator=(const Mutex&) = delete;
  35. void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION() {
  36. rtc::PlatformThreadRef current = CurrentThreadRefAssertingNotBeingHolder();
  37. impl_.Lock();
  38. // |holder_| changes from 0 to CurrentThreadRef().
  39. holder_.store(current, std::memory_order_relaxed);
  40. }
  41. RTC_WARN_UNUSED_RESULT bool TryLock() RTC_EXCLUSIVE_TRYLOCK_FUNCTION(true) {
  42. rtc::PlatformThreadRef current = CurrentThreadRefAssertingNotBeingHolder();
  43. if (impl_.TryLock()) {
  44. // |holder_| changes from 0 to CurrentThreadRef().
  45. holder_.store(current, std::memory_order_relaxed);
  46. return true;
  47. }
  48. return false;
  49. }
  50. void Unlock() RTC_UNLOCK_FUNCTION() {
  51. // |holder_| changes from CurrentThreadRef() to 0. If something else than
  52. // CurrentThreadRef() is stored in |holder_|, the Unlock results in
  53. // undefined behavior as mutexes can't be unlocked from another thread than
  54. // the one that locked it, or called while not being locked.
  55. holder_.store(0, std::memory_order_relaxed);
  56. impl_.Unlock();
  57. }
  58. private:
  59. rtc::PlatformThreadRef CurrentThreadRefAssertingNotBeingHolder() {
  60. rtc::PlatformThreadRef holder = holder_.load(std::memory_order_relaxed);
  61. rtc::PlatformThreadRef current = rtc::CurrentThreadRef();
  62. // TODO(bugs.webrtc.org/11567): remove this temporary check after migrating
  63. // fully to Mutex.
  64. RTC_CHECK_NE(holder, current);
  65. return current;
  66. }
  67. MutexImpl impl_;
  68. // TODO(bugs.webrtc.org/11567): remove |holder_| after migrating fully to
  69. // Mutex.
  70. // |holder_| contains the PlatformThreadRef of the thread currently holding
  71. // the lock, or 0.
  72. // Remarks on the used memory orders: the atomic load in
  73. // CurrentThreadRefAssertingNotBeingHolder() observes either of two things:
  74. // 1. our own previous write to holder_ with our thread ID.
  75. // 2. another thread (with ID y) writing y and then 0 from an initial value of
  76. // 0. If we're observing case 1, our own stores are obviously ordered before
  77. // the load, and hit the CHECK. If we're observing case 2, the value observed
  78. // w.r.t |impl_| being locked depends on the memory order. Since we only care
  79. // that it's different from CurrentThreadRef()), we use the more performant
  80. // option, memory_order_relaxed.
  81. std::atomic<rtc::PlatformThreadRef> holder_ = {0};
  82. };
  83. // MutexLock, for serializing execution through a scope.
  84. class RTC_SCOPED_LOCKABLE MutexLock final {
  85. public:
  86. MutexLock(const MutexLock&) = delete;
  87. MutexLock& operator=(const MutexLock&) = delete;
  88. explicit MutexLock(Mutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION(mutex)
  89. : mutex_(mutex) {
  90. mutex->Lock();
  91. }
  92. ~MutexLock() RTC_UNLOCK_FUNCTION() { mutex_->Unlock(); }
  93. private:
  94. Mutex* mutex_;
  95. };
  96. // A mutex used to protect global variables. Do NOT use for other purposes.
  97. #if defined(WEBRTC_ABSL_MUTEX)
  98. using GlobalMutex = absl::Mutex;
  99. using GlobalMutexLock = absl::MutexLock;
  100. #else
  101. class RTC_LOCKABLE GlobalMutex final {
  102. public:
  103. GlobalMutex(const GlobalMutex&) = delete;
  104. GlobalMutex& operator=(const GlobalMutex&) = delete;
  105. constexpr explicit GlobalMutex(absl::ConstInitType /*unused*/)
  106. : mutex_locked_(0) {}
  107. void Lock() RTC_EXCLUSIVE_LOCK_FUNCTION();
  108. void Unlock() RTC_UNLOCK_FUNCTION();
  109. private:
  110. std::atomic<int> mutex_locked_; // 0 means lock not taken, 1 means taken.
  111. };
  112. // GlobalMutexLock, for serializing execution through a scope.
  113. class RTC_SCOPED_LOCKABLE GlobalMutexLock final {
  114. public:
  115. GlobalMutexLock(const GlobalMutexLock&) = delete;
  116. GlobalMutexLock& operator=(const GlobalMutexLock&) = delete;
  117. explicit GlobalMutexLock(GlobalMutex* mutex) RTC_EXCLUSIVE_LOCK_FUNCTION();
  118. ~GlobalMutexLock() RTC_UNLOCK_FUNCTION();
  119. private:
  120. GlobalMutex* mutex_;
  121. };
  122. #endif // if defined(WEBRTC_ABSL_MUTEX)
  123. } // namespace webrtc
  124. #endif // RTC_BASE_SYNCHRONIZATION_MUTEX_H_