DISTRHO Plugin Framework
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.

399 lines
8.9KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2022 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * Permission to use, copy, modify, and/or distribute this software for any purpose with
  6. * or without fee is hereby granted, provided that the above copyright notice and this
  7. * permission notice appear in all copies.
  8. *
  9. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
  10. * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
  11. * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
  12. * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
  13. * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  14. * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #ifndef DISTRHO_MUTEX_HPP_INCLUDED
  17. #define DISTRHO_MUTEX_HPP_INCLUDED
  18. #include "../DistrhoUtils.hpp"
  19. #ifdef DISTRHO_OS_WINDOWS
  20. # ifndef NOMINMAX
  21. # define NOMINMAX
  22. # endif
  23. # include <winsock2.h>
  24. # include <windows.h>
  25. #endif
  26. // FIXME make Mutex stop relying on pthread
  27. #ifdef _MSC_VER
  28. #define DISTRHO_OS_WINDOWS__TODO
  29. #pragma NOTE(DPF Mutex implementation is TODO on MSVC)
  30. #else
  31. #include <pthread.h>
  32. #endif
  33. START_NAMESPACE_DISTRHO
  34. class Signal;
  35. // -----------------------------------------------------------------------
  36. // Mutex class
  37. class Mutex
  38. {
  39. public:
  40. /*
  41. * Constructor.
  42. */
  43. Mutex(const bool inheritPriority = true) noexcept
  44. #ifdef DISTRHO_OS_WINDOWS__TODO
  45. #else
  46. : fMutex()
  47. #endif
  48. {
  49. #ifdef DISTRHO_OS_WINDOWS__TODO
  50. #else
  51. pthread_mutexattr_t attr;
  52. pthread_mutexattr_init(&attr);
  53. pthread_mutexattr_setprotocol(&attr, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE);
  54. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
  55. pthread_mutex_init(&fMutex, &attr);
  56. pthread_mutexattr_destroy(&attr);
  57. #endif
  58. }
  59. /*
  60. * Destructor.
  61. */
  62. ~Mutex() noexcept
  63. {
  64. #ifdef DISTRHO_OS_WINDOWS__TODO
  65. #else
  66. pthread_mutex_destroy(&fMutex);
  67. #endif
  68. }
  69. /*
  70. * Lock the mutex.
  71. */
  72. bool lock() const noexcept
  73. {
  74. #ifdef DISTRHO_OS_WINDOWS__TODO
  75. #else
  76. return (pthread_mutex_lock(&fMutex) == 0);
  77. #endif
  78. }
  79. /*
  80. * Try to lock the mutex.
  81. * Returns true if successful.
  82. */
  83. bool tryLock() const noexcept
  84. {
  85. #ifdef DISTRHO_OS_WINDOWS__TODO
  86. #else
  87. return (pthread_mutex_trylock(&fMutex) == 0);
  88. #endif
  89. }
  90. /*
  91. * Unlock the mutex.
  92. */
  93. void unlock() const noexcept
  94. {
  95. #ifdef DISTRHO_OS_WINDOWS__TODO
  96. #else
  97. pthread_mutex_unlock(&fMutex);
  98. #endif
  99. }
  100. private:
  101. #ifdef DISTRHO_OS_WINDOWS__TODO
  102. #else
  103. mutable pthread_mutex_t fMutex;
  104. #endif
  105. DISTRHO_DECLARE_NON_COPYABLE(Mutex)
  106. };
  107. // -----------------------------------------------------------------------
  108. // RecursiveMutex class
  109. class RecursiveMutex
  110. {
  111. public:
  112. /*
  113. * Constructor.
  114. */
  115. RecursiveMutex() noexcept
  116. #ifdef DISTRHO_OS_WINDOWS
  117. : fSection()
  118. #else
  119. : fMutex()
  120. #endif
  121. {
  122. #ifdef DISTRHO_OS_WINDOWS
  123. InitializeCriticalSection(&fSection);
  124. #else
  125. pthread_mutexattr_t attr;
  126. pthread_mutexattr_init(&attr);
  127. pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
  128. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  129. pthread_mutex_init(&fMutex, &attr);
  130. pthread_mutexattr_destroy(&attr);
  131. #endif
  132. }
  133. /*
  134. * Destructor.
  135. */
  136. ~RecursiveMutex() noexcept
  137. {
  138. #ifdef DISTRHO_OS_WINDOWS
  139. DeleteCriticalSection(&fSection);
  140. #else
  141. pthread_mutex_destroy(&fMutex);
  142. #endif
  143. }
  144. /*
  145. * Lock the mutex.
  146. */
  147. bool lock() const noexcept
  148. {
  149. #ifdef DISTRHO_OS_WINDOWS
  150. EnterCriticalSection(&fSection);
  151. return true;
  152. #else
  153. return (pthread_mutex_lock(&fMutex) == 0);
  154. #endif
  155. }
  156. /*
  157. * Try to lock the mutex.
  158. * Returns true if successful.
  159. */
  160. bool tryLock() const noexcept
  161. {
  162. #ifdef DISTRHO_OS_WINDOWS
  163. return (TryEnterCriticalSection(&fSection) != FALSE);
  164. #else
  165. return (pthread_mutex_trylock(&fMutex) == 0);
  166. #endif
  167. }
  168. /*
  169. * Unlock the mutex.
  170. */
  171. void unlock() const noexcept
  172. {
  173. #ifdef DISTRHO_OS_WINDOWS
  174. LeaveCriticalSection(&fSection);
  175. #else
  176. pthread_mutex_unlock(&fMutex);
  177. #endif
  178. }
  179. private:
  180. #ifdef DISTRHO_OS_WINDOWS
  181. mutable CRITICAL_SECTION fSection;
  182. #else
  183. mutable pthread_mutex_t fMutex;
  184. #endif
  185. DISTRHO_DECLARE_NON_COPYABLE(RecursiveMutex)
  186. };
  187. #ifndef _MSC_VER
  188. // -----------------------------------------------------------------------
  189. // Signal class
  190. class Signal
  191. {
  192. public:
  193. /*
  194. * Constructor.
  195. */
  196. Signal() noexcept
  197. : fCondition(),
  198. fMutex(),
  199. fTriggered(false)
  200. {
  201. pthread_condattr_t cattr;
  202. pthread_condattr_init(&cattr);
  203. pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
  204. pthread_cond_init(&fCondition, &cattr);
  205. pthread_condattr_destroy(&cattr);
  206. pthread_mutexattr_t mattr;
  207. pthread_mutexattr_init(&mattr);
  208. pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
  209. pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
  210. pthread_mutex_init(&fMutex, &mattr);
  211. pthread_mutexattr_destroy(&mattr);
  212. }
  213. /*
  214. * Destructor.
  215. */
  216. ~Signal() noexcept
  217. {
  218. pthread_cond_destroy(&fCondition);
  219. pthread_mutex_destroy(&fMutex);
  220. }
  221. /*
  222. * Wait for a signal.
  223. */
  224. void wait() noexcept
  225. {
  226. pthread_mutex_lock(&fMutex);
  227. while (! fTriggered)
  228. {
  229. try {
  230. pthread_cond_wait(&fCondition, &fMutex);
  231. } DISTRHO_SAFE_EXCEPTION("pthread_cond_wait");
  232. }
  233. fTriggered = false;
  234. pthread_mutex_unlock(&fMutex);
  235. }
  236. /*
  237. * Wake up all waiting threads.
  238. */
  239. void signal() noexcept
  240. {
  241. pthread_mutex_lock(&fMutex);
  242. if (! fTriggered)
  243. {
  244. fTriggered = true;
  245. pthread_cond_broadcast(&fCondition);
  246. }
  247. pthread_mutex_unlock(&fMutex);
  248. }
  249. private:
  250. pthread_cond_t fCondition;
  251. pthread_mutex_t fMutex;
  252. volatile bool fTriggered;
  253. DISTRHO_PREVENT_HEAP_ALLOCATION
  254. DISTRHO_DECLARE_NON_COPYABLE(Signal)
  255. };
  256. #endif // _MSC_VER
  257. // -----------------------------------------------------------------------
  258. // Helper class to lock&unlock a mutex during a function scope.
  259. template <class Mutex>
  260. class ScopeLocker
  261. {
  262. public:
  263. ScopeLocker(const Mutex& mutex) noexcept
  264. : fMutex(mutex)
  265. {
  266. fMutex.lock();
  267. }
  268. ~ScopeLocker() noexcept
  269. {
  270. fMutex.unlock();
  271. }
  272. private:
  273. const Mutex& fMutex;
  274. DISTRHO_PREVENT_HEAP_ALLOCATION
  275. DISTRHO_DECLARE_NON_COPYABLE(ScopeLocker)
  276. };
  277. // -----------------------------------------------------------------------
  278. // Helper class to try-lock&unlock a mutex during a function scope.
  279. template <class Mutex>
  280. class ScopeTryLocker
  281. {
  282. public:
  283. ScopeTryLocker(const Mutex& mutex) noexcept
  284. : fMutex(mutex),
  285. fLocked(mutex.tryLock()) {}
  286. ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept
  287. : fMutex(mutex),
  288. fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {}
  289. ~ScopeTryLocker() noexcept
  290. {
  291. if (fLocked)
  292. fMutex.unlock();
  293. }
  294. bool wasLocked() const noexcept
  295. {
  296. return fLocked;
  297. }
  298. bool wasNotLocked() const noexcept
  299. {
  300. return !fLocked;
  301. }
  302. private:
  303. const Mutex& fMutex;
  304. const bool fLocked;
  305. DISTRHO_PREVENT_HEAP_ALLOCATION
  306. DISTRHO_DECLARE_NON_COPYABLE(ScopeTryLocker)
  307. };
  308. // -----------------------------------------------------------------------
  309. // Helper class to unlock&lock a mutex during a function scope.
  310. template <class Mutex>
  311. class ScopeUnlocker
  312. {
  313. public:
  314. ScopeUnlocker(const Mutex& mutex) noexcept
  315. : fMutex(mutex)
  316. {
  317. fMutex.unlock();
  318. }
  319. ~ScopeUnlocker() noexcept
  320. {
  321. fMutex.lock();
  322. }
  323. private:
  324. const Mutex& fMutex;
  325. DISTRHO_PREVENT_HEAP_ALLOCATION
  326. DISTRHO_DECLARE_NON_COPYABLE(ScopeUnlocker)
  327. };
  328. // -----------------------------------------------------------------------
  329. // Define types
  330. typedef ScopeLocker<Mutex> MutexLocker;
  331. typedef ScopeLocker<RecursiveMutex> RecursiveMutexLocker;
  332. typedef ScopeTryLocker<Mutex> MutexTryLocker;
  333. typedef ScopeTryLocker<RecursiveMutex> RecursiveMutexTryLocker;
  334. typedef ScopeUnlocker<Mutex> MutexUnlocker;
  335. typedef ScopeUnlocker<RecursiveMutex> RecursiveMutexUnlocker;
  336. // -----------------------------------------------------------------------
  337. END_NAMESPACE_DISTRHO
  338. #endif // DISTRHO_MUTEX_HPP_INCLUDED