text: // Copyright (c) 2011 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef BASE_SYNCHRONIZATION_LOCK_H_
  #define BASE_SYNCHRONIZATION_LOCK_H_
  
  #include "base/base_export.h"
  #include "base/logging.h"
  #include "base/macros.h"
  #include "base/synchronization/lock_impl.h"
  #include "base/threading/platform_thread.h"
  #include "build/build_config.h"
  
  namespace base {
  
  // A convenient wrapper for an OS specific critical section.  The only real
  // intelligence in this class is in debug mode for the support for the
  // AssertAcquired() method.
  class BASE_EXPORT Lock {
   public:
  #if !DCHECK_IS_ON()
     // Optimized wrapper implementation
    Lock() : lock_() {}
    ~Lock() {}
    void Acquire() { lock_.Lock(); }
    void Release() { lock_.Unlock(); }
  
    // If the lock is not held, take it and return true. If the lock is already
    // held by another thread, immediately return false. This must not be called
    // by a thread already holding the lock (what happens is undefined and an
    // assertion may fail).
    bool Try() { return lock_.Try(); }
  
    // Null implementation if not debug.
    void AssertAcquired() const {}
  #else
    Lock();
    ~Lock();
  
    // NOTE: We do not permit recursive locks and will commonly fire a DCHECK() if
    // a thread attempts to acquire the lock a second time (while already holding
    // it).
    void Acquire() {
      lock_.Lock();
      CheckUnheldAndMark();
    }
    void Release() {
      CheckHeldAndUnmark();
      lock_.Unlock();
    }
  
    bool Try() {
      bool rv = lock_.Try();
      if (rv) {
        CheckUnheldAndMark();
      }
      return rv;
    }
  
    void AssertAcquired() const;
  #endif  // DCHECK_IS_ON()
  
    // Whether Lock mitigates priority inversion when used from different thread
    // priorities.
    static bool HandlesMultipleThreadPriorities() {
  #if defined(OS_WIN)
      // Windows mitigates priority inversion by randomly boosting the priority of
      // ready threads.
      // https://msdn.microsoft.com/library/windows/desktop/ms684831.aspx
      return true;
  #elif defined(OS_POSIX) || defined(OS_FUCHSIA)
      // POSIX mitigates priority inversion by setting the priority of a thread
      // holding a Lock to the maximum priority of any other thread waiting on it.
      return internal::LockImpl::PriorityInheritanceAvailable();
  #else
  #error Unsupported platform
  #endif
    }
  
    // Both Windows and POSIX implementations of ConditionVariable need to be
    // able to see our lock and tweak our debugging counters, as they release and
    // acquire locks inside of their condition variable APIs.
    friend class ConditionVariable;
  
   private:
  #if DCHECK_IS_ON()
    // Members and routines taking care of locks assertions.
    // Note that this checks for recursive locks and allows them
    // if the variable is set.  This is allowed by the underlying implementation
    // on windows but not on Posix, so we're doing unneeded checks on Posix.
    // It's worth it to share the code.
    void CheckHeldAndUnmark();
    void CheckUnheldAndMark();
  
    // All private data is implicitly protected by lock_.
    // Be VERY careful to only access members under that lock.
    base::PlatformThreadRef owning_thread_ref_;
  #endif  // DCHECK_IS_ON()
  
    // Platform specific underlying lock implementation.
    internal::LockImpl lock_;
  
    DISALLOW_COPY_AND_ASSIGN(Lock);
  };
  
  // A helper class that acquires the given Lock while the AutoLock is in scope.
  class AutoLock {
   public:
    struct AlreadyAcquired {};
  
    explicit AutoLock(Lock& lock) : lock_(lock) {
      lock_.Acquire();
    }
  
    AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
      lock_.AssertAcquired();
    }
  
    ~AutoLock() {
      lock_.AssertAcquired();
      lock_.Release();
    }
  
   private:
    Lock& lock_;
    DISALLOW_COPY_AND_ASSIGN(AutoLock);
  };
  
  // AutoUnlock is a helper that will Release() the |lock| argument in the
  // constructor, and re-Acquire() it in the destructor.
  class AutoUnlock {
   public:
    explicit AutoUnlock(Lock& lock) : lock_(lock) {
      // We require our caller to have the lock.
      lock_.AssertAcquired();
      lock_.Release();
    }
  
    ~AutoUnlock() {
      lock_.Acquire();
    }
  
   private:
    Lock& lock_;
    DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
  };
  
  }  // namespace base
  
  #endif  // BASE_SYNCHRONIZATION_LOCK_H_
  