Collection of DPF-based plugins for packaging
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.

370 lines
8.1KB

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