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 
158 #elif V8_OS_WIN
159 
160 Mutex::Mutex() : native_handle_(SRWLOCK_INIT) {
161 #ifdef DEBUG
162   level_ = 0;
163 #endif
164 }
165 
166 
167 Mutex::~Mutex() {
168   DCHECK_EQ(0, level_);
169 }
170 
171 
172 void Mutex::Lock() {
173   AcquireSRWLockExclusive(&native_handle_);
174   AssertUnheldAndMark();
175 }
176 
177 
178 void Mutex::Unlock() {
179   AssertHeldAndUnmark();
180   ReleaseSRWLockExclusive(&native_handle_);
181 }
182 
183 
184 bool Mutex::TryLock() {
185   if (!TryAcquireSRWLockExclusive(&native_handle_)) {
186     return false;
187   }
188   AssertUnheldAndMark();
189   return true;
190 }
191 
192 
193 RecursiveMutex::RecursiveMutex() {
194   InitializeCriticalSection(&native_handle_);
195 #ifdef DEBUG
196   level_ = 0;
197 #endif
198 }
199 
200 
201 RecursiveMutex::~RecursiveMutex() {
202   DeleteCriticalSection(&native_handle_);
203   DCHECK_EQ(0, level_);
204 }
205 
206 
207 void RecursiveMutex::Lock() {
208   EnterCriticalSection(&native_handle_);
209 #ifdef DEBUG
210   DCHECK_LE(0, level_);
211   level_++;
212 #endif
213 }
214 
215 
216 void RecursiveMutex::Unlock() {
217 #ifdef DEBUG
218   DCHECK_LT(0, level_);
219   level_--;
220 #endif
221   LeaveCriticalSection(&native_handle_);
222 }
223 
224 
225 bool RecursiveMutex::TryLock() {
226   if (!TryEnterCriticalSection(&native_handle_)) {
227     return false;
228   }
229 #ifdef DEBUG
230   DCHECK_LE(0, level_);
231   level_++;
232 #endif
233   return true;
234 }
235 
236 #endif  // V8_OS_POSIX
237 
238 }  // namespace base
239 }  // namespace v8
240