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 #include "src/base/platform/mutex.h"
6
7 #include <errno.h>
8
9 namespace v8 {
10 namespace base {
11
12 #if V8_OS_POSIX
13
InitializeNativeHandle(pthread_mutex_t * mutex)14 static V8_INLINE void InitializeNativeHandle(pthread_mutex_t* mutex) {
15 int result;
16 #if defined(DEBUG)
17 // Use an error checking mutex in debug mode.
18 pthread_mutexattr_t attr;
19 result = pthread_mutexattr_init(&attr);
20 DCHECK_EQ(0, result);
21 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
22 DCHECK_EQ(0, result);
23 result = pthread_mutex_init(mutex, &attr);
24 DCHECK_EQ(0, result);
25 result = pthread_mutexattr_destroy(&attr);
26 #else
27 // Use a fast mutex (default attributes).
28 result = pthread_mutex_init(mutex, nullptr);
29 #endif // defined(DEBUG)
30 DCHECK_EQ(0, result);
31 USE(result);
32 }
33
34
InitializeRecursiveNativeHandle(pthread_mutex_t * mutex)35 static V8_INLINE void InitializeRecursiveNativeHandle(pthread_mutex_t* mutex) {
36 pthread_mutexattr_t attr;
37 int result = pthread_mutexattr_init(&attr);
38 DCHECK_EQ(0, result);
39 result = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
40 DCHECK_EQ(0, result);
41 result = pthread_mutex_init(mutex, &attr);
42 DCHECK_EQ(0, result);
43 result = pthread_mutexattr_destroy(&attr);
44 DCHECK_EQ(0, result);
45 USE(result);
46 }
47
48
DestroyNativeHandle(pthread_mutex_t * mutex)49 static V8_INLINE void DestroyNativeHandle(pthread_mutex_t* mutex) {
50 int result = pthread_mutex_destroy(mutex);
51 DCHECK_EQ(0, result);
52 USE(result);
53 }
54
55
LockNativeHandle(pthread_mutex_t * mutex)56 static V8_INLINE void LockNativeHandle(pthread_mutex_t* mutex) {
57 int result = pthread_mutex_lock(mutex);
58 DCHECK_EQ(0, result);
59 USE(result);
60 }
61
62
UnlockNativeHandle(pthread_mutex_t * mutex)63 static V8_INLINE void UnlockNativeHandle(pthread_mutex_t* mutex) {
64 int result = pthread_mutex_unlock(mutex);
65 DCHECK_EQ(0, result);
66 USE(result);
67 }
68
69
TryLockNativeHandle(pthread_mutex_t * mutex)70 static V8_INLINE bool TryLockNativeHandle(pthread_mutex_t* mutex) {
71 int result = pthread_mutex_trylock(mutex);
72 if (result == EBUSY) {
73 return false;
74 }
75 DCHECK_EQ(0, result);
76 return true;
77 }
78
79
Mutex()80 Mutex::Mutex() {
81 InitializeNativeHandle(&native_handle_);
82 #ifdef DEBUG
83 level_ = 0;
84 #endif
85 }
86
87
~Mutex()88 Mutex::~Mutex() {
89 DestroyNativeHandle(&native_handle_);
90 DCHECK_EQ(0, level_);
91 }
92
93
Lock()94 void Mutex::Lock() {
95 LockNativeHandle(&native_handle_);
96 AssertUnheldAndMark();
97 }
98
99
Unlock()100 void Mutex::Unlock() {
101 AssertHeldAndUnmark();
102 UnlockNativeHandle(&native_handle_);
103 }
104
105
TryLock()106 bool Mutex::TryLock() {
107 if (!TryLockNativeHandle(&native_handle_)) {
108 return false;
109 }
110 AssertUnheldAndMark();
111 return true;
112 }
113
114
RecursiveMutex()115 RecursiveMutex::RecursiveMutex() {
116 InitializeRecursiveNativeHandle(&native_handle_);
117 #ifdef DEBUG
118 level_ = 0;
119 #endif
120 }
121
122
~RecursiveMutex()123 RecursiveMutex::~RecursiveMutex() {
124 DestroyNativeHandle(&native_handle_);
125 DCHECK_EQ(0, level_);
126 }
127
128
Lock()129 void RecursiveMutex::Lock() {
130 LockNativeHandle(&native_handle_);
131 #ifdef DEBUG
132 DCHECK_LE(0, level_);
133 level_++;
134 #endif
135 }
136
137
Unlock()138 void RecursiveMutex::Unlock() {
139 #ifdef DEBUG
140 DCHECK_LT(0, level_);
141 level_--;
142 #endif
143 UnlockNativeHandle(&native_handle_);
144 }
145
146
TryLock()147 bool RecursiveMutex::TryLock() {
148 if (!TryLockNativeHandle(&native_handle_)) {
149 return false;
150 }
151 #ifdef DEBUG
152 DCHECK_LE(0, level_);
153 level_++;
154 #endif
155 return true;
156 }
157
SharedMutex()158 SharedMutex::SharedMutex() { pthread_rwlock_init(&native_handle_, nullptr); }
159
~SharedMutex()160 SharedMutex::~SharedMutex() {
161 int result = pthread_rwlock_destroy(&native_handle_);
162 DCHECK_EQ(0, result);
163 USE(result);
164 }
165
LockShared()166 void SharedMutex::LockShared() {
167 int result = pthread_rwlock_rdlock(&native_handle_);
168 DCHECK_EQ(0, result);
169 USE(result);
170 }
171
LockExclusive()172 void SharedMutex::LockExclusive() {
173 int result = pthread_rwlock_wrlock(&native_handle_);
174 DCHECK_EQ(0, result);
175 USE(result);
176 }
177
UnlockShared()178 void SharedMutex::UnlockShared() {
179 int result = pthread_rwlock_unlock(&native_handle_);
180 DCHECK_EQ(0, result);
181 USE(result);
182 }
183
UnlockExclusive()184 void SharedMutex::UnlockExclusive() {
185 // Same code as {UnlockShared} on POSIX.
186 UnlockShared();
187 }
188
TryLockShared()189 bool SharedMutex::TryLockShared() {
190 return pthread_rwlock_tryrdlock(&native_handle_) == 0;
191 }
192
TryLockExclusive()193 bool SharedMutex::TryLockExclusive() {
194 return pthread_rwlock_trywrlock(&native_handle_) == 0;
195 }
196
197 #elif V8_OS_WIN
198
199 Mutex::Mutex() : native_handle_(SRWLOCK_INIT) {
200 #ifdef DEBUG
201 level_ = 0;
202 #endif
203 }
204
205
206 Mutex::~Mutex() {
207 DCHECK_EQ(0, level_);
208 }
209
210
211 void Mutex::Lock() {
212 AcquireSRWLockExclusive(&native_handle_);
213 AssertUnheldAndMark();
214 }
215
216
217 void Mutex::Unlock() {
218 AssertHeldAndUnmark();
219 ReleaseSRWLockExclusive(&native_handle_);
220 }
221
222
223 bool Mutex::TryLock() {
224 if (!TryAcquireSRWLockExclusive(&native_handle_)) {
225 return false;
226 }
227 AssertUnheldAndMark();
228 return true;
229 }
230
231
232 RecursiveMutex::RecursiveMutex() {
233 InitializeCriticalSection(&native_handle_);
234 #ifdef DEBUG
235 level_ = 0;
236 #endif
237 }
238
239
240 RecursiveMutex::~RecursiveMutex() {
241 DeleteCriticalSection(&native_handle_);
242 DCHECK_EQ(0, level_);
243 }
244
245
246 void RecursiveMutex::Lock() {
247 EnterCriticalSection(&native_handle_);
248 #ifdef DEBUG
249 DCHECK_LE(0, level_);
250 level_++;
251 #endif
252 }
253
254
255 void RecursiveMutex::Unlock() {
256 #ifdef DEBUG
257 DCHECK_LT(0, level_);
258 level_--;
259 #endif
260 LeaveCriticalSection(&native_handle_);
261 }
262
263
264 bool RecursiveMutex::TryLock() {
265 if (!TryEnterCriticalSection(&native_handle_)) {
266 return false;
267 }
268 #ifdef DEBUG
269 DCHECK_LE(0, level_);
270 level_++;
271 #endif
272 return true;
273 }
274
275 SharedMutex::SharedMutex() : native_handle_(SRWLOCK_INIT) {}
276
277 SharedMutex::~SharedMutex() {}
278
279 void SharedMutex::LockShared() { AcquireSRWLockShared(&native_handle_); }
280
281 void SharedMutex::LockExclusive() { AcquireSRWLockExclusive(&native_handle_); }
282
283 void SharedMutex::UnlockShared() { ReleaseSRWLockShared(&native_handle_); }
284
285 void SharedMutex::UnlockExclusive() {
286 ReleaseSRWLockExclusive(&native_handle_);
287 }
288
289 bool SharedMutex::TryLockShared() {
290 return TryAcquireSRWLockShared(&native_handle_);
291 }
292
293 bool SharedMutex::TryLockExclusive() {
294 return TryAcquireSRWLockExclusive(&native_handle_);
295 }
296
297 #elif V8_OS_STARBOARD
298
299 Mutex::Mutex() { SbMutexCreate(&native_handle_); }
300
301 Mutex::~Mutex() { SbMutexDestroy(&native_handle_); }
302
303 void Mutex::Lock() { SbMutexAcquire(&native_handle_); }
304
305 void Mutex::Unlock() { SbMutexRelease(&native_handle_); }
306
307 RecursiveMutex::RecursiveMutex() {}
308
309 RecursiveMutex::~RecursiveMutex() {}
310
311 void RecursiveMutex::Lock() { native_handle_.Acquire(); }
312
313 void RecursiveMutex::Unlock() { native_handle_.Release(); }
314
315 bool RecursiveMutex::TryLock() { return native_handle_.AcquireTry(); }
316
317 SharedMutex::SharedMutex() = default;
318
319 SharedMutex::~SharedMutex() = default;
320
321 void SharedMutex::LockShared() { native_handle_.AcquireReadLock(); }
322
323 void SharedMutex::LockExclusive() { native_handle_.AcquireWriteLock(); }
324
325 void SharedMutex::UnlockShared() { native_handle_.ReleaseReadLock(); }
326
327 void SharedMutex::UnlockExclusive() { native_handle_.ReleaseWriteLock(); }
328
329 bool SharedMutex::TryLockShared() { return false; }
330
331 bool SharedMutex::TryLockExclusive() { return false; }
332 #endif // V8_OS_STARBOARD
333
334 } // namespace base
335 } // namespace v8
336