v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
mutex.h
Go to the documentation of this file.
1// Copyright 2013 the V8 project 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 V8_BASE_PLATFORM_MUTEX_H_
6#define V8_BASE_PLATFORM_MUTEX_H_
7
8#include <optional>
9
10#include "absl/synchronization/mutex.h"
11#include "include/v8config.h"
12
15#include "src/base/logging.h"
16
17namespace v8 {
18namespace base {
19
20class ConditionVariable;
21
22// Mutex - a replacement for std::mutex
23//
24// This class is a synchronization primitive that can be used to protect shared
25// data from being simultaneously accessed by multiple threads. A mutex offers
26// exclusive, non-recursive ownership semantics:
27// - A calling thread owns a mutex from the time that it successfully calls
28// either |Lock()| or |TryLock()| until it calls |Unlock()|.
29// - When a thread owns a mutex, all other threads will block (for calls to
30// |Lock()|) or receive a |false| return value (for |TryLock()|) if they
31// attempt to claim ownership of the mutex.
32// A calling thread must not own the mutex prior to calling |Lock()| or
33// |TryLock()|. The behavior of a program is undefined if a mutex is destroyed
34// while still owned by some thread. The Mutex class is non-copyable.
35
36class V8_BASE_EXPORT Mutex final {
37 public:
38 Mutex();
39 Mutex(const Mutex&) = delete;
40 Mutex& operator=(const Mutex&) = delete;
41 ~Mutex();
42
43 // Locks the given mutex. If the mutex is currently unlocked, it becomes
44 // locked and owned by the calling thread, and immediately. If the mutex
45 // is already locked by another thread, suspends the calling thread until
46 // the mutex is unlocked.
47 void Lock();
48
49 // Unlocks the given mutex. The mutex is assumed to be locked and owned by
50 // the calling thread on entrance.
51 void Unlock();
52
53 // Tries to lock the given mutex. Returns whether the mutex was
54 // successfully locked.
55 // Note: Instead of `DCHECK(!mutex.TryLock())` use `mutex.AssertHeld()`.
56 bool TryLock() V8_WARN_UNUSED_RESULT;
57
58 V8_INLINE void AssertHeld() const {
59 // If this access results in a race condition being detected by TSan, this
60 // means that you in fact did *not* hold the mutex.
61 DCHECK_EQ(1, level_);
62 }
63
64 private:
65#ifdef DEBUG
66 // This is being used for Assert* methods. Accesses are only allowed if you
67 // actually hold the mutex, otherwise you would get race conditions.
68 int level_;
69#endif
70
72#ifdef DEBUG
73 // If this access results in a race condition being detected by TSan, this
74 // means that you in fact did *not* hold the mutex.
75 DCHECK_EQ(1, level_);
76 level_--;
77#endif
78 }
79
81#ifdef DEBUG
82 // This is only invoked *after* actually getting the mutex, so should not
83 // result in race conditions.
84 DCHECK_EQ(0, level_);
85 level_++;
86#endif
87 }
88
89 friend class ConditionVariable;
90
91 absl::Mutex native_handle_;
92};
93
94// POD Mutex initialized lazily (i.e. the first time Pointer() is called).
95// Usage:
96// static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER;
97//
98// void my_function() {
99// MutexGuard guard(my_mutex.Pointer());
100// // Do something.
101// }
102//
105#define LAZY_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
106
107// RecursiveMutex - a replacement for std::recursive_mutex
108//
109// This class is a synchronization primitive that can be used to protect shared
110// data from being simultaneously accessed by multiple threads. A recursive
111// mutex offers exclusive, recursive ownership semantics:
112// - A calling thread owns a recursive mutex for a period of time that starts
113// when it successfully calls either |Lock()| or |TryLock()|. During this
114// period, the thread may make additional calls to |Lock()| or |TryLock()|.
115// The period of ownership ends when the thread makes a matching number of
116// calls to |Unlock()|.
117// - When a thread owns a recursive mutex, all other threads will block (for
118// calls to |Lock()|) or receive a |false| return value (for |TryLock()|) if
119// they attempt to claim ownership of the recursive mutex.
120// - The maximum number of times that a recursive mutex may be locked is
121// unspecified, but after that number is reached, calls to |Lock()| will
122// probably abort the process and calls to |TryLock()| return false.
123// The behavior of a program is undefined if a recursive mutex is destroyed
124// while still owned by some thread. The RecursiveMutex class is non-copyable.
125
127 public:
128 RecursiveMutex() = default;
132
133 // Locks the mutex. If another thread has already locked the mutex, a call to
134 // |Lock()| will block execution until the lock is acquired. A thread may call
135 // |Lock()| on a recursive mutex repeatedly. Ownership will only be released
136 // after the thread makes a matching number of calls to |Unlock()|.
137 // The behavior is undefined if the mutex is not unlocked before being
138 // destroyed, i.e. some thread still owns it.
139 void Lock();
140
141 // Unlocks the mutex if its level of ownership is 1 (there was exactly one
142 // more call to |Lock()| than there were calls to unlock() made by this
143 // thread), reduces the level of ownership by 1 otherwise. The mutex must be
144 // locked by the current thread of execution, otherwise, the behavior is
145 // undefined.
146 void Unlock();
147
148 // Tries to lock the given mutex. Returns whether the mutex was
149 // successfully locked.
150 // Note: Instead of `DCHECK(!mutex.TryLock())` use `mutex.AssertHeld()`.
151 bool TryLock() V8_WARN_UNUSED_RESULT;
152
153 V8_INLINE void AssertHeld() const {
154 // If this access results in a race condition being detected by TSan, this
155 // mean that you in fact did *not* hold the mutex.
156 DCHECK_LT(0, level_);
157 }
158
159 private:
160 std::atomic<int> thread_id_ = 0;
161 int level_ = 0;
163};
164
165
166// POD RecursiveMutex initialized lazily (i.e. the first time Pointer() is
167// called).
168// Usage:
169// static LazyRecursiveMutex my_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
170//
171// void my_function() {
172// LockGuard<RecursiveMutex> guard(my_mutex.Pointer());
173// // Do something.
174// }
175//
179
180#define LAZY_RECURSIVE_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
181
182// LockGuard
183//
184// This class is a mutex wrapper that provides a convenient RAII-style mechanism
185// for owning a mutex for the duration of a scoped block.
186// When a LockGuard object is created, it attempts to take ownership of the
187// mutex it is given. When control leaves the scope in which the LockGuard
188// object was created, the LockGuard is destructed and the mutex is released.
189// The LockGuard class is non-copyable.
190
191template <typename Mutex>
193 public:
196 mutex_->Lock();
197 }
199 // `mutex_` is guaranteed to be non-null here.
200 mutex_->Lock();
201 }
202 LockGuard(const LockGuard&) = delete;
203 LockGuard& operator=(const LockGuard&) = delete;
204 LockGuard(LockGuard&& other) V8_NOEXCEPT : mutex_(other.mutex_) {
206 other.mutex_ = nullptr;
207 }
209 if (mutex_) {
210 // mutex_ may have been moved away.
211 mutex_->Unlock();
212 }
213 }
214
215 private:
217};
218
221
223 public:
224 MutexGuardIf(Mutex* mutex, bool enable_mutex) {
225 if (enable_mutex) {
226 mutex_.emplace(mutex);
227 }
228 }
229 MutexGuardIf(const MutexGuardIf&) = delete;
231
232 private:
233 std::optional<MutexGuard> mutex_;
234};
235
236} // namespace base
237} // namespace v8
238
239#endif // V8_BASE_PLATFORM_MUTEX_H_
#define V8_BASE_EXPORT
Definition base-export.h:26
LockGuard(const LockGuard &)=delete
LockGuard(Mutex &mutex)
Definition mutex.h:198
LockGuard & operator=(const LockGuard &)=delete
LockGuard(LockGuard &&other) V8_NOEXCEPT
Definition mutex.h:204
LockGuard(Mutex *mutex)
Definition mutex.h:194
MutexGuardIf(Mutex *mutex, bool enable_mutex)
Definition mutex.h:224
MutexGuardIf & operator=(const MutexGuardIf &)=delete
std::optional< MutexGuard > mutex_
Definition mutex.h:233
MutexGuardIf(const MutexGuardIf &)=delete
Mutex(const Mutex &)=delete
V8_INLINE void AssertUnheldAndMark()
Definition mutex.h:80
absl::Mutex native_handle_
Definition mutex.h:91
V8_INLINE void AssertHeldAndUnmark()
Definition mutex.h:71
Mutex & operator=(const Mutex &)=delete
RecursiveMutex(const RecursiveMutex &)=delete
RecursiveMutex & operator=(const RecursiveMutex &)=delete
base::Mutex & mutex_
base::Mutex mutex
#define V8_NOEXCEPT
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_LT(v1, v2)
Definition logging.h:489
#define DCHECK_EQ(v1, v2)
Definition logging.h:485
#define V8_INLINE
Definition v8config.h:500
#define V8_WARN_UNUSED_RESULT
Definition v8config.h:671
#define V8_NODISCARD
Definition v8config.h:693
wasm::ValueType type