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.

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