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.

374 lines
8.3KB

  1. /*
  2. * Carla Mutex
  3. * Copyright (C) 2013-2016 Filipe Coelho <falktx@falktx.com>
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License as
  7. * published by the Free Software Foundation; either version 2 of
  8. * the License, or any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * For a full copy of the GNU General Public License see the doc/GPL.txt file.
  16. */
  17. #ifndef CARLA_MUTEX_HPP_INCLUDED
  18. #define CARLA_MUTEX_HPP_INCLUDED
  19. #include "CarlaUtils.hpp"
  20. #include <pthread.h>
  21. class CarlaSignal;
  22. // -----------------------------------------------------------------------
  23. // CarlaMutex class
  24. class CarlaMutex
  25. {
  26. public:
  27. /*
  28. * Constructor.
  29. */
  30. CarlaMutex(const bool inheritPriority = true) noexcept
  31. : fMutex(),
  32. fTryLockWasCalled(false)
  33. {
  34. pthread_mutexattr_t attr;
  35. pthread_mutexattr_init(&attr);
  36. pthread_mutexattr_setprotocol(&attr, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE);
  37. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
  38. pthread_mutex_init(&fMutex, &attr);
  39. pthread_mutexattr_destroy(&attr);
  40. }
  41. /*
  42. * Destructor.
  43. */
  44. ~CarlaMutex() noexcept
  45. {
  46. pthread_mutex_destroy(&fMutex);
  47. }
  48. /*
  49. * Check if "tryLock()" was called before.
  50. */
  51. bool wasTryLockCalled() const noexcept
  52. {
  53. const bool ret(fTryLockWasCalled);
  54. fTryLockWasCalled = false;
  55. return ret;
  56. }
  57. /*
  58. * Lock the mutex.
  59. */
  60. void lock() const noexcept
  61. {
  62. pthread_mutex_lock(&fMutex);
  63. }
  64. /*
  65. * Try to lock the mutex.
  66. * Returns true if successful.
  67. */
  68. bool tryLock() const noexcept
  69. {
  70. fTryLockWasCalled = true;
  71. return (pthread_mutex_trylock(&fMutex) == 0);
  72. }
  73. /*
  74. * Unlock the mutex, optionally resetting the tryLock check.
  75. */
  76. void unlock(const bool resetTryLock = false) const noexcept
  77. {
  78. if (resetTryLock)
  79. fTryLockWasCalled = false;
  80. pthread_mutex_unlock(&fMutex);
  81. }
  82. private:
  83. mutable pthread_mutex_t fMutex;
  84. mutable volatile bool fTryLockWasCalled; // true if "tryLock()" was called at least once
  85. friend class CarlaSignal;
  86. CARLA_PREVENT_HEAP_ALLOCATION
  87. CARLA_DECLARE_NON_COPY_CLASS(CarlaMutex)
  88. };
  89. // -----------------------------------------------------------------------
  90. // CarlaRecursiveMutex class
  91. class CarlaRecursiveMutex
  92. {
  93. public:
  94. /*
  95. * Constructor.
  96. */
  97. CarlaRecursiveMutex() noexcept
  98. #ifdef CARLA_OS_WIN
  99. : fSection()
  100. #else
  101. : fMutex()
  102. #endif
  103. {
  104. #ifdef CARLA_OS_WIN
  105. InitializeCriticalSection(&fSection);
  106. #else
  107. pthread_mutexattr_t attr;
  108. pthread_mutexattr_init(&attr);
  109. pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
  110. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  111. pthread_mutex_init(&fMutex, &attr);
  112. pthread_mutexattr_destroy(&attr);
  113. #endif
  114. }
  115. /*
  116. * Destructor.
  117. */
  118. ~CarlaRecursiveMutex() noexcept
  119. {
  120. #ifdef CARLA_OS_WIN
  121. DeleteCriticalSection(&fSection);
  122. #else
  123. pthread_mutex_destroy(&fMutex);
  124. #endif
  125. }
  126. /*
  127. * Lock the mutex.
  128. */
  129. void lock() const noexcept
  130. {
  131. #ifdef CARLA_OS_WIN
  132. EnterCriticalSection(&fSection);
  133. #else
  134. pthread_mutex_lock(&fMutex);
  135. #endif
  136. }
  137. /*
  138. * Try to lock the mutex.
  139. * Returns true if successful.
  140. */
  141. bool tryLock() const noexcept
  142. {
  143. #ifdef CARLA_OS_WIN
  144. return (TryEnterCriticalSection(&fSection) != FALSE);
  145. #else
  146. return (pthread_mutex_trylock(&fMutex) == 0);
  147. #endif
  148. }
  149. /*
  150. * Unlock the mutex.
  151. */
  152. void unlock() const noexcept
  153. {
  154. #ifdef CARLA_OS_WIN
  155. LeaveCriticalSection(&fSection);
  156. #else
  157. pthread_mutex_unlock(&fMutex);
  158. #endif
  159. }
  160. private:
  161. #ifdef CARLA_OS_WIN
  162. mutable CRITICAL_SECTION fSection;
  163. #else
  164. mutable pthread_mutex_t fMutex;
  165. #endif
  166. CARLA_PREVENT_HEAP_ALLOCATION
  167. CARLA_DECLARE_NON_COPY_CLASS(CarlaRecursiveMutex)
  168. };
  169. // -----------------------------------------------------------------------
  170. // CarlaSignal class
  171. class CarlaSignal
  172. {
  173. public:
  174. /*
  175. * Constructor.
  176. */
  177. CarlaSignal() noexcept
  178. : fCondition(),
  179. fMutex(),
  180. fTriggered(false)
  181. {
  182. pthread_condattr_t cattr;
  183. pthread_condattr_init(&cattr);
  184. pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
  185. pthread_cond_init(&fCondition, &cattr);
  186. pthread_condattr_destroy(&cattr);
  187. pthread_mutexattr_t mattr;
  188. pthread_mutexattr_init(&mattr);
  189. pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
  190. pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
  191. pthread_mutex_init(&fMutex, &mattr);
  192. pthread_mutexattr_destroy(&mattr);
  193. }
  194. /*
  195. * Destructor.
  196. */
  197. ~CarlaSignal() noexcept
  198. {
  199. pthread_cond_destroy(&fCondition);
  200. pthread_mutex_destroy(&fMutex);
  201. }
  202. /*
  203. * Wait for a signal.
  204. */
  205. void wait() noexcept
  206. {
  207. pthread_mutex_lock(&fMutex);
  208. while (! fTriggered)
  209. {
  210. try {
  211. pthread_cond_wait(&fCondition, &fMutex);
  212. } CARLA_SAFE_EXCEPTION("pthread_cond_wait");
  213. }
  214. fTriggered = false;
  215. pthread_mutex_unlock(&fMutex);
  216. }
  217. /*
  218. * Wake up all waiting threads.
  219. */
  220. void signal() noexcept
  221. {
  222. pthread_mutex_lock(&fMutex);
  223. if (! fTriggered)
  224. {
  225. fTriggered = true;
  226. pthread_cond_broadcast(&fCondition);
  227. }
  228. pthread_mutex_unlock(&fMutex);
  229. }
  230. private:
  231. pthread_cond_t fCondition;
  232. pthread_mutex_t fMutex;
  233. volatile bool fTriggered;
  234. CARLA_PREVENT_HEAP_ALLOCATION
  235. CARLA_DECLARE_NON_COPY_CLASS(CarlaSignal)
  236. };
  237. // -----------------------------------------------------------------------
  238. // Helper class to lock&unlock a mutex during a function scope.
  239. template <class Mutex>
  240. class CarlaScopeLocker
  241. {
  242. public:
  243. CarlaScopeLocker(const Mutex& mutex) noexcept
  244. : fMutex(mutex)
  245. {
  246. fMutex.lock();
  247. }
  248. ~CarlaScopeLocker() noexcept
  249. {
  250. fMutex.unlock();
  251. }
  252. private:
  253. const Mutex& fMutex;
  254. CARLA_PREVENT_HEAP_ALLOCATION
  255. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeLocker)
  256. };
  257. // -----------------------------------------------------------------------
  258. // Helper class to try-lock&unlock a mutex during a function scope.
  259. template <class Mutex>
  260. class CarlaScopeTryLocker
  261. {
  262. public:
  263. CarlaScopeTryLocker(const Mutex& mutex) noexcept
  264. : fMutex(mutex),
  265. fLocked(mutex.tryLock()) {}
  266. ~CarlaScopeTryLocker() noexcept
  267. {
  268. if (fLocked)
  269. fMutex.unlock();
  270. }
  271. bool wasLocked() const noexcept
  272. {
  273. return fLocked;
  274. }
  275. bool wasNotLocked() const noexcept
  276. {
  277. return !fLocked;
  278. }
  279. private:
  280. const Mutex& fMutex;
  281. const bool fLocked;
  282. CARLA_PREVENT_HEAP_ALLOCATION
  283. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeTryLocker)
  284. };
  285. // -----------------------------------------------------------------------
  286. // Helper class to unlock&lock a mutex during a function scope.
  287. template <class Mutex>
  288. class CarlaScopeUnlocker
  289. {
  290. public:
  291. CarlaScopeUnlocker(const Mutex& mutex) noexcept
  292. : fMutex(mutex)
  293. {
  294. fMutex.unlock();
  295. }
  296. ~CarlaScopeUnlocker() noexcept
  297. {
  298. fMutex.lock();
  299. }
  300. private:
  301. const Mutex& fMutex;
  302. CARLA_PREVENT_HEAP_ALLOCATION
  303. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeUnlocker)
  304. };
  305. // -----------------------------------------------------------------------
  306. // Define types
  307. typedef CarlaScopeLocker<CarlaMutex> CarlaMutexLocker;
  308. typedef CarlaScopeLocker<CarlaRecursiveMutex> CarlaRecursiveMutexLocker;
  309. typedef CarlaScopeTryLocker<CarlaMutex> CarlaMutexTryLocker;
  310. typedef CarlaScopeTryLocker<CarlaRecursiveMutex> CarlaRecursiveMutexTryLocker;
  311. typedef CarlaScopeUnlocker<CarlaMutex> CarlaMutexUnlocker;
  312. typedef CarlaScopeUnlocker<CarlaRecursiveMutex> CarlaRecursiveMutexUnlocker;
  313. // -----------------------------------------------------------------------
  314. #endif // CARLA_MUTEX_HPP_INCLUDED