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.

367 lines
8.0KB

  1. /*
  2. * DISTRHO Plugin Framework (DPF)
  3. * Copyright (C) 2012-2021 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. # include <winsock2.h>
  21. # include <windows.h>
  22. #endif
  23. #include <pthread.h>
  24. START_NAMESPACE_DISTRHO
  25. class Signal;
  26. // -----------------------------------------------------------------------
  27. // Mutex class
  28. class Mutex
  29. {
  30. public:
  31. /*
  32. * Constructor.
  33. */
  34. Mutex(const bool inheritPriority = true) noexcept
  35. : fMutex()
  36. {
  37. pthread_mutexattr_t attr;
  38. pthread_mutexattr_init(&attr);
  39. pthread_mutexattr_setprotocol(&attr, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE);
  40. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
  41. pthread_mutex_init(&fMutex, &attr);
  42. pthread_mutexattr_destroy(&attr);
  43. }
  44. /*
  45. * Destructor.
  46. */
  47. ~Mutex() noexcept
  48. {
  49. pthread_mutex_destroy(&fMutex);
  50. }
  51. /*
  52. * Lock the mutex.
  53. */
  54. bool lock() const noexcept
  55. {
  56. return (pthread_mutex_lock(&fMutex) == 0);
  57. }
  58. /*
  59. * Try to lock the mutex.
  60. * Returns true if successful.
  61. */
  62. bool tryLock() const noexcept
  63. {
  64. return (pthread_mutex_trylock(&fMutex) == 0);
  65. }
  66. /*
  67. * Unlock the mutex.
  68. */
  69. void unlock() const noexcept
  70. {
  71. pthread_mutex_unlock(&fMutex);
  72. }
  73. private:
  74. mutable pthread_mutex_t fMutex;
  75. DISTRHO_DECLARE_NON_COPYABLE(Mutex)
  76. };
  77. // -----------------------------------------------------------------------
  78. // RecursiveMutex class
  79. class RecursiveMutex
  80. {
  81. public:
  82. /*
  83. * Constructor.
  84. */
  85. RecursiveMutex() noexcept
  86. #ifdef DISTRHO_OS_WINDOWS
  87. : fSection()
  88. #else
  89. : fMutex()
  90. #endif
  91. {
  92. #ifdef DISTRHO_OS_WINDOWS
  93. InitializeCriticalSection(&fSection);
  94. #else
  95. pthread_mutexattr_t attr;
  96. pthread_mutexattr_init(&attr);
  97. pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
  98. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  99. pthread_mutex_init(&fMutex, &attr);
  100. pthread_mutexattr_destroy(&attr);
  101. #endif
  102. }
  103. /*
  104. * Destructor.
  105. */
  106. ~RecursiveMutex() noexcept
  107. {
  108. #ifdef DISTRHO_OS_WINDOWS
  109. DeleteCriticalSection(&fSection);
  110. #else
  111. pthread_mutex_destroy(&fMutex);
  112. #endif
  113. }
  114. /*
  115. * Lock the mutex.
  116. */
  117. bool lock() const noexcept
  118. {
  119. #ifdef DISTRHO_OS_WINDOWS
  120. EnterCriticalSection(&fSection);
  121. return true;
  122. #else
  123. return (pthread_mutex_lock(&fMutex) == 0);
  124. #endif
  125. }
  126. /*
  127. * Try to lock the mutex.
  128. * Returns true if successful.
  129. */
  130. bool tryLock() const noexcept
  131. {
  132. #ifdef DISTRHO_OS_WINDOWS
  133. return (TryEnterCriticalSection(&fSection) != FALSE);
  134. #else
  135. return (pthread_mutex_trylock(&fMutex) == 0);
  136. #endif
  137. }
  138. /*
  139. * Unlock the mutex.
  140. */
  141. void unlock() const noexcept
  142. {
  143. #ifdef DISTRHO_OS_WINDOWS
  144. LeaveCriticalSection(&fSection);
  145. #else
  146. pthread_mutex_unlock(&fMutex);
  147. #endif
  148. }
  149. private:
  150. #ifdef DISTRHO_OS_WINDOWS
  151. mutable CRITICAL_SECTION fSection;
  152. #else
  153. mutable pthread_mutex_t fMutex;
  154. #endif
  155. DISTRHO_DECLARE_NON_COPYABLE(RecursiveMutex)
  156. };
  157. // -----------------------------------------------------------------------
  158. // Signal class
  159. class Signal
  160. {
  161. public:
  162. /*
  163. * Constructor.
  164. */
  165. Signal() noexcept
  166. : fCondition(),
  167. fMutex(),
  168. fTriggered(false)
  169. {
  170. pthread_condattr_t cattr;
  171. pthread_condattr_init(&cattr);
  172. pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
  173. pthread_cond_init(&fCondition, &cattr);
  174. pthread_condattr_destroy(&cattr);
  175. pthread_mutexattr_t mattr;
  176. pthread_mutexattr_init(&mattr);
  177. pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
  178. pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
  179. pthread_mutex_init(&fMutex, &mattr);
  180. pthread_mutexattr_destroy(&mattr);
  181. }
  182. /*
  183. * Destructor.
  184. */
  185. ~Signal() noexcept
  186. {
  187. pthread_cond_destroy(&fCondition);
  188. pthread_mutex_destroy(&fMutex);
  189. }
  190. /*
  191. * Wait for a signal.
  192. */
  193. void wait() noexcept
  194. {
  195. pthread_mutex_lock(&fMutex);
  196. while (! fTriggered)
  197. {
  198. try {
  199. pthread_cond_wait(&fCondition, &fMutex);
  200. } DISTRHO_SAFE_EXCEPTION("pthread_cond_wait");
  201. }
  202. fTriggered = false;
  203. pthread_mutex_unlock(&fMutex);
  204. }
  205. /*
  206. * Wake up all waiting threads.
  207. */
  208. void signal() noexcept
  209. {
  210. pthread_mutex_lock(&fMutex);
  211. if (! fTriggered)
  212. {
  213. fTriggered = true;
  214. pthread_cond_broadcast(&fCondition);
  215. }
  216. pthread_mutex_unlock(&fMutex);
  217. }
  218. private:
  219. pthread_cond_t fCondition;
  220. pthread_mutex_t fMutex;
  221. volatile bool fTriggered;
  222. DISTRHO_PREVENT_HEAP_ALLOCATION
  223. DISTRHO_DECLARE_NON_COPYABLE(Signal)
  224. };
  225. // -----------------------------------------------------------------------
  226. // Helper class to lock&unlock a mutex during a function scope.
  227. template <class Mutex>
  228. class ScopeLocker
  229. {
  230. public:
  231. ScopeLocker(const Mutex& mutex) noexcept
  232. : fMutex(mutex)
  233. {
  234. fMutex.lock();
  235. }
  236. ~ScopeLocker() noexcept
  237. {
  238. fMutex.unlock();
  239. }
  240. private:
  241. const Mutex& fMutex;
  242. DISTRHO_PREVENT_HEAP_ALLOCATION
  243. DISTRHO_DECLARE_NON_COPYABLE(ScopeLocker)
  244. };
  245. // -----------------------------------------------------------------------
  246. // Helper class to try-lock&unlock a mutex during a function scope.
  247. template <class Mutex>
  248. class ScopeTryLocker
  249. {
  250. public:
  251. ScopeTryLocker(const Mutex& mutex) noexcept
  252. : fMutex(mutex),
  253. fLocked(mutex.tryLock()) {}
  254. ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept
  255. : fMutex(mutex),
  256. fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {}
  257. ~ScopeTryLocker() noexcept
  258. {
  259. if (fLocked)
  260. fMutex.unlock();
  261. }
  262. bool wasLocked() const noexcept
  263. {
  264. return fLocked;
  265. }
  266. bool wasNotLocked() const noexcept
  267. {
  268. return !fLocked;
  269. }
  270. private:
  271. const Mutex& fMutex;
  272. const bool fLocked;
  273. DISTRHO_PREVENT_HEAP_ALLOCATION
  274. DISTRHO_DECLARE_NON_COPYABLE(ScopeTryLocker)
  275. };
  276. // -----------------------------------------------------------------------
  277. // Helper class to unlock&lock a mutex during a function scope.
  278. template <class Mutex>
  279. class ScopeUnlocker
  280. {
  281. public:
  282. ScopeUnlocker(const Mutex& mutex) noexcept
  283. : fMutex(mutex)
  284. {
  285. fMutex.unlock();
  286. }
  287. ~ScopeUnlocker() noexcept
  288. {
  289. fMutex.lock();
  290. }
  291. private:
  292. const Mutex& fMutex;
  293. DISTRHO_PREVENT_HEAP_ALLOCATION
  294. DISTRHO_DECLARE_NON_COPYABLE(ScopeUnlocker)
  295. };
  296. // -----------------------------------------------------------------------
  297. // Define types
  298. typedef ScopeLocker<Mutex> MutexLocker;
  299. typedef ScopeLocker<RecursiveMutex> RecursiveMutexLocker;
  300. typedef ScopeTryLocker<Mutex> MutexTryLocker;
  301. typedef ScopeTryLocker<RecursiveMutex> RecursiveMutexTryLocker;
  302. typedef ScopeUnlocker<Mutex> MutexUnlocker;
  303. typedef ScopeUnlocker<RecursiveMutex> RecursiveMutexUnlocker;
  304. // -----------------------------------------------------------------------
  305. END_NAMESPACE_DISTRHO
  306. #endif // DISTRHO_MUTEX_HPP_INCLUDED