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
13namespace 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.
18class 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.
95class 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.
113class 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