lock_impl.h 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
  5. #define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
  6. #include "base/base_export.h"
  7. #include "base/check_op.h"
  8. #include "base/macros.h"
  9. #include "base/thread_annotations.h"
  10. #include "build/build_config.h"
  11. #if defined(OS_WIN)
  12. #include "base/win/windows_types.h"
  13. #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
  14. #include <errno.h>
  15. #include <pthread.h>
  16. #include <string.h>
  17. #include <ostream>
  18. #endif
  19. namespace base {
  20. class Lock;
  21. class ConditionVariable;
  22. namespace win {
  23. namespace internal {
  24. class AutoNativeLock;
  25. class ScopedHandleVerifier;
  26. } // namespace internal
  27. } // namespace win
  28. namespace internal {
  29. // This class implements the underlying platform-specific spin-lock mechanism
  30. // used for the Lock class. Do not use, use Lock instead.
  31. class BASE_EXPORT LockImpl {
  32. friend class base::Lock;
  33. friend class base::ConditionVariable;
  34. friend class base::win::internal::AutoNativeLock;
  35. friend class base::win::internal::ScopedHandleVerifier;
  36. #if defined(OS_WIN)
  37. using NativeHandle = CHROME_SRWLOCK;
  38. #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
  39. using NativeHandle = pthread_mutex_t;
  40. #endif
  41. LockImpl();
  42. ~LockImpl();
  43. // If the lock is not held, take it and return true. If the lock is already
  44. // held by something else, immediately return false.
  45. inline bool Try();
  46. // Take the lock, blocking until it is available if necessary.
  47. inline void Lock();
  48. // Release the lock. This must only be called by the lock's holder: after
  49. // a successful call to Try, or a call to Lock.
  50. inline void Unlock();
  51. // Return the native underlying lock.
  52. // TODO(awalker): refactor lock and condition variables so that this is
  53. // unnecessary.
  54. NativeHandle* native_handle() { return &native_handle_; }
  55. #if defined(OS_POSIX) || defined(OS_FUCHSIA)
  56. // Whether this lock will attempt to use priority inheritance.
  57. static bool PriorityInheritanceAvailable();
  58. #endif
  59. void LockInternalWithTracking();
  60. NativeHandle native_handle_;
  61. DISALLOW_COPY_AND_ASSIGN(LockImpl);
  62. };
  63. void LockImpl::Lock() {
  64. // The ScopedLockAcquireActivity in LockInternalWithTracking() (not inlined
  65. // here because of circular includes) is relatively expensive and so its
  66. // actions can become significant due to the very large number of locks that
  67. // tend to be used throughout the build. It is also not needed unless the lock
  68. // is contended.
  69. //
  70. // To avoid this cost in the vast majority of the calls, simply "try" the lock
  71. // first and only do the (tracked) blocking call if that fails. |Try()| is
  72. // cheap on platforms with futex-type locks, as it doesn't call into the
  73. // kernel.
  74. if (LIKELY(Try()))
  75. return;
  76. LockInternalWithTracking();
  77. }
  78. #if defined(OS_WIN)
  79. bool LockImpl::Try() {
  80. return !!::TryAcquireSRWLockExclusive(
  81. reinterpret_cast<PSRWLOCK>(&native_handle_));
  82. }
  83. void LockImpl::Unlock() {
  84. ::ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&native_handle_));
  85. }
  86. #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
  87. bool LockImpl::Try() {
  88. int rv = pthread_mutex_trylock(&native_handle_);
  89. DCHECK(rv == 0 || rv == EBUSY) << ". " << strerror(rv);
  90. return rv == 0;
  91. }
  92. void LockImpl::Unlock() {
  93. int rv = pthread_mutex_unlock(&native_handle_);
  94. DCHECK_EQ(rv, 0) << ". " << strerror(rv);
  95. }
  96. #endif
  97. // This is an implementation used for AutoLock templated on the lock type.
  98. template <class LockType>
  99. class SCOPED_LOCKABLE BasicAutoLock {
  100. public:
  101. struct AlreadyAcquired {};
  102. explicit BasicAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
  103. : lock_(lock) {
  104. lock_.Acquire();
  105. }
  106. BasicAutoLock(LockType& lock, const AlreadyAcquired&)
  107. EXCLUSIVE_LOCKS_REQUIRED(lock)
  108. : lock_(lock) {
  109. lock_.AssertAcquired();
  110. }
  111. ~BasicAutoLock() UNLOCK_FUNCTION() {
  112. lock_.AssertAcquired();
  113. lock_.Release();
  114. }
  115. private:
  116. LockType& lock_;
  117. DISALLOW_COPY_AND_ASSIGN(BasicAutoLock);
  118. };
  119. // This is an implementation used for AutoUnlock templated on the lock type.
  120. template <class LockType>
  121. class BasicAutoUnlock {
  122. public:
  123. explicit BasicAutoUnlock(LockType& lock) : lock_(lock) {
  124. // We require our caller to have the lock.
  125. lock_.AssertAcquired();
  126. lock_.Release();
  127. }
  128. ~BasicAutoUnlock() { lock_.Acquire(); }
  129. private:
  130. LockType& lock_;
  131. DISALLOW_COPY_AND_ASSIGN(BasicAutoUnlock);
  132. };
  133. // This is an implementation used for AutoLockMaybe templated on the lock type.
  134. template <class LockType>
  135. class SCOPED_LOCKABLE BasicAutoLockMaybe {
  136. public:
  137. explicit BasicAutoLockMaybe(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
  138. : lock_(lock) {
  139. if (lock_)
  140. lock_->Acquire();
  141. }
  142. ~BasicAutoLockMaybe() UNLOCK_FUNCTION() {
  143. if (lock_) {
  144. lock_->AssertAcquired();
  145. lock_->Release();
  146. }
  147. }
  148. private:
  149. LockType* const lock_;
  150. DISALLOW_COPY_AND_ASSIGN(BasicAutoLockMaybe);
  151. };
  152. // This is an implementation used for ReleasableAutoLock templated on the lock
  153. // type.
  154. template <class LockType>
  155. class SCOPED_LOCKABLE BasicReleasableAutoLock {
  156. public:
  157. explicit BasicReleasableAutoLock(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
  158. : lock_(lock) {
  159. DCHECK(lock_);
  160. lock_->Acquire();
  161. }
  162. ~BasicReleasableAutoLock() UNLOCK_FUNCTION() {
  163. if (lock_) {
  164. lock_->AssertAcquired();
  165. lock_->Release();
  166. }
  167. }
  168. void Release() UNLOCK_FUNCTION() {
  169. DCHECK(lock_);
  170. lock_->AssertAcquired();
  171. lock_->Release();
  172. lock_ = nullptr;
  173. }
  174. private:
  175. LockType* lock_;
  176. DISALLOW_COPY_AND_ASSIGN(BasicReleasableAutoLock);
  177. };
  178. } // namespace internal
  179. } // namespace base
  180. #endif // BASE_SYNCHRONIZATION_LOCK_IMPL_H_