1 // Copyright 2010-2018, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 #include "base/mutex.h"
31
32 #ifdef OS_WIN
33 #include <Windows.h>
34 #else
35 #include <pthread.h>
36 #endif
37
38 #include <atomic>
39
40 #include "base/port.h"
41
42 #if defined(OS_WIN)
43 // We do not use pthread on Windows
44 #elif defined(OS_NACL)
45 // TODO(team): Consider to use glibc rwlock.
46 #else
47 #define MOZC_PTHREAD_HAS_READER_WRITER_LOCK
48 #endif
49
50 namespace mozc {
51 namespace {
52
53 // State for once_t.
54 enum CallOnceState {
55 ONCE_INIT = 0,
56 ONCE_RUNNING = 1,
57 ONCE_DONE = 2,
58 };
59
60 } // namespace
61
62 #ifdef OS_WIN // Hereafter, we have Win32 implementations
63 namespace {
64
65 template <typename T>
AsCriticalSection(T * opaque_buffer)66 CRITICAL_SECTION *AsCriticalSection(T* opaque_buffer) {
67 static_assert(sizeof(T) >= sizeof(CRITICAL_SECTION),
68 "The opaque buffer must have sufficient space to store a "
69 "CRITICAL_SECTION structure");
70 return reinterpret_cast<CRITICAL_SECTION *>(opaque_buffer);
71 }
72
73 template <typename T>
AsSRWLock(T * opaque_buffer)74 SRWLOCK *AsSRWLock(T* opaque_buffer) {
75 static_assert(sizeof(T) >= sizeof(SRWLOCK),
76 "The opaque buffer must have sufficient space to store a "
77 "SRWLOCK structure");
78 return reinterpret_cast<SRWLOCK *>(opaque_buffer);
79 }
80
81 } // namespace
82
Mutex()83 Mutex::Mutex() {
84 ::InitializeCriticalSection(AsCriticalSection(&opaque_buffer_));
85 }
86
~Mutex()87 Mutex::~Mutex() {
88 ::DeleteCriticalSection(AsCriticalSection(&opaque_buffer_));
89 }
90
Lock()91 void Mutex::Lock() {
92 ::EnterCriticalSection(AsCriticalSection(&opaque_buffer_));
93 }
94
TryLock()95 bool Mutex::TryLock() {
96 return ::TryEnterCriticalSection(AsCriticalSection(&opaque_buffer_)) != FALSE;
97 }
98
Unlock()99 void Mutex::Unlock() {
100 ::LeaveCriticalSection(AsCriticalSection(&opaque_buffer_));
101 }
102
ReaderWriterMutex()103 ReaderWriterMutex::ReaderWriterMutex() {
104 ::InitializeSRWLock(AsSRWLock(&opaque_buffer_));
105 }
106
~ReaderWriterMutex()107 ReaderWriterMutex::~ReaderWriterMutex() {
108 }
109
ReaderLock()110 void ReaderWriterMutex::ReaderLock() {
111 ::AcquireSRWLockShared(AsSRWLock(&opaque_buffer_));
112 }
113
WriterLock()114 void ReaderWriterMutex::WriterLock() {
115 ::AcquireSRWLockExclusive(AsSRWLock(&opaque_buffer_));
116 }
117
ReaderUnlock()118 void ReaderWriterMutex::ReaderUnlock() {
119 ::ReleaseSRWLockShared(AsSRWLock(&opaque_buffer_));
120 }
121
WriterUnlock()122 void ReaderWriterMutex::WriterUnlock() {
123 ::ReleaseSRWLockExclusive(AsSRWLock(&opaque_buffer_));
124 }
125
MultipleReadersThreadsSupported()126 bool ReaderWriterMutex::MultipleReadersThreadsSupported() {
127 return true;
128 }
129
130 #else // Hereafter, we have pthread-based implementation
131
132 namespace {
133
134 template <typename T>
AsPthreadMutexT(T * opaque_buffer)135 pthread_mutex_t *AsPthreadMutexT(T* opaque_buffer) {
136 static_assert(sizeof(T) >= sizeof(pthread_mutex_t),
137 "The opaque buffer must have sufficient space to store a "
138 "pthread_mutex_t structure");
139 return reinterpret_cast<pthread_mutex_t *>(opaque_buffer);
140 }
141
142 } // namespace
143
Mutex()144 Mutex::Mutex() {
145 // make RECURSIVE lock:
146 // The default is no-recursive lock.
147 // When mutex.Lock() is called while the mutex is already locked,
148 // mutex will be blocked. This behavior is not compatible with windows.
149 // We set PTHREAD_MUTEX_RECURSIVE_NP to make the mutex recursive-lock
150
151 // PTHREAD_MUTEX_RECURSIVE_NP and PTHREAD_MUTEX_RECURSIVE seem to be
152 // variants. For example, Mac OS X 10.4 had
153 // PTHREAD_MUTEX_RECURSIVE_NP but Mac OS X 10.5 does not
154 pthread_mutexattr_t attr;
155 pthread_mutexattr_init(&attr);
156 #if defined(OS_MACOSX) || defined(OS_DRAGONFLY)
157 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
158 #elif defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_NACL)
159 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE_NP);
160 #else
161 #error "This platform is not supported."
162 #endif
163 pthread_mutex_init(AsPthreadMutexT(&opaque_buffer_), &attr);
164 }
165
~Mutex()166 Mutex::~Mutex() {
167 pthread_mutex_destroy(AsPthreadMutexT(&opaque_buffer_));
168 }
169
Lock()170 void Mutex::Lock() {
171 pthread_mutex_lock(AsPthreadMutexT(&opaque_buffer_));
172 }
173
TryLock()174 bool Mutex::TryLock() {
175 return pthread_mutex_trylock(AsPthreadMutexT(&opaque_buffer_)) == 0;
176 }
177
Unlock()178 void Mutex::Unlock() {
179 pthread_mutex_unlock(AsPthreadMutexT(&opaque_buffer_));
180 }
181
182 #ifdef MOZC_USE_PEPPER_FILE_IO
raw_mutex()183 pthread_mutex_t *Mutex::raw_mutex() {
184 return AsPthreadMutexT(&opaque_buffer_);
185 }
186 #endif // MOZC_USE_PEPPER_FILE_IO
187
188 #ifdef MOZC_PTHREAD_HAS_READER_WRITER_LOCK
189 // Use pthread native reader writer lock.
190 namespace {
191
192 template <typename T>
AsPthreadRWLockT(T * opaque_buffer)193 pthread_rwlock_t *AsPthreadRWLockT(T* opaque_buffer) {
194 static_assert(sizeof(T) >= sizeof(pthread_rwlock_t),
195 "The opaque buffer must have sufficient space to store a "
196 "pthread_rwlock_t structure");
197 return reinterpret_cast<pthread_rwlock_t *>(opaque_buffer);
198 }
199
200 } // namespace
201
ReaderWriterMutex()202 ReaderWriterMutex::ReaderWriterMutex() {
203 pthread_rwlock_init(AsPthreadRWLockT(&opaque_buffer_), NULL);
204 }
205
~ReaderWriterMutex()206 ReaderWriterMutex::~ReaderWriterMutex() {
207 pthread_rwlock_destroy(AsPthreadRWLockT(&opaque_buffer_));
208 }
209
ReaderLock()210 void ReaderWriterMutex::ReaderLock() {
211 pthread_rwlock_rdlock(AsPthreadRWLockT(&opaque_buffer_));
212 }
213
ReaderUnlock()214 void ReaderWriterMutex::ReaderUnlock() {
215 pthread_rwlock_unlock(AsPthreadRWLockT(&opaque_buffer_));
216 }
217
WriterLock()218 void ReaderWriterMutex::WriterLock() {
219 pthread_rwlock_wrlock(AsPthreadRWLockT(&opaque_buffer_));
220 }
221
WriterUnlock()222 void ReaderWriterMutex::WriterUnlock() {
223 pthread_rwlock_unlock(AsPthreadRWLockT(&opaque_buffer_));
224 }
225
MultipleReadersThreadsSupported()226 bool ReaderWriterMutex::MultipleReadersThreadsSupported() {
227 return true;
228 }
229
230 #else
231
232 // Fallback implementations as ReaderWriterLock is not available.
ReaderWriterMutex()233 ReaderWriterMutex::ReaderWriterMutex() {
234 // Non-recursive lock is OK.
235 pthread_mutex_init(AsPthreadMutexT(&opaque_buffer_), NULL);
236 }
237
~ReaderWriterMutex()238 ReaderWriterMutex::~ReaderWriterMutex() {
239 pthread_mutex_destroy(AsPthreadMutexT(&opaque_buffer_));
240 }
241
ReaderLock()242 void ReaderWriterMutex::ReaderLock() {
243 pthread_mutex_lock(AsPthreadMutexT(&opaque_buffer_));
244 }
245
WriterLock()246 void ReaderWriterMutex::WriterLock() {
247 pthread_mutex_lock(AsPthreadMutexT(&opaque_buffer_));
248 }
249
ReaderUnlock()250 void ReaderWriterMutex::ReaderUnlock() {
251 pthread_mutex_unlock(AsPthreadMutexT(&opaque_buffer_));
252 }
253
WriterUnlock()254 void ReaderWriterMutex::WriterUnlock() {
255 pthread_mutex_unlock(AsPthreadMutexT(&opaque_buffer_));
256 }
257
MultipleReadersThreadsSupported()258 bool ReaderWriterMutex::MultipleReadersThreadsSupported() {
259 return false;
260 }
261
262 #endif // MOZC_PTHREAD_HAS_READER_WRITER_LOCK
263
264 #endif // OS_WIN or pthread
265
CallOnce(once_t * once,void (* func)())266 void CallOnce(once_t *once, void (*func)()) {
267 if (once == nullptr || func == nullptr) {
268 return;
269 }
270 int expected_state = ONCE_INIT;
271 if (once->compare_exchange_strong(expected_state, ONCE_RUNNING)) {
272 (*func)();
273 *once = ONCE_DONE;
274 return;
275 }
276 // If the above compare_exchange_strong() returns false, it stores the value
277 // of once to expected_state, which is ONCE_RUNNING or ONCE_DONE.
278 if (expected_state == ONCE_DONE) {
279 return;
280 }
281 // Here's the case where expected_state == ONCE_RUNNING, indicating that
282 // another thread is calling func. Wait for it to complete.
283 while (*once == ONCE_RUNNING) {
284 #ifdef OS_WIN
285 ::YieldProcessor();
286 #endif // OS_WIN
287 } // Busy loop
288 }
289
ResetOnce(once_t * once)290 void ResetOnce(once_t *once) {
291 if (once) {
292 *once = ONCE_INIT;
293 }
294 }
295
296 } // namespace mozc
297