Audio plugin host https://kx.studio/carla
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mingw.mutex.h 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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 STDMUTEX_RECURSION_CHECKS
  43. #include <processthreadsapi.h> // For GetCurrentThreadId
  44. #endif
  45. #include <synchapi.h> // For InitializeCriticalSection, etc.
  46. #include <errhandlingapi.h> // For GetLastError
  47. #include <handleapi.h>
  48. // Need for the implementation of invoke
  49. #include "mingw.invoke.h"
  50. #if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x0501)
  51. #error To use the MinGW-std-threads library, you will need to define the macro _WIN32_WINNT to be 0x0501 (Windows XP) or higher.
  52. #endif
  53. namespace 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. #if STDMUTEX_RECURSION_CHECKS
  59. namespace vista
  60. {
  61. class 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.
  67. using std::lock_guard;
  68. using std::unique_lock;
  69. using std::adopt_lock_t;
  70. using std::defer_lock_t;
  71. using std::try_to_lock_t;
  72. using std::adopt_lock;
  73. using std::defer_lock;
  74. using std::try_to_lock;
  75. class recursive_mutex
  76. {
  77. CRITICAL_SECTION mHandle;
  78. public:
  79. typedef LPCRITICAL_SECTION native_handle_type;
  80. native_handle_type native_handle() {return &mHandle;}
  81. recursive_mutex() noexcept : mHandle()
  82. {
  83. InitializeCriticalSection(&mHandle);
  84. }
  85. recursive_mutex (const recursive_mutex&) = delete;
  86. recursive_mutex& operator=(const recursive_mutex&) = delete;
  87. ~recursive_mutex() noexcept
  88. {
  89. DeleteCriticalSection(&mHandle);
  90. }
  91. void lock()
  92. {
  93. EnterCriticalSection(&mHandle);
  94. }
  95. void unlock()
  96. {
  97. LeaveCriticalSection(&mHandle);
  98. }
  99. bool try_lock()
  100. {
  101. return (TryEnterCriticalSection(&mHandle)!=0);
  102. }
  103. };
  104. #if STDMUTEX_RECURSION_CHECKS
  105. struct _OwnerThread
  106. {
  107. // If this is to be read before locking, then the owner-thread variable must
  108. // be atomic to prevent a torn read from spuriously causing errors.
  109. std::atomic<DWORD> mOwnerThread;
  110. constexpr _OwnerThread () noexcept : mOwnerThread(0) {}
  111. static void on_deadlock (void)
  112. {
  113. using namespace std;
  114. fprintf(stderr, "FATAL: Recursive locking of non-recursive mutex\
  115. detected. Throwing system exception\n");
  116. fflush(stderr);
  117. throw system_error(make_error_code(errc::resource_deadlock_would_occur));
  118. }
  119. DWORD checkOwnerBeforeLock() const
  120. {
  121. DWORD self = GetCurrentThreadId();
  122. if (mOwnerThread.load(std::memory_order_relaxed) == self)
  123. on_deadlock();
  124. return self;
  125. }
  126. void setOwnerAfterLock(DWORD id)
  127. {
  128. mOwnerThread.store(id, std::memory_order_relaxed);
  129. }
  130. void checkSetOwnerBeforeUnlock()
  131. {
  132. DWORD self = GetCurrentThreadId();
  133. if (mOwnerThread.load(std::memory_order_relaxed) != self)
  134. on_deadlock();
  135. mOwnerThread.store(0, std::memory_order_relaxed);
  136. }
  137. };
  138. #endif
  139. // Though the Slim Reader-Writer (SRW) locks used here are not complete until
  140. // Windows 7, implementing partial functionality in Vista will simplify the
  141. // interaction with condition variables.
  142. #if defined(_WIN32) && (WINVER >= _WIN32_WINNT_VISTA)
  143. namespace windows7
  144. {
  145. class mutex
  146. {
  147. SRWLOCK mHandle;
  148. // Track locking thread for error checking.
  149. #if STDMUTEX_RECURSION_CHECKS
  150. friend class vista::condition_variable;
  151. _OwnerThread mOwnerThread {};
  152. #endif
  153. public:
  154. typedef PSRWLOCK native_handle_type;
  155. #pragma GCC diagnostic push
  156. #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
  157. constexpr mutex () noexcept : mHandle(SRWLOCK_INIT) { }
  158. #pragma GCC diagnostic pop
  159. mutex (const mutex&) = delete;
  160. mutex & operator= (const mutex&) = delete;
  161. void lock (void)
  162. {
  163. // Note: Undefined behavior if called recursively.
  164. #if STDMUTEX_RECURSION_CHECKS
  165. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  166. #endif
  167. AcquireSRWLockExclusive(&mHandle);
  168. #if STDMUTEX_RECURSION_CHECKS
  169. mOwnerThread.setOwnerAfterLock(self);
  170. #endif
  171. }
  172. void unlock (void)
  173. {
  174. #if STDMUTEX_RECURSION_CHECKS
  175. mOwnerThread.checkSetOwnerBeforeUnlock();
  176. #endif
  177. ReleaseSRWLockExclusive(&mHandle);
  178. }
  179. // TryAcquireSRW functions are a Windows 7 feature.
  180. #if (WINVER >= _WIN32_WINNT_WIN7)
  181. bool try_lock (void)
  182. {
  183. #if STDMUTEX_RECURSION_CHECKS
  184. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  185. #endif
  186. BOOL ret = TryAcquireSRWLockExclusive(&mHandle);
  187. #if STDMUTEX_RECURSION_CHECKS
  188. if (ret)
  189. mOwnerThread.setOwnerAfterLock(self);
  190. #endif
  191. return ret;
  192. }
  193. #endif
  194. native_handle_type native_handle (void)
  195. {
  196. return &mHandle;
  197. }
  198. };
  199. } // Namespace windows7
  200. #endif // Compiling for Vista
  201. namespace xp
  202. {
  203. class mutex
  204. {
  205. CRITICAL_SECTION mHandle;
  206. std::atomic_uchar mState;
  207. // Track locking thread for error checking.
  208. #if STDMUTEX_RECURSION_CHECKS
  209. friend class vista::condition_variable;
  210. _OwnerThread mOwnerThread {};
  211. #endif
  212. public:
  213. typedef PCRITICAL_SECTION native_handle_type;
  214. constexpr mutex () noexcept : mHandle(), mState(2) { }
  215. mutex (const mutex&) = delete;
  216. mutex & operator= (const mutex&) = delete;
  217. ~mutex() noexcept
  218. {
  219. // Undefined behavior if the mutex is held (locked) by any thread.
  220. // Undefined behavior if a thread terminates while holding ownership of the
  221. // mutex.
  222. DeleteCriticalSection(&mHandle);
  223. }
  224. void lock (void)
  225. {
  226. unsigned char state = mState.load(std::memory_order_acquire);
  227. while (state) {
  228. if ((state == 2) && mState.compare_exchange_weak(state, 1, std::memory_order_acquire))
  229. {
  230. InitializeCriticalSection(&mHandle);
  231. mState.store(0, std::memory_order_release);
  232. break;
  233. }
  234. if (state == 1)
  235. {
  236. Sleep(0);
  237. state = mState.load(std::memory_order_acquire);
  238. }
  239. }
  240. #if STDMUTEX_RECURSION_CHECKS
  241. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  242. #endif
  243. EnterCriticalSection(&mHandle);
  244. #if STDMUTEX_RECURSION_CHECKS
  245. mOwnerThread.setOwnerAfterLock(self);
  246. #endif
  247. }
  248. void unlock (void)
  249. {
  250. #if STDMUTEX_RECURSION_CHECKS
  251. mOwnerThread.checkSetOwnerBeforeUnlock();
  252. #endif
  253. LeaveCriticalSection(&mHandle);
  254. }
  255. bool try_lock (void)
  256. {
  257. unsigned char state = mState.load(std::memory_order_acquire);
  258. if ((state == 2) && mState.compare_exchange_strong(state, 1, std::memory_order_acquire))
  259. {
  260. InitializeCriticalSection(&mHandle);
  261. mState.store(0, std::memory_order_release);
  262. }
  263. if (state == 1)
  264. return false;
  265. #if STDMUTEX_RECURSION_CHECKS
  266. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  267. #endif
  268. BOOL ret = TryEnterCriticalSection(&mHandle);
  269. #if STDMUTEX_RECURSION_CHECKS
  270. if (ret)
  271. mOwnerThread.setOwnerAfterLock(self);
  272. #endif
  273. return ret;
  274. }
  275. native_handle_type native_handle (void)
  276. {
  277. return &mHandle;
  278. }
  279. };
  280. } // Namespace "xp"
  281. #if (WINVER >= _WIN32_WINNT_WIN7)
  282. using windows7::mutex;
  283. #else
  284. using xp::mutex;
  285. #endif
  286. class recursive_timed_mutex
  287. {
  288. static constexpr DWORD kWaitAbandoned = 0x00000080l;
  289. static constexpr DWORD kWaitObject0 = 0x00000000l;
  290. static constexpr DWORD kInfinite = 0xffffffffl;
  291. inline bool try_lock_internal (DWORD ms) noexcept
  292. {
  293. DWORD ret = WaitForSingleObject(mHandle, ms);
  294. #ifndef NDEBUG
  295. if (ret == kWaitAbandoned)
  296. {
  297. using namespace std;
  298. fprintf(stderr, "FATAL: Thread terminated while holding a mutex.");
  299. terminate();
  300. }
  301. #endif
  302. return (ret == kWaitObject0) || (ret == kWaitAbandoned);
  303. }
  304. protected:
  305. HANDLE mHandle;
  306. // Track locking thread for error checking of non-recursive timed_mutex. For
  307. // standard compliance, this must be defined in same class and at the same
  308. // access-control level as every other variable in the timed_mutex.
  309. #if STDMUTEX_RECURSION_CHECKS
  310. friend class vista::condition_variable;
  311. _OwnerThread mOwnerThread {};
  312. #endif
  313. public:
  314. typedef HANDLE native_handle_type;
  315. native_handle_type native_handle() const {return mHandle;}
  316. recursive_timed_mutex(const recursive_timed_mutex&) = delete;
  317. recursive_timed_mutex& operator=(const recursive_timed_mutex&) = delete;
  318. recursive_timed_mutex(): mHandle(CreateMutex(NULL, FALSE, NULL)) {}
  319. ~recursive_timed_mutex()
  320. {
  321. CloseHandle(mHandle);
  322. }
  323. void lock()
  324. {
  325. DWORD ret = WaitForSingleObject(mHandle, kInfinite);
  326. // If (ret == WAIT_ABANDONED), then the thread that held ownership was
  327. // terminated. Behavior is undefined, but Windows will pass ownership to this
  328. // thread.
  329. #ifndef NDEBUG
  330. if (ret == kWaitAbandoned)
  331. {
  332. using namespace std;
  333. fprintf(stderr, "FATAL: Thread terminated while holding a mutex.");
  334. terminate();
  335. }
  336. #endif
  337. if ((ret != kWaitObject0) && (ret != kWaitAbandoned))
  338. {
  339. throw std::system_error(GetLastError(), std::system_category());
  340. }
  341. }
  342. void unlock()
  343. {
  344. if (!ReleaseMutex(mHandle))
  345. throw std::system_error(GetLastError(), std::system_category());
  346. }
  347. bool try_lock()
  348. {
  349. return try_lock_internal(0);
  350. }
  351. template <class Rep, class Period>
  352. bool try_lock_for(const std::chrono::duration<Rep,Period>& dur)
  353. {
  354. using namespace std::chrono;
  355. auto timeout = duration_cast<milliseconds>(dur).count();
  356. while (timeout > 0)
  357. {
  358. constexpr auto kMaxStep = static_cast<decltype(timeout)>(kInfinite-1);
  359. auto step = (timeout < kMaxStep) ? timeout : kMaxStep;
  360. if (try_lock_internal(static_cast<DWORD>(step)))
  361. return true;
  362. timeout -= step;
  363. }
  364. return false;
  365. }
  366. template <class Clock, class Duration>
  367. bool try_lock_until(const std::chrono::time_point<Clock,Duration>& timeout_time)
  368. {
  369. return try_lock_for(timeout_time - Clock::now());
  370. }
  371. };
  372. // Override if, and only if, it is necessary for error-checking.
  373. #if STDMUTEX_RECURSION_CHECKS
  374. class timed_mutex: recursive_timed_mutex
  375. {
  376. public:
  377. timed_mutex(const timed_mutex&) = delete;
  378. timed_mutex& operator=(const timed_mutex&) = delete;
  379. void lock()
  380. {
  381. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  382. recursive_timed_mutex::lock();
  383. mOwnerThread.setOwnerAfterLock(self);
  384. }
  385. void unlock()
  386. {
  387. mOwnerThread.checkSetOwnerBeforeUnlock();
  388. recursive_timed_mutex::unlock();
  389. }
  390. template <class Rep, class Period>
  391. bool try_lock_for(const std::chrono::duration<Rep,Period>& dur)
  392. {
  393. DWORD self = mOwnerThread.checkOwnerBeforeLock();
  394. bool ret = recursive_timed_mutex::try_lock_for(dur);
  395. if (ret)
  396. mOwnerThread.setOwnerAfterLock(self);
  397. return ret;
  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. bool try_lock ()
  405. {
  406. return try_lock_for(std::chrono::milliseconds(0));
  407. }
  408. };
  409. #else
  410. typedef recursive_timed_mutex timed_mutex;
  411. #endif
  412. class once_flag
  413. {
  414. // When available, the SRW-based mutexes should be faster than the
  415. // CriticalSection-based mutexes. Only try_lock will be unavailable in Vista,
  416. // and try_lock is not used by once_flag.
  417. #if (_WIN32_WINNT == _WIN32_WINNT_VISTA)
  418. windows7::mutex mMutex;
  419. #else
  420. mutex mMutex;
  421. #endif
  422. std::atomic_bool mHasRun;
  423. once_flag(const once_flag&) = delete;
  424. once_flag& operator=(const once_flag&) = delete;
  425. template<class Callable, class... Args>
  426. friend void call_once(once_flag& once, Callable&& f, Args&&... args);
  427. public:
  428. constexpr once_flag() noexcept: mMutex(), mHasRun(false) {}
  429. };
  430. template<class Callable, class... Args>
  431. void call_once(once_flag& flag, Callable&& func, Args&&... args)
  432. {
  433. if (flag.mHasRun.load(std::memory_order_acquire))
  434. return;
  435. lock_guard<decltype(flag.mMutex)> lock(flag.mMutex);
  436. if (flag.mHasRun.load(std::memory_order_acquire))
  437. return;
  438. detail::invoke(std::forward<Callable>(func),std::forward<Args>(args)...);
  439. flag.mHasRun.store(true, std::memory_order_release);
  440. }
  441. } // Namespace mingw_stdthread
  442. // Push objects into std, but only if they are not already there.
  443. namespace std
  444. {
  445. // Because of quirks of the compiler, the common "using namespace std;"
  446. // directive would flatten the namespaces and introduce ambiguity where there
  447. // was none. Direct specification (std::), however, would be unaffected.
  448. // Take the safe option, and include only in the presence of MinGW's win32
  449. // implementation.
  450. #if defined(__MINGW32__ ) && !defined(_GLIBCXX_HAS_GTHREADS)
  451. using mingw_stdthread::recursive_mutex;
  452. using mingw_stdthread::mutex;
  453. using mingw_stdthread::recursive_timed_mutex;
  454. using mingw_stdthread::timed_mutex;
  455. using mingw_stdthread::once_flag;
  456. using mingw_stdthread::call_once;
  457. #elif !defined(MINGW_STDTHREAD_REDUNDANCY_WARNING) // Skip repetition
  458. #define MINGW_STDTHREAD_REDUNDANCY_WARNING
  459. #pragma message "This version of MinGW seems to include a win32 port of\
  460. pthreads, and probably already has C++11 std threading classes implemented,\
  461. based on pthreads. These classes, found in namespace std, are not overridden\
  462. by the mingw-std-thread library. If you would still like to use this\
  463. implementation (as it is more lightweight), use the classes provided in\
  464. namespace mingw_stdthread."
  465. #endif
  466. }
  467. #endif // WIN32STDMUTEX_H