Home | History | Annotate | Download | only in synchronization
      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 
      5 #ifndef BASE_SYNCHRONIZATION_LOCK_H_
      6 #define BASE_SYNCHRONIZATION_LOCK_H_
      7 
      8 #include "base/base_export.h"
      9 #include "base/synchronization/lock_impl.h"
     10 #include "base/threading/platform_thread.h"
     11 
     12 namespace base {
     13 
     14 // A convenient wrapper for an OS specific critical section.  The only real
     15 // intelligence in this class is in debug mode for the support for the
     16 // AssertAcquired() method.
     17 class BASE_EXPORT Lock {
     18  public:
     19 #if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
     20    // Optimized wrapper implementation
     21   Lock() : lock_() {}
     22   ~Lock() {}
     23   void Acquire() { lock_.Lock(); }
     24   void Release() { lock_.Unlock(); }
     25 
     26   // If the lock is not held, take it and return true. If the lock is already
     27   // held by another thread, immediately return false. This must not be called
     28   // by a thread already holding the lock (what happens is undefined and an
     29   // assertion may fail).
     30   bool Try() { return lock_.Try(); }
     31 
     32   // Null implementation if not debug.
     33   void AssertAcquired() const {}
     34 #else
     35   Lock();
     36   ~Lock();
     37 
     38   // NOTE: Although windows critical sections support recursive locks, we do not
     39   // allow this, and we will commonly fire a DCHECK() if a thread attempts to
     40   // acquire the lock a second time (while already holding it).
     41   void Acquire() {
     42     lock_.Lock();
     43     CheckUnheldAndMark();
     44   }
     45   void Release() {
     46     CheckHeldAndUnmark();
     47     lock_.Unlock();
     48   }
     49 
     50   bool Try() {
     51     bool rv = lock_.Try();
     52     if (rv) {
     53       CheckUnheldAndMark();
     54     }
     55     return rv;
     56   }
     57 
     58   void AssertAcquired() const;
     59 #endif  // NDEBUG && !DCHECK_ALWAYS_ON
     60 
     61 #if defined(OS_POSIX)
     62   // The posix implementation of ConditionVariable needs to be able
     63   // to see our lock and tweak our debugging counters, as it releases
     64   // and acquires locks inside of pthread_cond_{timed,}wait.
     65   friend class ConditionVariable;
     66 #elif defined(OS_WIN)
     67   // The Windows Vista implementation of ConditionVariable needs the
     68   // native handle of the critical section.
     69   friend class WinVistaCondVar;
     70 #endif
     71 
     72  private:
     73 #if !defined(NDEBUG) || defined(DCHECK_ALWAYS_ON)
     74   // Members and routines taking care of locks assertions.
     75   // Note that this checks for recursive locks and allows them
     76   // if the variable is set.  This is allowed by the underlying implementation
     77   // on windows but not on Posix, so we're doing unneeded checks on Posix.
     78   // It's worth it to share the code.
     79   void CheckHeldAndUnmark();
     80   void CheckUnheldAndMark();
     81 
     82   // All private data is implicitly protected by lock_.
     83   // Be VERY careful to only access members under that lock.
     84   base::PlatformThreadRef owning_thread_ref_;
     85 #endif  // !NDEBUG || DCHECK_ALWAYS_ON
     86 
     87   // Platform specific underlying lock implementation.
     88   internal::LockImpl lock_;
     89 
     90   DISALLOW_COPY_AND_ASSIGN(Lock);
     91 };
     92 
     93 // A helper class that acquires the given Lock while the AutoLock is in scope.
     94 class AutoLock {
     95  public:
     96   struct AlreadyAcquired {};
     97 
     98   explicit AutoLock(Lock& lock) : lock_(lock) {
     99     lock_.Acquire();
    100   }
    101 
    102   AutoLock(Lock& lock, const AlreadyAcquired&) : lock_(lock) {
    103     lock_.AssertAcquired();
    104   }
    105 
    106   ~AutoLock() {
    107     lock_.AssertAcquired();
    108     lock_.Release();
    109   }
    110 
    111  private:
    112   Lock& lock_;
    113   DISALLOW_COPY_AND_ASSIGN(AutoLock);
    114 };
    115 
    116 // AutoUnlock is a helper that will Release() the |lock| argument in the
    117 // constructor, and re-Acquire() it in the destructor.
    118 class AutoUnlock {
    119  public:
    120   explicit AutoUnlock(Lock& lock) : lock_(lock) {
    121     // We require our caller to have the lock.
    122     lock_.AssertAcquired();
    123     lock_.Release();
    124   }
    125 
    126   ~AutoUnlock() {
    127     lock_.Acquire();
    128   }
    129 
    130  private:
    131   Lock& lock_;
    132   DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
    133 };
    134 
    135 }  // namespace base
    136 
    137 #endif  // BASE_SYNCHRONIZATION_LOCK_H_
    138