V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
mutex.h
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 "src/base/base-export.h"
9 #include "src/base/lazy-instance.h"
10 #if V8_OS_WIN
11 #include "src/base/win32-headers.h"
12 #endif
13 #include "src/base/logging.h"
14 
15 #if V8_OS_POSIX
16 #include <pthread.h> // NOLINT
17 #endif
18 
19 namespace v8 {
20 namespace base {
21 
22 // ----------------------------------------------------------------------------
23 // Mutex
24 //
25 // This class is a synchronization primitive that can be used to protect shared
26 // data from being simultaneously accessed by multiple threads. A mutex offers
27 // exclusive, non-recursive ownership semantics:
28 // - A calling thread owns a mutex from the time that it successfully calls
29 // either |Lock()| or |TryLock()| until it calls |Unlock()|.
30 // - When a thread owns a mutex, all other threads will block (for calls to
31 // |Lock()|) or receive a |false| return value (for |TryLock()|) if they
32 // attempt to claim ownership of the mutex.
33 // A calling thread must not own the mutex prior to calling |Lock()| or
34 // |TryLock()|. The behavior of a program is undefined if a mutex is destroyed
35 // while still owned by some thread. The Mutex class is non-copyable.
36 
37 class V8_BASE_EXPORT Mutex final {
38  public:
39  Mutex();
40  ~Mutex();
41 
42  // Locks the given mutex. If the mutex is currently unlocked, it becomes
43  // locked and owned by the calling thread, and immediately. If the mutex
44  // is already locked by another thread, suspends the calling thread until
45  // the mutex is unlocked.
46  void Lock();
47 
48  // Unlocks the given mutex. The mutex is assumed to be locked and owned by
49  // the calling thread on entrance.
50  void Unlock();
51 
52  // Tries to lock the given mutex. Returns whether the mutex was
53  // successfully locked.
54  bool TryLock() V8_WARN_UNUSED_RESULT;
55 
56  // The implementation-defined native handle type.
57 #if V8_OS_POSIX
58  typedef pthread_mutex_t NativeHandle;
59 #elif V8_OS_WIN
60  typedef SRWLOCK NativeHandle;
61 #endif
62 
63  NativeHandle& native_handle() {
64  return native_handle_;
65  }
66  const NativeHandle& native_handle() const {
67  return native_handle_;
68  }
69 
70  private:
71  NativeHandle native_handle_;
72 #ifdef DEBUG
73  int level_;
74 #endif
75 
76  V8_INLINE void AssertHeldAndUnmark() {
77 #ifdef DEBUG
78  DCHECK_EQ(1, level_);
79  level_--;
80 #endif
81  }
82 
83  V8_INLINE void AssertUnheldAndMark() {
84 #ifdef DEBUG
85  DCHECK_EQ(0, level_);
86  level_++;
87 #endif
88  }
89 
90  friend class ConditionVariable;
91 
92  DISALLOW_COPY_AND_ASSIGN(Mutex);
93 };
94 
95 // POD Mutex initialized lazily (i.e. the first time Pointer() is called).
96 // Usage:
97 // static LazyMutex my_mutex = LAZY_MUTEX_INITIALIZER;
98 //
99 // void my_function() {
100 // MutexGuard guard(my_mutex.Pointer());
101 // // Do something.
102 // }
103 //
106 
107 #define LAZY_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
108 
109 
110 // -----------------------------------------------------------------------------
111 // RecursiveMutex
112 //
113 // This class is a synchronization primitive that can be used to protect shared
114 // data from being simultaneously accessed by multiple threads. A recursive
115 // mutex offers exclusive, recursive ownership semantics:
116 // - A calling thread owns a recursive mutex for a period of time that starts
117 // when it successfully calls either |Lock()| or |TryLock()|. During this
118 // period, the thread may make additional calls to |Lock()| or |TryLock()|.
119 // The period of ownership ends when the thread makes a matching number of
120 // calls to |Unlock()|.
121 // - When a thread owns a recursive mutex, all other threads will block (for
122 // calls to |Lock()|) or receive a |false| return value (for |TryLock()|) if
123 // they attempt to claim ownership of the recursive mutex.
124 // - The maximum number of times that a recursive mutex may be locked is
125 // unspecified, but after that number is reached, calls to |Lock()| will
126 // probably abort the process and calls to |TryLock()| return false.
127 // The behavior of a program is undefined if a recursive mutex is destroyed
128 // while still owned by some thread. The RecursiveMutex class is non-copyable.
129 
130 class V8_BASE_EXPORT RecursiveMutex final {
131  public:
132  RecursiveMutex();
133  ~RecursiveMutex();
134 
135  // Locks the mutex. If another thread has already locked the mutex, a call to
136  // |Lock()| will block execution until the lock is acquired. A thread may call
137  // |Lock()| on a recursive mutex repeatedly. Ownership will only be released
138  // after the thread makes a matching number of calls to |Unlock()|.
139  // The behavior is undefined if the mutex is not unlocked before being
140  // destroyed, i.e. some thread still owns it.
141  void Lock();
142 
143  // Unlocks the mutex if its level of ownership is 1 (there was exactly one
144  // more call to |Lock()| than there were calls to unlock() made by this
145  // thread), reduces the level of ownership by 1 otherwise. The mutex must be
146  // locked by the current thread of execution, otherwise, the behavior is
147  // undefined.
148  void Unlock();
149 
150  // Tries to lock the given mutex. Returns whether the mutex was
151  // successfully locked.
152  bool TryLock() V8_WARN_UNUSED_RESULT;
153 
154  // The implementation-defined native handle type.
155 #if V8_OS_POSIX
156  typedef pthread_mutex_t NativeHandle;
157 #elif V8_OS_WIN
158  typedef CRITICAL_SECTION NativeHandle;
159 #endif
160 
161  NativeHandle& native_handle() {
162  return native_handle_;
163  }
164  const NativeHandle& native_handle() const {
165  return native_handle_;
166  }
167 
168  private:
169  NativeHandle native_handle_;
170 #ifdef DEBUG
171  int level_;
172 #endif
173 
174  DISALLOW_COPY_AND_ASSIGN(RecursiveMutex);
175 };
176 
177 
178 // POD RecursiveMutex initialized lazily (i.e. the first time Pointer() is
179 // called).
180 // Usage:
181 // static LazyRecursiveMutex my_mutex = LAZY_RECURSIVE_MUTEX_INITIALIZER;
182 //
183 // void my_function() {
184 // LockGuard<RecursiveMutex> guard(my_mutex.Pointer());
185 // // Do something.
186 // }
187 //
191 
192 #define LAZY_RECURSIVE_MUTEX_INITIALIZER LAZY_STATIC_INSTANCE_INITIALIZER
193 
194 
195 // -----------------------------------------------------------------------------
196 // LockGuard
197 //
198 // This class is a mutex wrapper that provides a convenient RAII-style mechanism
199 // for owning a mutex for the duration of a scoped block.
200 // When a LockGuard object is created, it attempts to take ownership of the
201 // mutex it is given. When control leaves the scope in which the LockGuard
202 // object was created, the LockGuard is destructed and the mutex is released.
203 // The LockGuard class is non-copyable.
204 
205 // Controls whether a LockGuard always requires a valid Mutex or will just
206 // ignore it if it's nullptr.
207 enum class NullBehavior { kRequireNotNull, kIgnoreIfNull };
208 
209 template <typename Mutex, NullBehavior Behavior = NullBehavior::kRequireNotNull>
210 class LockGuard final {
211  public:
212  explicit LockGuard(Mutex* mutex) : mutex_(mutex) {
213  if (Behavior == NullBehavior::kRequireNotNull || mutex_ != nullptr) {
214  mutex_->Lock();
215  }
216  }
217  ~LockGuard() {
218  if (mutex_ != nullptr) mutex_->Unlock();
219  }
220 
221  private:
222  Mutex* mutex_;
223 
224  DISALLOW_COPY_AND_ASSIGN(LockGuard);
225 };
226 
227 using MutexGuard = LockGuard<Mutex>;
228 
229 } // namespace base
230 } // namespace v8
231 
232 #endif // V8_BASE_PLATFORM_MUTEX_H_
Definition: libplatform.h:13