mingw.mutex.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501
  1. /**
  2. * @file mingw.mutex.h
  3. * @brief std::mutex et al implementation for MinGW
  4. ** (c) 2013-2016 by Mega Limited, Auckland, New Zealand
  5. * @author Alexander Vassilev
  6. *
  7. * @copyright Simplified (2-clause) BSD License.
  8. * You should have received a copy of the license along with this
  9. * program.
  10. *
  11. * This code is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. * @note
  15. * This file may become part of the mingw-w64 runtime package. If/when this happens,
  16. * the appropriate license will be added, i.e. this code will become dual-licensed,
  17. * and the current BSD 2-clause license will stay.
  18. */
  19. #ifndef WIN32STDMUTEX_H
  20. #define WIN32STDMUTEX_H
  21. #if !defined(__cplusplus) || (__cplusplus < 201103L)
  22. #error A C++11 compiler is required!
  23. #endif
  24. // Recursion checks on non-recursive locks have some performance penalty, and
  25. // the C++ standard does not mandate them. The user might want to explicitly
  26. // enable or disable such checks. If the user has no preference, enable such
  27. // checks in debug builds, but not in release builds.
  28. #ifdef STDMUTEX_RECURSION_CHECKS
  29. #elif defined(NDEBUG)
  30. #define STDMUTEX_RECURSION_CHECKS 0
  31. #else
  32. #define STDMUTEX_RECURSION_CHECKS 1
  33. #endif
  34. #include <chrono>
  35. #include <system_error>
  36. #include <atomic>
  37. #include <mutex> //need for call_once()
  38. #if STDMUTEX_RECURSION_CHECKS || !defined(NDEBUG)
  39. #include <cstdio>
  40. #endif
  41. #include <sdkddkver.h> // Detect Windows version.
  42. #if (defined(__MINGW32__) && !defined(__MINGW64_VERSION_MAJOR))
  43. #pragma message "The Windows API that MinGW-w32 provides is not fully compatible\
  44. with Microsoft's API. We'll try to work around this, but we can make no\
  45. guarantees. This problem does not exist in MinGW-w64."
  46. #include <windows.h> // No further granularity can be expected.
  47. #else
  48. #if STDMUTEX_RECURSION_CHECKS
  49. #include <processthreadsapi.h> // For GetCurrentThreadId
  50. #endif
  51. #include <synchapi.h> // For InitializeCriticalSection, etc.
  52. #include <errhandlingapi.h> // For GetLastError
  53. #include <handleapi.h>
  54. #endif
  55. // Need for the implementation of invoke
  56. #include "mingw.invoke.h"
  57. #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501)
  58. #error To use the MinGW-std-threads library, you will need to define the macro _WIN32_WINNT to be 0x0501 (Windows XP) or higher.
  59. #endif
  60. namespace mingw_stdthread
  61. {
  62. // The _NonRecursive class has mechanisms that do not play nice with direct
  63. // manipulation of the native handle. This forward declaration is part of
  64. // a friend class declaration.
  65. #if STDMUTEX_RECURSION_CHECKS
  66. namespace vista
  67. {
  68. class condition_variable;
  69. }
  70. #endif
  71. // To make this namespace equivalent to the thread-related subset of std,
  72. // pull in the classes and class templates supplied by std but not by this
  73. // implementation.
  74. using std::lock_guard;
  75. using std::unique_lock;
  76. using std::adopt_lock_t;
  77. using std::defer_lock_t;
  78. using std::try_to_lock_t;
  79. using std::adopt_lock;
  80. using std::defer_lock;
  81. using std::try_to_lock;
  82. class recursive_mutex
  83. {
  84. CRITICAL_SECTION mHandle;
  85. public:
  86. typedef LPCRITICAL_SECTION native_handle_type;
  87. native_handle_type native_handle() {return &mHandle;}
  88. recursive_mutex() noexcept : mHandle()
  89. {
  90. InitializeCriticalSection(&mHandle);
  91. }
  92. recursive_mutex (const recursive_mutex&) = delete;
  93. recursive_mutex& operator=(const recursive_mutex&) = delete;
  94. ~recursive_mutex() noexcept
  95. {
  96. DeleteCriticalSection(&mHandle);
  97. }
  98. void lock()
  99. {
  100. EnterCriticalSection(&mHandle);
  101. }
  102. void unlock()
  103. {
  104. LeaveCriticalSection(&mHandle);
  105. }
  106. bool try_lock()
  107. {
  108. return (TryEnterCriticalSection(&mHandle)!=0);
  109. }
  110. };
  111. #if STDMUTEX_RECURSION_CHECKS
  112. struct _OwnerThread
  113. {
  114. // If this is to be read before locking, then the owner-thread variable must
  115. // be atomic to prevent a torn read from spuriously causing errors.
  116. std::atomic<DWORD> mOwnerThread;
  117. constexpr _OwnerThread () noexcept : mOwnerThread(0) {}
  118. static void on_deadlock (void)
  119. {
  120. using namespace std;
  121. fprintf(stderr, "FATAL: Recursive locking of non-recursive mutex\
  122. detected. Throwing system exception\n");
  123. fflush(stderr);
  124. __builtin_trap();
  125. }
  126. DWORD checkOwnerBeforeLock() const
  127. {
  128. DWORD self = GetCurrentThreadId();
  129. if (mOwnerThread.load(std::memory_order_relaxed) == self)
  130. on_deadlock();
  131. return self;
  132. }
  133. void setOwnerAfterLock(DWORD id)
  134. {
  135. mOwnerThread.store(id, std::memory_order_relaxed);
  136. }
  137. void checkSetOwnerBeforeUnlock()
  138. {
  139. DWORD self = GetCurrentThreadId();
  140. if (mOwnerThread.load(std::memory_order_relaxed) != self)
  141. on_deadlock();
  142. mOwnerThread.store(0, std::memory_order_relaxed);
  143. }
  144. };
  145. #endif
  146. // Though the Slim Reader-Writer (SRW) locks used here are not complete until
  147. // Windows 7, implementing partial functionality in Vista will simplify the
  148. // interaction with condition variables.
  149. //Define SRWLOCK_INIT.
  150. #if !defined(SRWLOCK_INIT)
  151. #pragma message "SRWLOCK_INIT macro is not defined. Defining automatically."
  152. #define SRWLOCK_INIT {0}
  153. #endif
  154. #if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA)
  155. namespace windows7
  156. {
  157. class mutex
  158. {
  159. SRWLOCK mHandle;
  160. // Track locking thread for error checking.
  161. #if STDMUTEX_RECURSION_CHECKS
  162. friend class vista::condition_variable;
  163. _OwnerThread mOwnerThread {};
  164. #endif
  165. public:
  166. typedef PSRWLOCK native_handle_type;
  167. #pragma GCC diagnostic push
  168. #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
  169. constexpr mutex () noexcept : mHandle(SRWLOCK_INIT) { }
  170. #pragma GCC diagnostic pop
  171. mutex (const mutex&) = delete;
  172. mutex & operator= (const mutex&) = delete;
  173. void lock (void)
  174. {
  175. // Note: Undefined behavior if called recursively.
  176. #if STDMUTEX_RECURSION_CHECKS
  177. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  178. #endif
  179. AcquireSRWLockExclusive(&mHandle);
  180. #if STDMUTEX_RECURSION_CHECKS
  181. mOwnerThread.setOwnerAfterLock(self);
  182. #endif
  183. }
  184. void unlock (void)
  185. {
  186. #if STDMUTEX_RECURSION_CHECKS
  187. mOwnerThread.checkSetOwnerBeforeUnlock();
  188. #endif
  189. ReleaseSRWLockExclusive(&mHandle);
  190. }
  191. // TryAcquireSRW functions are a Windows 7 feature.
  192. #if (WINVER >= _WIN32_WINNT_WIN7)
  193. bool try_lock (void)
  194. {
  195. #if STDMUTEX_RECURSION_CHECKS
  196. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  197. #endif
  198. BOOL ret = TryAcquireSRWLockExclusive(&mHandle);
  199. #if STDMUTEX_RECURSION_CHECKS
  200. if (ret)
  201. mOwnerThread.setOwnerAfterLock(self);
  202. #endif
  203. return ret;
  204. }
  205. #endif
  206. native_handle_type native_handle (void)
  207. {
  208. return &mHandle;
  209. }
  210. };
  211. } // Namespace windows7
  212. #endif // Compiling for Vista
  213. namespace xp
  214. {
  215. class mutex
  216. {
  217. CRITICAL_SECTION mHandle;
  218. std::atomic_uchar mState;
  219. // Track locking thread for error checking.
  220. #if STDMUTEX_RECURSION_CHECKS
  221. friend class vista::condition_variable;
  222. _OwnerThread mOwnerThread {};
  223. #endif
  224. public:
  225. typedef PCRITICAL_SECTION native_handle_type;
  226. constexpr mutex () noexcept : mHandle(), mState(2) { }
  227. mutex (const mutex&) = delete;
  228. mutex & operator= (const mutex&) = delete;
  229. ~mutex() noexcept
  230. {
  231. // Undefined behavior if the mutex is held (locked) by any thread.
  232. // Undefined behavior if a thread terminates while holding ownership of the
  233. // mutex.
  234. DeleteCriticalSection(&mHandle);
  235. }
  236. void lock (void)
  237. {
  238. unsigned char state = mState.load(std::memory_order_acquire);
  239. while (state) {
  240. if ((state == 2) && mState.compare_exchange_weak(state, 1, std::memory_order_acquire))
  241. {
  242. InitializeCriticalSection(&mHandle);
  243. mState.store(0, std::memory_order_release);
  244. break;
  245. }
  246. if (state == 1)
  247. {
  248. Sleep(0);
  249. state = mState.load(std::memory_order_acquire);
  250. }
  251. }
  252. #if STDMUTEX_RECURSION_CHECKS
  253. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  254. #endif
  255. EnterCriticalSection(&mHandle);
  256. #if STDMUTEX_RECURSION_CHECKS
  257. mOwnerThread.setOwnerAfterLock(self);
  258. #endif
  259. }
  260. void unlock (void)
  261. {
  262. #if STDMUTEX_RECURSION_CHECKS
  263. mOwnerThread.checkSetOwnerBeforeUnlock();
  264. #endif
  265. LeaveCriticalSection(&mHandle);
  266. }
  267. bool try_lock (void)
  268. {
  269. unsigned char state = mState.load(std::memory_order_acquire);
  270. if ((state == 2) && mState.compare_exchange_strong(state, 1, std::memory_order_acquire))
  271. {
  272. InitializeCriticalSection(&mHandle);
  273. mState.store(0, std::memory_order_release);
  274. }
  275. if (state == 1)
  276. return false;
  277. #if STDMUTEX_RECURSION_CHECKS
  278. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  279. #endif
  280. BOOL ret = TryEnterCriticalSection(&mHandle);
  281. #if STDMUTEX_RECURSION_CHECKS
  282. if (ret)
  283. mOwnerThread.setOwnerAfterLock(self);
  284. #endif
  285. return ret;
  286. }
  287. native_handle_type native_handle (void)
  288. {
  289. return &mHandle;
  290. }
  291. };
  292. } // Namespace "xp"
  293. #if (WINVER >= _WIN32_WINNT_WIN7)
  294. using windows7::mutex;
  295. #else
  296. using xp::mutex;
  297. #endif
  298. class recursive_timed_mutex
  299. {
  300. static constexpr DWORD kWaitAbandoned = 0x00000080l;
  301. static constexpr DWORD kWaitObject0 = 0x00000000l;
  302. static constexpr DWORD kInfinite = 0xffffffffl;
  303. inline bool try_lock_internal (DWORD ms) noexcept
  304. {
  305. DWORD ret = WaitForSingleObject(mHandle, ms);
  306. #ifndef NDEBUG
  307. if (ret == kWaitAbandoned)
  308. {
  309. using namespace std;
  310. fprintf(stderr, "FATAL: Thread terminated while holding a mutex.");
  311. terminate();
  312. }
  313. #endif
  314. return (ret == kWaitObject0) || (ret == kWaitAbandoned);
  315. }
  316. protected:
  317. HANDLE mHandle;
  318. // Track locking thread for error checking of non-recursive timed_mutex. For
  319. // standard compliance, this must be defined in same class and at the same
  320. // access-control level as every other variable in the timed_mutex.
  321. #if STDMUTEX_RECURSION_CHECKS
  322. friend class vista::condition_variable;
  323. _OwnerThread mOwnerThread {};
  324. #endif
  325. public:
  326. typedef HANDLE native_handle_type;
  327. native_handle_type native_handle() const {return mHandle;}
  328. recursive_timed_mutex(const recursive_timed_mutex&) = delete;
  329. recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
  330. recursive_timed_mutex(): mHandle(CreateMutex(NULL, FALSE, NULL)) {}
  331. ~recursive_timed_mutex()
  332. {
  333. CloseHandle(mHandle);
  334. }
  335. void lock()
  336. {
  337. DWORD ret = WaitForSingleObject(mHandle, kInfinite);
  338. // If (ret == WAIT_ABANDONED), then the thread that held ownership was
  339. // terminated. Behavior is undefined, but Windows will pass ownership to this
  340. // thread.
  341. #ifndef NDEBUG
  342. if (ret == kWaitAbandoned)
  343. {
  344. using namespace std;
  345. fprintf(stderr, "FATAL: Thread terminated while holding a mutex.");
  346. terminate();
  347. }
  348. #endif
  349. if ((ret != kWaitObject0) && (ret != kWaitAbandoned))
  350. {
  351. __builtin_trap();
  352. }
  353. }
  354. void unlock()
  355. {
  356. if (!ReleaseMutex(mHandle))
  357. __builtin_trap();
  358. }
  359. bool try_lock()
  360. {
  361. return try_lock_internal(0);
  362. }
  363. template <class Rep, class Period>
  364. bool try_lock_for(const std::chrono::duration<Rep,Period>& dur)
  365. {
  366. using namespace std::chrono;
  367. auto timeout = duration_cast<milliseconds>(dur).count();
  368. while (timeout > 0)
  369. {
  370. constexpr auto kMaxStep = static_cast<decltype(timeout)>(kInfinite-1);
  371. auto step = (timeout < kMaxStep) ? timeout : kMaxStep;
  372. if (try_lock_internal(static_cast<DWORD>(step)))
  373. return true;
  374. timeout -= step;
  375. }
  376. return false;
  377. }
  378. template <class Clock, class Duration>
  379. bool try_lock_until(const std::chrono::time_point<Clock,Duration>& timeout_time)
  380. {
  381. return try_lock_for(timeout_time - Clock::now());
  382. }
  383. };
  384. // Override if, and only if, it is necessary for error-checking.
  385. #if STDMUTEX_RECURSION_CHECKS
  386. class timed_mutex: recursive_timed_mutex
  387. {
  388. public:
  389. timed_mutex() = default;
  390. timed_mutex(const timed_mutex&) = delete;
  391. timed_mutex& operator=(const timed_mutex&) = delete;
  392. void lock()
  393. {
  394. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  395. recursive_timed_mutex::lock();
  396. mOwnerThread.setOwnerAfterLock(self);
  397. }
  398. void unlock()
  399. {
  400. mOwnerThread.checkSetOwnerBeforeUnlock();
  401. recursive_timed_mutex::unlock();
  402. }
  403. template <class Rep, class Period>
  404. bool try_lock_for(const std::chrono::duration<Rep,Period>& dur)
  405. {
  406. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  407. bool ret = recursive_timed_mutex::try_lock_for(dur);
  408. if (ret)
  409. mOwnerThread.setOwnerAfterLock(self);
  410. return ret;
  411. }
  412. template <class Clock, class Duration>
  413. bool try_lock_until(const std::chrono::time_point<Clock,Duration>& timeout_time)
  414. {
  415. return try_lock_for(timeout_time - Clock::now());
  416. }
  417. bool try_lock ()
  418. {
  419. return try_lock_for(std::chrono::milliseconds(0));
  420. }
  421. };
  422. #else
  423. typedef recursive_timed_mutex timed_mutex;
  424. #endif
  425. class once_flag
  426. {
  427. // When available, the SRW-based mutexes should be faster than the
  428. // CriticalSection-based mutexes. Only try_lock will be unavailable in Vista,
  429. // and try_lock is not used by once_flag.
  430. #if (_WIN32_WINNT == _WIN32_WINNT_VISTA)
  431. windows7::mutex mMutex;
  432. #else
  433. mutex mMutex;
  434. #endif
  435. std::atomic_bool mHasRun;
  436. once_flag(const once_flag&) = delete;
  437. once_flag& operator=(const once_flag&) = delete;
  438. template<class Callable, class... Args>
  439. friend void call_once(once_flag& once, Callable&& f, Args&&... args);
  440. public:
  441. constexpr once_flag() noexcept: mMutex(), mHasRun(false) {}
  442. };
  443. template<class Callable, class... Args>
  444. void call_once(once_flag& flag, Callable&& func, Args&&... args)
  445. {
  446. if (flag.mHasRun.load(std::memory_order_acquire))
  447. return;
  448. lock_guard<decltype(flag.mMutex)> lock(flag.mMutex);
  449. if (flag.mHasRun.load(std::memory_order_relaxed))
  450. return;
  451. detail::invoke(std::forward<Callable>(func),std::forward<Args>(args)...);
  452. flag.mHasRun.store(true, std::memory_order_release);
  453. }
  454. } // Namespace mingw_stdthread
  455. // Push objects into std, but only if they are not already there.
  456. namespace std
  457. {
  458. // Because of quirks of the compiler, the common "using namespace std;"
  459. // directive would flatten the namespaces and introduce ambiguity where there
  460. // was none. Direct specification (std::), however, would be unaffected.
  461. // Take the safe option, and include only in the presence of MinGW's win32
  462. // implementation.
  463. #if defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS) && !defined(__clang__)
  464. using mingw_stdthread::recursive_mutex;
  465. using mingw_stdthread::mutex;
  466. using mingw_stdthread::recursive_timed_mutex;
  467. using mingw_stdthread::timed_mutex;
  468. using mingw_stdthread::once_flag;
  469. using mingw_stdthread::call_once;
  470. #elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
  471. #define MINGW_STDTHREAD_REDUNDANCY_WARNING
  472. #pragma message "This version of MinGW seems to include a win32 port of\
  473. pthreads, and probably already has C++11 std threading classes implemented,\
  474. based on pthreads. These classes, found in namespace std, are not overridden\
  475. by the mingw-std-thread library. If you would still like to use this\
  476. implementation (as it is more lightweight), use the classes provided in\
  477. namespace mingw_stdthread."
  478. #endif
  479. }
  480. #endif // WIN32STDMUTEX_H