tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

lock_impl.h (6662B)


      1 // Copyright 2011 The Chromium Authors
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef BASE_SYNCHRONIZATION_LOCK_IMPL_H_
      6 #define BASE_SYNCHRONIZATION_LOCK_IMPL_H_
      7 
      8 #include "base/base_export.h"
      9 #include "base/check.h"
     10 #include "base/dcheck_is_on.h"
     11 #include "base/thread_annotations.h"
     12 #include "build/build_config.h"
     13 
     14 #if BUILDFLAG(IS_WIN)
     15 #include "base/win/windows_types.h"
     16 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
     17 #include <errno.h>
     18 #include <pthread.h>
     19 #include <string.h>
     20 #endif
     21 
     22 namespace base {
     23 class Lock;
     24 class ConditionVariable;
     25 
     26 namespace win {
     27 namespace internal {
     28 class AutoNativeLock;
     29 class ScopedHandleVerifier;
     30 }  // namespace internal
     31 }  // namespace win
     32 
     33 namespace internal {
     34 
     35 // This class implements the underlying platform-specific spin-lock mechanism
     36 // used for the Lock class. Do not use, use Lock instead.
     37 class BASE_EXPORT LockImpl {
     38 public:
     39  LockImpl(const LockImpl&) = delete;
     40  LockImpl& operator=(const LockImpl&) = delete;
     41 
     42 private:
     43  friend class base::Lock;
     44  friend class base::ConditionVariable;
     45  friend class base::win::internal::AutoNativeLock;
     46  friend class base::win::internal::ScopedHandleVerifier;
     47 
     48 #if BUILDFLAG(IS_WIN)
     49  using NativeHandle = CHROME_SRWLOCK;
     50 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
     51  using NativeHandle = pthread_mutex_t;
     52 #endif
     53 
     54  LockImpl();
     55  ~LockImpl();
     56 
     57  // If the lock is not held, take it and return true.  If the lock is already
     58  // held by something else, immediately return false.
     59  inline bool Try();
     60 
     61  // Take the lock, blocking until it is available if necessary.
     62  inline void Lock();
     63 
     64  // Release the lock.  This must only be called by the lock's holder: after
     65  // a successful call to Try, or a call to Lock.
     66  inline void Unlock();
     67 
     68  // Return the native underlying lock.
     69  // TODO(awalker): refactor lock and condition variables so that this is
     70  // unnecessary.
     71  NativeHandle* native_handle() { return &native_handle_; }
     72 
     73 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
     74  // Whether this lock will attempt to use priority inheritance.
     75  static bool PriorityInheritanceAvailable();
     76 #endif
     77 
     78  void LockInternal();
     79  NativeHandle native_handle_;
     80 };
     81 
     82 void LockImpl::Lock() {
     83  // Try the lock first to acquire it cheaply if it's not contended. Try() is
     84  // cheap on platforms with futex-type locks, as it doesn't call into the
     85  // kernel. Not marked LIKELY(), as:
     86  // 1. We don't know how much contention the lock would experience
     87  // 2. This may lead to weird-looking code layout when inlined into a caller
     88  // with (UN)LIKELY() annotations.
     89  if (Try()) {
     90    return;
     91  }
     92 
     93  LockInternal();
     94 }
     95 
     96 #if BUILDFLAG(IS_WIN)
     97 bool LockImpl::Try() {
     98  return !!::TryAcquireSRWLockExclusive(
     99      reinterpret_cast<PSRWLOCK>(&native_handle_));
    100 }
    101 
    102 void LockImpl::Unlock() {
    103  ::ReleaseSRWLockExclusive(reinterpret_cast<PSRWLOCK>(&native_handle_));
    104 }
    105 
    106 #elif BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
    107 
    108 #if DCHECK_IS_ON()
    109 BASE_EXPORT void dcheck_trylock_result(int rv);
    110 BASE_EXPORT void dcheck_unlock_result(int rv);
    111 #endif
    112 
    113 bool LockImpl::Try() {
    114  int rv = pthread_mutex_trylock(&native_handle_);
    115 #if DCHECK_IS_ON()
    116  dcheck_trylock_result(rv);
    117 #endif
    118  return rv == 0;
    119 }
    120 
    121 void LockImpl::Unlock() {
    122  [[maybe_unused]] int rv = pthread_mutex_unlock(&native_handle_);
    123 #if DCHECK_IS_ON()
    124  dcheck_unlock_result(rv);
    125 #endif
    126 }
    127 #endif
    128 
    129 // This is an implementation used for AutoLock templated on the lock type.
    130 template <class LockType>
    131 class SCOPED_LOCKABLE BasicAutoLock {
    132 public:
    133  struct AlreadyAcquired {};
    134 
    135  explicit BasicAutoLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
    136      : lock_(lock) {
    137    lock_.Acquire();
    138  }
    139 
    140  BasicAutoLock(LockType& lock, const AlreadyAcquired&)
    141      EXCLUSIVE_LOCKS_REQUIRED(lock)
    142      : lock_(lock) {
    143    lock_.AssertAcquired();
    144  }
    145 
    146  BasicAutoLock(const BasicAutoLock&) = delete;
    147  BasicAutoLock& operator=(const BasicAutoLock&) = delete;
    148 
    149  ~BasicAutoLock() UNLOCK_FUNCTION() {
    150    lock_.AssertAcquired();
    151    lock_.Release();
    152  }
    153 
    154 private:
    155  LockType& lock_;
    156 };
    157 
    158 // This is an implementation used for AutoTryLock templated on the lock type.
    159 template <class LockType>
    160 class SCOPED_LOCKABLE BasicAutoTryLock {
    161 public:
    162  explicit BasicAutoTryLock(LockType& lock) EXCLUSIVE_LOCK_FUNCTION(lock)
    163      : lock_(lock), is_acquired_(lock_.Try()) {}
    164 
    165  BasicAutoTryLock(const BasicAutoTryLock&) = delete;
    166  BasicAutoTryLock& operator=(const BasicAutoTryLock&) = delete;
    167 
    168  ~BasicAutoTryLock() UNLOCK_FUNCTION() {
    169    if (is_acquired_) {
    170      lock_.AssertAcquired();
    171      lock_.Release();
    172    }
    173  }
    174 
    175  bool is_acquired() const { return is_acquired_; }
    176 
    177 private:
    178  LockType& lock_;
    179  const bool is_acquired_;
    180 };
    181 
    182 // This is an implementation used for AutoUnlock templated on the lock type.
    183 template <class LockType>
    184 class BasicAutoUnlock {
    185 public:
    186  explicit BasicAutoUnlock(LockType& lock) : lock_(lock) {
    187    // We require our caller to have the lock.
    188    lock_.AssertAcquired();
    189    lock_.Release();
    190  }
    191 
    192  BasicAutoUnlock(const BasicAutoUnlock&) = delete;
    193  BasicAutoUnlock& operator=(const BasicAutoUnlock&) = delete;
    194 
    195  ~BasicAutoUnlock() { lock_.Acquire(); }
    196 
    197 private:
    198  LockType& lock_;
    199 };
    200 
    201 // This is an implementation used for AutoLockMaybe templated on the lock type.
    202 template <class LockType>
    203 class SCOPED_LOCKABLE BasicAutoLockMaybe {
    204 public:
    205  explicit BasicAutoLockMaybe(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
    206      : lock_(lock) {
    207    if (lock_)
    208      lock_->Acquire();
    209  }
    210 
    211  BasicAutoLockMaybe(const BasicAutoLockMaybe&) = delete;
    212  BasicAutoLockMaybe& operator=(const BasicAutoLockMaybe&) = delete;
    213 
    214  ~BasicAutoLockMaybe() UNLOCK_FUNCTION() {
    215    if (lock_) {
    216      lock_->AssertAcquired();
    217      lock_->Release();
    218    }
    219  }
    220 
    221 private:
    222  LockType* const lock_;
    223 };
    224 
    225 // This is an implementation used for ReleasableAutoLock templated on the lock
    226 // type.
    227 template <class LockType>
    228 class SCOPED_LOCKABLE BasicReleasableAutoLock {
    229 public:
    230  explicit BasicReleasableAutoLock(LockType* lock) EXCLUSIVE_LOCK_FUNCTION(lock)
    231      : lock_(lock) {
    232    DCHECK(lock_);
    233    lock_->Acquire();
    234  }
    235 
    236  BasicReleasableAutoLock(const BasicReleasableAutoLock&) = delete;
    237  BasicReleasableAutoLock& operator=(const BasicReleasableAutoLock&) = delete;
    238 
    239  ~BasicReleasableAutoLock() UNLOCK_FUNCTION() {
    240    if (lock_) {
    241      lock_->AssertAcquired();
    242      lock_->Release();
    243    }
    244  }
    245 
    246  void Release() UNLOCK_FUNCTION() {
    247    DCHECK(lock_);
    248    lock_->AssertAcquired();
    249    lock_->Release();
    250    lock_ = nullptr;
    251  }
    252 
    253 private:
    254  LockType* lock_;
    255 };
    256 
    257 }  // namespace internal
    258 }  // namespace base
    259 
    260 #endif  // BASE_SYNCHRONIZATION_LOCK_IMPL_H_