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.

357 lines
7.9KB

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