blob: 00095ab3afea8aef847ebd2c362ba5a925d2debc (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
|
// 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/thread_annotations.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 LOCKABLE BASE_EXPORT Lock {
public:
#if !DCHECK_IS_ON()
// Optimized wrapper implementation
Lock() : lock_() {}
~Lock() {}
// TODO(lukasza): https://crbug.com/831825: Add EXCLUSIVE_LOCK_FUNCTION
// annotation to Acquire method and similar annotations to Release and Try
// methods (here and in the #else branch).
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 ASSERT_EXCLUSIVE_LOCK() {}
#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 ASSERT_EXCLUSIVE_LOCK();
#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.
using AutoLock = internal::BasicAutoLock<Lock>;
// AutoUnlock is a helper that will Release() the |lock| argument in the
// constructor, and re-Acquire() it in the destructor.
using AutoUnlock = internal::BasicAutoUnlock<Lock>;
// Like AutoLock but is a no-op when the provided Lock* is null. Inspired from
// absl::MutexLockMaybe. Use this instead of base::Optional<base::AutoLock> to
// get around -Wthread-safety-analysis warnings for conditional locking.
using AutoLockMaybe = internal::BasicAutoLockMaybe<Lock>;
// Like AutoLock but permits Release() of its mutex before destruction.
// Release() may be called at most once. Inspired from
// absl::ReleasableMutexLock. Use this instead of base::Optional<base::AutoLock>
// to get around -Wthread-safety-analysis warnings for AutoLocks that are
// explicitly released early (prefer proper scoping to this).
using ReleasableAutoLock = internal::BasicReleasableAutoLock<Lock>;
} // namespace base
#endif // BASE_SYNCHRONIZATION_LOCK_H_
|