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