CellModules
mingw.mutex.h
Go to the documentation of this file.
1
20#ifndef WIN32STDMUTEX_H
21#define WIN32STDMUTEX_H
22
23#if !defined(__cplusplus) || (__cplusplus < 201103L)
24#error A C++11 compiler is required!
25#endif
26// Recursion checks on non-recursive locks have some performance penalty, so the user
27// may want to disable the checks in release builds. In that case, make sure they
28// are always enabled in debug builds.
29
30#if defined(STDMUTEX_NO_RECURSION_CHECKS) && !defined(NDEBUG)
31 #undef STDMUTEX_NO_RECURSION_CHECKS
32#endif
33
34#include <windows.h>
35#include <chrono>
36#include <system_error>
37#include <cstdio>
38#include <atomic>
39#include <mutex> //need for call_once()
40#include <assert.h>
41
42// Need for yield in spinlock and the implementation of invoke
43#include "mingw.thread.h"
44
45
46#ifndef EPROTO
47 #define EPROTO 134
48#endif
49#ifndef EOWNERDEAD
50 #define EOWNERDEAD 133
51#endif
52
53namespace mingw_stdthread
54{
55// The _NonRecursive class has mechanisms that do not play nice with direct
56// manipulation of the native handle. This forward declaration is part of
57// a friend class declaration.
58#ifndef STDMUTEX_NO_RECURSION_CHECKS
59namespace vista
60{
61class condition_variable;
62}
63#endif
64// To make this namespace equivalent to the thread-related subset of std,
65// pull in the classes and class templates supplied by std but not by this
66// implementation.
67using std::lock_guard;
68using std::unique_lock;
69using std::adopt_lock_t;
70using std::defer_lock_t;
71using std::try_to_lock_t;
72using std::adopt_lock;
73using std::defer_lock;
74using std::try_to_lock;
75
77{
78protected:
79 CRITICAL_SECTION mHandle;
80public:
81 typedef LPCRITICAL_SECTION native_handle_type;
83 recursive_mutex() noexcept : mHandle()
84 {
85 InitializeCriticalSection(&mHandle);
86 }
90 {
91 DeleteCriticalSection(&mHandle);
92 }
93 void lock()
94 {
95 EnterCriticalSection(&mHandle);
96 }
97 void unlock()
98 {
99 LeaveCriticalSection(&mHandle);
100 }
101 bool try_lock()
102 {
103 return (TryEnterCriticalSection(&mHandle)!=0);
104 }
105};
106
108{
109// If this is to be read before locking, then the owner-thread variable must
110// be atomic to prevent a torn read from spuriously causing errors.
111 std::atomic<DWORD> mOwnerThread;
112 constexpr _OwnerThread () noexcept : mOwnerThread(0) {}
114 {
115 DWORD self = GetCurrentThreadId();
116 if (mOwnerThread.load(std::memory_order_relaxed) == self)
117 {
118 std::fprintf(stderr, "FATAL: Recursive locking of non-recursive mutex detected. Throwing system exception\n");
119 std::fflush(stderr);
120 throw std::system_error(EDEADLK, std::generic_category());
121 }
122 return self;
123 }
124 void setOwnerAfterLock(DWORD id)
125 {
126 mOwnerThread.store(id, std::memory_order_relaxed);
127 }
129 {
130 DWORD self = GetCurrentThreadId();
131 if (mOwnerThread.load(std::memory_order_relaxed) != self)
132 {
133 std::fprintf(stderr, "FATAL: Recursive unlocking of non-recursive mutex detected. Throwing system exception\n");
134 std::fflush(stderr);
135 throw std::system_error(EDEADLK, std::generic_category());
136 }
137 mOwnerThread.store(0, std::memory_order_relaxed);
138 }
139};
140
141/*template <class B>
142class _NonRecursive: protected B
143{
144protected:
145#ifndef STDMUTEX_NO_RECURSION_CHECKS
146// Allow condition variable to unlock the native handle directly.
147 friend class vista::condition_variable;
148#endif
149 typedef B base;
150 _OwnerThread mOwnerThread;
151public:
152 using typename base::native_handle_type;
153 using base::native_handle;
154 constexpr _NonRecursive() noexcept :base(), mOwnerThread() {}
155 _NonRecursive (const _NonRecursive<B>&) = delete;
156 _NonRecursive& operator= (const _NonRecursive<B>&) = delete;
157 void lock()
158 {
159 DWORD self = mOwnerThread.checkOwnerBeforeLock();
160 base::lock();
161 mOwnerThread.setOwnerAfterLock(self);
162 }
163 void unlock()
164 {
165 mOwnerThread.checkSetOwnerBeforeUnlock();
166 base::unlock();
167 }
168 bool try_lock()
169 {
170 DWORD self = mOwnerThread.checkOwnerBeforeLock();
171 bool ret = base::try_lock();
172 if (ret)
173 mOwnerThread.setOwnerAfterLock(self);
174 return ret;
175 }
176};*/
177
178// Though the Slim Reader-Writer (SRW) locks used here are not complete until
179// Windows 7, implementing partial functionality in Vista will simplify the
180// interaction with condition variables.
181#if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA)
182namespace windows7
183{
184class mutex
185{
186 SRWLOCK mHandle;
187// Track locking thread for error checking.
188#ifndef STDMUTEX_NO_RECURSION_CHECKS
189 friend class vista::condition_variable;
190 _OwnerThread mOwnerThread;
191#endif
192public:
193 typedef PSRWLOCK native_handle_type;
194 constexpr mutex () noexcept : mHandle(SRWLOCK_INIT)
195#ifndef STDMUTEX_NO_RECURSION_CHECKS
196 , mOwnerThread()
197#endif
198 { }
199 mutex (const mutex&) = delete;
200 mutex & operator= (const mutex&) = delete;
201 void lock (void)
202 {
203#ifndef STDMUTEX_NO_RECURSION_CHECKS
204 DWORD self = mOwnerThread.checkOwnerBeforeLock();
205#endif
206 AcquireSRWLockExclusive(&mHandle);
207#ifndef STDMUTEX_NO_RECURSION_CHECKS
208 mOwnerThread.setOwnerAfterLock(self);
209#endif
210 }
211 void unlock (void)
212 {
213#ifndef STDMUTEX_NO_RECURSION_CHECKS
214 mOwnerThread.checkSetOwnerBeforeUnlock();
215#endif
216 ReleaseSRWLockExclusive(&mHandle);
217 }
218// TryAcquireSRW functions are a Windows 7 feature.
219#if (WINVER >= _WIN32_WINNT_WIN7)
220 bool try_lock (void)
221 {
222#ifndef STDMUTEX_NO_RECURSION_CHECKS
223 DWORD self = mOwnerThread.checkOwnerBeforeLock();
224#endif
225 BOOL ret = TryAcquireSRWLockExclusive(&mHandle);
226#ifndef STDMUTEX_NO_RECURSION_CHECKS
227 if (ret)
228 mOwnerThread.setOwnerAfterLock(self);
229#endif
230 return ret;
231 }
232#endif
233 native_handle_type native_handle (void)
234 {
235 return &mHandle;
236 }
237};
238} // Namespace windows7
239#endif // Compiling for Vista
240namespace xp
241{
242/*
243#ifndef STDMUTEX_NO_RECURSION_CHECKS
244 typedef _NonRecursive<recursive_mutex> mutex;
245#else
246 typedef recursive_mutex mutex;
247#endif*/
248class mutex
249{
250 CRITICAL_SECTION mHandle;
251 std::atomic_uchar mState;
252// Track locking thread for error checking.
253#ifndef STDMUTEX_NO_RECURSION_CHECKS
256#endif
257public:
258 typedef PCRITICAL_SECTION native_handle_type;
259 constexpr mutex () noexcept : mHandle(), mState(2)
260#ifndef STDMUTEX_NO_RECURSION_CHECKS
261 , mOwnerThread()
262#endif
263 { }
264 mutex (const mutex&) = delete;
265 mutex & operator= (const mutex&) = delete;
266 ~mutex() noexcept
267 {
268 DeleteCriticalSection(&mHandle);
269 }
270 void lock (void)
271 {
272 unsigned char state = mState.load(std::memory_order_acquire);
273 while (state) {
274 if ((state == 2) && mState.compare_exchange_weak(state, 1, std::memory_order_acquire))
275 {
276 InitializeCriticalSection(&mHandle);
277 mState.store(0, std::memory_order_release);
278 break;
279 }
280 if (state == 1)
282 }
283#ifndef STDMUTEX_NO_RECURSION_CHECKS
284 DWORD self = mOwnerThread.checkOwnerBeforeLock();
285#endif
286 EnterCriticalSection(&mHandle);
287#ifndef STDMUTEX_NO_RECURSION_CHECKS
289#endif
290 }
291 void unlock (void)
292 {
293 assert(mState.load(std::memory_order_relaxed) == 0);
294#ifndef STDMUTEX_NO_RECURSION_CHECKS
296#endif
297 LeaveCriticalSection(&mHandle);
298 }
299 bool try_lock (void)
300 {
301 unsigned char state = mState.load(std::memory_order_acquire);
302 if ((state == 2) && mState.compare_exchange_strong(state, 1, std::memory_order_acquire))
303 {
304 InitializeCriticalSection(&mHandle);
305 mState.store(0, std::memory_order_release);
306 }
307 if (state == 1)
308 return false;
309#ifndef STDMUTEX_NO_RECURSION_CHECKS
310 DWORD self = mOwnerThread.checkOwnerBeforeLock();
311#endif
312 BOOL ret = TryEnterCriticalSection(&mHandle);
313#ifndef STDMUTEX_NO_RECURSION_CHECKS
314 if (ret)
316#endif
317 return ret;
318 }
320 {
321 return &mHandle;
322 }
323};
324}
325#if (WINVER >= _WIN32_WINNT_WIN7)
326using windows7::mutex;
327#else
328using xp::mutex;
329#endif
330
332{
333protected:
334 HANDLE mHandle;
335// Track locking thread for error checking of non-recursive timed_mutex. For
336// standard compliance, this must be defined in same class and at the same
337// access-control level as every other variable in the timed_mutex.
338#ifndef STDMUTEX_NO_RECURSION_CHECKS
341#endif
342public:
343 typedef HANDLE native_handle_type;
347 recursive_timed_mutex(): mHandle(CreateMutex(NULL, FALSE, NULL))
348#ifndef STDMUTEX_NO_RECURSION_CHECKS
349 , mOwnerThread()
350#endif
351 {}
353 {
354 CloseHandle(mHandle);
355 }
356 void lock()
357 {
358 DWORD ret = WaitForSingleObject(mHandle, INFINITE);
359 if (ret != WAIT_OBJECT_0)
360 {
361 if (ret == WAIT_ABANDONED)
362 throw std::system_error(EOWNERDEAD, std::generic_category());
363 else
364 throw std::system_error(EPROTO, std::generic_category());
365 }
366 }
367 void unlock()
368 {
369 if (!ReleaseMutex(mHandle))
370 throw std::system_error(EDEADLK, std::generic_category());
371 }
372 bool try_lock()
373 {
374 DWORD ret = WaitForSingleObject(mHandle, 0);
375 if (ret == WAIT_TIMEOUT)
376 return false;
377 else if (ret == WAIT_OBJECT_0)
378 return true;
379 else if (ret == WAIT_ABANDONED)
380 throw std::system_error(EOWNERDEAD, std::generic_category());
381 else
382 throw std::system_error(EPROTO, std::generic_category());
383 }
384 template <class Rep, class Period>
385 bool try_lock_for(const std::chrono::duration<Rep,Period>& dur)
386 {
387 DWORD timeout = (DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(dur).count();
388
389 DWORD ret = WaitForSingleObject(mHandle, timeout);
390 if (ret == WAIT_TIMEOUT)
391 return false;
392 else if (ret == WAIT_OBJECT_0)
393 return true;
394 else if (ret == WAIT_ABANDONED)
395 throw std::system_error(EOWNERDEAD, std::generic_category());
396 else
397 throw std::system_error(EPROTO, std::generic_category());
398 }
399 template <class Clock, class Duration>
400 bool try_lock_until(const std::chrono::time_point<Clock,Duration>& timeout_time)
401 {
402 return try_lock_for(timeout_time - Clock::now());
403 }
404};
405
406// Override if, and only if, it is necessary for error-checking.
407#ifndef STDMUTEX_NO_RECURSION_CHECKS
409{
410protected:
412public:
413 using base::base;
414 timed_mutex(const timed_mutex&) = delete;
416 void lock()
417 {
418 DWORD self = mOwnerThread.checkOwnerBeforeLock();
419 base::lock();
421 }
422 void unlock()
423 {
425 base::unlock();
426 }
427 bool try_lock ()
428 {
429 DWORD self = mOwnerThread.checkOwnerBeforeLock();
430 bool ret = base::try_lock();
431 if (ret)
433 return ret;
434 }
435 template <class Rep, class Period>
436 bool try_lock_for(const std::chrono::duration<Rep,Period>& dur)
437 {
438 DWORD self = mOwnerThread.checkOwnerBeforeLock();
439 bool ret = base::try_lock_for(dur);
440 if (ret)
442 return ret;
443 }
444 template <class Clock, class Duration>
445 bool try_lock_until(const std::chrono::time_point<Clock,Duration>& timeout_time)
446 {
447 DWORD self = mOwnerThread.checkOwnerBeforeLock();
448 bool ret = base::try_lock_until(timeout_time);
449 if (ret)
451 return ret;
452 }
453};
454#else
455typedef recursive_timed_mutex timed_mutex;
456#endif
457
459{
460 mutex mMutex;
461 std::atomic_bool mHasRun;
462 once_flag(const once_flag&) = delete;
463 once_flag& operator=(const once_flag&) = delete;
464 template<class Callable, class... Args>
465 friend void call_once(once_flag& once, Callable&& f, Args&&... args);
466public:
467 constexpr once_flag() noexcept: mMutex(), mHasRun(false) {}
468};
469
470template<class Callable, class... Args>
471void call_once(once_flag& flag, Callable&& func, Args&&... args)
472{
473 if (flag.mHasRun.load(std::memory_order_acquire))
474 return;
475 lock_guard<mutex> lock(flag.mMutex);
476 if (flag.mHasRun.load(std::memory_order_acquire))
477 return;
478 detail::invoke(std::forward<Callable>(func),std::forward<Args>(args)...);
479 flag.mHasRun.store(true, std::memory_order_release);
480}
481} // Namespace mingw_stdthread
482
483// Push objects into std, but only if they are not already there.
484namespace std
485{
486// Because of quirks of the compiler, the common "using namespace std;"
487// directive would flatten the namespaces and introduce ambiguity where there
488// was none. Direct specification (std::), however, would be unaffected.
489// Take the safe option, and include only in the presence of MinGW's win32
490// implementation.
491#if defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS)
493using mingw_stdthread::mutex;
498#elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
499#define MINGW_STDTHREAD_REDUNDANCY_WARNING
500#pragma message "This version of MinGW seems to include a win32 port of\
501 pthreads, and probably already has C++11 std threading classes implemented,\
502 based on pthreads. These classes, found in namespace std, are not overridden\
503 by the mingw-std-thread library. If you would still like to use this\
504 implementation (as it is more lightweight), use the classes provided in\
505 namespace mingw_stdthread."
506#endif
507}
508#endif // WIN32STDMUTEX_H
friend void call_once(once_flag &once, Callable &&f, Args &&... args)
Definition: mingw.mutex.h:471
once_flag(const once_flag &)=delete
constexpr once_flag() noexcept
Definition: mingw.mutex.h:467
std::atomic_bool mHasRun
Definition: mingw.mutex.h:461
once_flag & operator=(const once_flag &)=delete
recursive_mutex & operator=(const recursive_mutex &)=delete
LPCRITICAL_SECTION native_handle_type
Definition: mingw.mutex.h:81
native_handle_type native_handle()
Definition: mingw.mutex.h:82
recursive_mutex(const recursive_mutex &)=delete
recursive_timed_mutex & operator=(const recursive_timed_mutex &)=delete
recursive_timed_mutex(const recursive_timed_mutex &)=delete
native_handle_type native_handle() const
Definition: mingw.mutex.h:344
bool try_lock_for(const std::chrono::duration< Rep, Period > &dur)
Definition: mingw.mutex.h:385
bool try_lock_until(const std::chrono::time_point< Clock, Duration > &timeout_time)
Definition: mingw.mutex.h:400
recursive_timed_mutex base
Definition: mingw.mutex.h:411
bool try_lock_for(const std::chrono::duration< Rep, Period > &dur)
Definition: mingw.mutex.h:436
timed_mutex(const timed_mutex &)=delete
bool try_lock_until(const std::chrono::time_point< Clock, Duration > &timeout_time)
Definition: mingw.mutex.h:445
timed_mutex & operator=(const timed_mutex &)=delete
native_handle_type native_handle(void)
Definition: mingw.mutex.h:319
mutex(const mutex &)=delete
mutex & operator=(const mutex &)=delete
std::atomic_uchar mState
Definition: mingw.mutex.h:251
constexpr mutex() noexcept
Definition: mingw.mutex.h:259
CRITICAL_SECTION mHandle
Definition: mingw.mutex.h:250
PCRITICAL_SECTION native_handle_type
Definition: mingw.mutex.h:258
#define EPROTO
Definition: mingw.mutex.h:47
#define EOWNERDEAD
Definition: mingw.mutex.h:50
std::thread implementation for MinGW (c) 2013-2016 by Mega Limited, Auckland, New Zealand
auto invoke(F &&f, Args &&... args) -> decltype(InvokeResult< F, Args... >::invoke(std::forward< F >(f), std::forward< Args >(args)...))
Definition: mingw.thread.h:122
void call_once(once_flag &flag, Callable &&func, Args &&... args)
Definition: mingw.mutex.h:471
Provides common mathematical functions and vector operations.
Definition: std.hpp:4
void setOwnerAfterLock(DWORD id)
Definition: mingw.mutex.h:124
std::atomic< DWORD > mOwnerThread
Definition: mingw.mutex.h:111
constexpr _OwnerThread() noexcept
Definition: mingw.mutex.h:112
DWORD checkOwnerBeforeLock() const
Definition: mingw.mutex.h:113