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 #pragma once
      8 
      9 #include "base/base_api.h"
     10 #include "base/synchronization/lock_impl.h"
     11 #include "base/threading/platform_thread.h"
     12 
     13 namespace base {
     14 
     15 // A convenient wrapper for an OS specific critical section.  The only real
     16 // intelligence in this class is in debug mode for the support for the
     17 // AssertAcquired() method.
     18 class BASE_API Lock {
     19  public:
     20 #if defined(NDEBUG)             // 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
     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   // Windows doesn't need to do this as it calls the Lock::* methods.
     66   friend class ConditionVariable;
     67 #endif
     68 
     69  private:
     70 #if !defined(NDEBUG)
     71   // Members and routines taking care of locks assertions.
     72   // Note that this checks for recursive locks and allows them
     73   // if the variable is set.  This is allowed by the underlying implementation
     74   // on windows but not on Posix, so we're doing unneeded checks on Posix.
     75   // It's worth it to share the code.
     76   void CheckHeldAndUnmark();
     77   void CheckUnheldAndMark();
     78 
     79   // All private data is implicitly protected by lock_.
     80   // Be VERY careful to only access members under that lock.
     81 
     82   // Determines validity of owning_thread_id_.  Needed as we don't have
     83   // a null owning_thread_id_ value.
     84   bool owned_by_thread_;
     85   base::PlatformThreadId owning_thread_id_;
     86 #endif  // NDEBUG
     87 
     88   // Platform specific underlying lock implementation.
     89   internal::LockImpl lock_;
     90 
     91   DISALLOW_COPY_AND_ASSIGN(Lock);
     92 };
     93 
     94 // A helper class that acquires the given Lock while the AutoLock is in scope.
     95 class AutoLock {
     96  public:
     97   explicit AutoLock(Lock& lock) : lock_(lock) {
     98     lock_.Acquire();
     99   }
    100 
    101   ~AutoLock() {
    102     lock_.AssertAcquired();
    103     lock_.Release();
    104   }
    105 
    106  private:
    107   Lock& lock_;
    108   DISALLOW_COPY_AND_ASSIGN(AutoLock);
    109 };
    110 
    111 // AutoUnlock is a helper that will Release() the |lock| argument in the
    112 // constructor, and re-Acquire() it in the destructor.
    113 class AutoUnlock {
    114  public:
    115   explicit AutoUnlock(Lock& lock) : lock_(lock) {
    116     // We require our caller to have the lock.
    117     lock_.AssertAcquired();
    118     lock_.Release();
    119   }
    120 
    121   ~AutoUnlock() {
    122     lock_.Acquire();
    123   }
    124 
    125  private:
    126   Lock& lock_;
    127   DISALLOW_COPY_AND_ASSIGN(AutoUnlock);
    128 };
    129 
    130 }  // namespace base
    131 
    132 #endif  // BASE_SYNCHRONIZATION_LOCK_H_
    133