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.

371 lines
8.2KB

  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. CARLA_DECLARE_NON_COPY_CLASS(CarlaMutex)
  86. };
  87. // -----------------------------------------------------------------------
  88. // CarlaRecursiveMutex class
  89. class CarlaRecursiveMutex
  90. {
  91. public:
  92. /*
  93. * Constructor.
  94. */
  95. CarlaRecursiveMutex() noexcept
  96. #ifdef CARLA_OS_WIN
  97. : fSection()
  98. #else
  99. : fMutex()
  100. #endif
  101. {
  102. #ifdef CARLA_OS_WIN
  103. InitializeCriticalSection(&fSection);
  104. #else
  105. pthread_mutexattr_t attr;
  106. pthread_mutexattr_init(&attr);
  107. pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
  108. pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
  109. pthread_mutex_init(&fMutex, &attr);
  110. pthread_mutexattr_destroy(&attr);
  111. #endif
  112. }
  113. /*
  114. * Destructor.
  115. */
  116. ~CarlaRecursiveMutex() noexcept
  117. {
  118. #ifdef CARLA_OS_WIN
  119. DeleteCriticalSection(&fSection);
  120. #else
  121. pthread_mutex_destroy(&fMutex);
  122. #endif
  123. }
  124. /*
  125. * Lock the mutex.
  126. */
  127. void lock() const noexcept
  128. {
  129. #ifdef CARLA_OS_WIN
  130. EnterCriticalSection(&fSection);
  131. #else
  132. pthread_mutex_lock(&fMutex);
  133. #endif
  134. }
  135. /*
  136. * Try to lock the mutex.
  137. * Returns true if successful.
  138. */
  139. bool tryLock() const noexcept
  140. {
  141. #ifdef CARLA_OS_WIN
  142. return (TryEnterCriticalSection(&fSection) != FALSE);
  143. #else
  144. return (pthread_mutex_trylock(&fMutex) == 0);
  145. #endif
  146. }
  147. /*
  148. * Unlock the mutex.
  149. */
  150. void unlock() const noexcept
  151. {
  152. #ifdef CARLA_OS_WIN
  153. LeaveCriticalSection(&fSection);
  154. #else
  155. pthread_mutex_unlock(&fMutex);
  156. #endif
  157. }
  158. private:
  159. #ifdef CARLA_OS_WIN
  160. mutable CRITICAL_SECTION fSection;
  161. #else
  162. mutable pthread_mutex_t fMutex;
  163. #endif
  164. CARLA_DECLARE_NON_COPY_CLASS(CarlaRecursiveMutex)
  165. };
  166. // -----------------------------------------------------------------------
  167. // CarlaSignal class
  168. class CarlaSignal
  169. {
  170. public:
  171. /*
  172. * Constructor.
  173. */
  174. CarlaSignal() noexcept
  175. : fCondition(),
  176. fMutex(),
  177. fTriggered(false)
  178. {
  179. pthread_condattr_t cattr;
  180. pthread_condattr_init(&cattr);
  181. pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
  182. pthread_cond_init(&fCondition, &cattr);
  183. pthread_condattr_destroy(&cattr);
  184. pthread_mutexattr_t mattr;
  185. pthread_mutexattr_init(&mattr);
  186. pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
  187. pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
  188. pthread_mutex_init(&fMutex, &mattr);
  189. pthread_mutexattr_destroy(&mattr);
  190. }
  191. /*
  192. * Destructor.
  193. */
  194. ~CarlaSignal() noexcept
  195. {
  196. pthread_cond_destroy(&fCondition);
  197. pthread_mutex_destroy(&fMutex);
  198. }
  199. /*
  200. * Wait for a signal.
  201. */
  202. void wait() noexcept
  203. {
  204. pthread_mutex_lock(&fMutex);
  205. while (! fTriggered)
  206. {
  207. try {
  208. pthread_cond_wait(&fCondition, &fMutex);
  209. } CARLA_SAFE_EXCEPTION("pthread_cond_wait");
  210. }
  211. fTriggered = false;
  212. pthread_mutex_unlock(&fMutex);
  213. }
  214. /*
  215. * Wake up all waiting threads.
  216. */
  217. void signal() noexcept
  218. {
  219. pthread_mutex_lock(&fMutex);
  220. if (! fTriggered)
  221. {
  222. fTriggered = true;
  223. pthread_cond_broadcast(&fCondition);
  224. }
  225. pthread_mutex_unlock(&fMutex);
  226. }
  227. private:
  228. pthread_cond_t fCondition;
  229. pthread_mutex_t fMutex;
  230. volatile bool fTriggered;
  231. CARLA_PREVENT_HEAP_ALLOCATION
  232. CARLA_DECLARE_NON_COPY_CLASS(CarlaSignal)
  233. };
  234. // -----------------------------------------------------------------------
  235. // Helper class to lock&unlock a mutex during a function scope.
  236. template <class Mutex>
  237. class CarlaScopeLocker
  238. {
  239. public:
  240. CarlaScopeLocker(const Mutex& mutex) noexcept
  241. : fMutex(mutex)
  242. {
  243. fMutex.lock();
  244. }
  245. ~CarlaScopeLocker() noexcept
  246. {
  247. fMutex.unlock();
  248. }
  249. private:
  250. const Mutex& fMutex;
  251. CARLA_PREVENT_HEAP_ALLOCATION
  252. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeLocker)
  253. };
  254. // -----------------------------------------------------------------------
  255. // Helper class to try-lock&unlock a mutex during a function scope.
  256. template <class Mutex>
  257. class CarlaScopeTryLocker
  258. {
  259. public:
  260. CarlaScopeTryLocker(const Mutex& mutex) noexcept
  261. : fMutex(mutex),
  262. fLocked(mutex.tryLock()) {}
  263. ~CarlaScopeTryLocker() noexcept
  264. {
  265. if (fLocked)
  266. fMutex.unlock();
  267. }
  268. bool wasLocked() const noexcept
  269. {
  270. return fLocked;
  271. }
  272. bool wasNotLocked() const noexcept
  273. {
  274. return !fLocked;
  275. }
  276. private:
  277. const Mutex& fMutex;
  278. const bool fLocked;
  279. CARLA_PREVENT_HEAP_ALLOCATION
  280. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeTryLocker)
  281. };
  282. // -----------------------------------------------------------------------
  283. // Helper class to unlock&lock a mutex during a function scope.
  284. template <class Mutex>
  285. class CarlaScopeUnlocker
  286. {
  287. public:
  288. CarlaScopeUnlocker(const Mutex& mutex) noexcept
  289. : fMutex(mutex)
  290. {
  291. fMutex.unlock();
  292. }
  293. ~CarlaScopeUnlocker() noexcept
  294. {
  295. fMutex.lock();
  296. }
  297. private:
  298. const Mutex& fMutex;
  299. CARLA_PREVENT_HEAP_ALLOCATION
  300. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeUnlocker)
  301. };
  302. // -----------------------------------------------------------------------
  303. // Define types
  304. typedef CarlaScopeLocker<CarlaMutex> CarlaMutexLocker;
  305. typedef CarlaScopeLocker<CarlaRecursiveMutex> CarlaRecursiveMutexLocker;
  306. typedef CarlaScopeTryLocker<CarlaMutex> CarlaMutexTryLocker;
  307. typedef CarlaScopeTryLocker<CarlaRecursiveMutex> CarlaRecursiveMutexTryLocker;
  308. typedef CarlaScopeUnlocker<CarlaMutex> CarlaMutexUnlocker;
  309. typedef CarlaScopeUnlocker<CarlaRecursiveMutex> CarlaRecursiveMutexUnlocker;
  310. // -----------------------------------------------------------------------
  311. #endif // CARLA_MUTEX_HPP_INCLUDED