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.

290 lines
6.5KB

  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. // -----------------------------------------------------------------------
  22. // CarlaMutex class
  23. class CarlaMutex
  24. {
  25. public:
  26. /*
  27. * Constructor.
  28. */
  29. CarlaMutex(const bool inheritPriority = true) noexcept
  30. : fMutex(),
  31. fTryLockWasCalled(false)
  32. {
  33. pthread_mutexattr_t atts;
  34. pthread_mutexattr_init(&atts);
  35. pthread_mutexattr_setprotocol(&atts, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE);
  36. pthread_mutexattr_settype(&atts, PTHREAD_MUTEX_NORMAL);
  37. pthread_mutex_init(&fMutex, &atts);
  38. pthread_mutexattr_destroy(&atts);
  39. }
  40. /*
  41. * Destructor.
  42. */
  43. ~CarlaMutex() noexcept
  44. {
  45. pthread_mutex_destroy(&fMutex);
  46. }
  47. /*
  48. * Check if "tryLock()" was called before.
  49. */
  50. bool wasTryLockCalled() const noexcept
  51. {
  52. const bool ret(fTryLockWasCalled);
  53. fTryLockWasCalled = false;
  54. return ret;
  55. }
  56. /*
  57. * Lock the mutex.
  58. */
  59. void lock() const noexcept
  60. {
  61. pthread_mutex_lock(&fMutex);
  62. }
  63. /*
  64. * Try to lock the mutex.
  65. * Returns true if successful.
  66. */
  67. bool tryLock() const noexcept
  68. {
  69. fTryLockWasCalled = true;
  70. return (pthread_mutex_trylock(&fMutex) == 0);
  71. }
  72. /*
  73. * Unlock the mutex, optionally resetting the tryLock check.
  74. */
  75. void unlock(const bool resetTryLock = false) const noexcept
  76. {
  77. if (resetTryLock)
  78. fTryLockWasCalled = false;
  79. pthread_mutex_unlock(&fMutex);
  80. }
  81. private:
  82. mutable pthread_mutex_t fMutex;
  83. mutable volatile bool fTryLockWasCalled; // true if "tryLock()" was called at least once
  84. CARLA_PREVENT_HEAP_ALLOCATION
  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 atts;
  106. pthread_mutexattr_init(&atts);
  107. pthread_mutexattr_setprotocol(&atts, PTHREAD_PRIO_INHERIT);
  108. pthread_mutexattr_settype(&atts, PTHREAD_MUTEX_RECURSIVE);
  109. pthread_mutex_init(&fMutex, &atts);
  110. pthread_mutexattr_destroy(&atts);
  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_PREVENT_HEAP_ALLOCATION
  165. CARLA_DECLARE_NON_COPY_CLASS(CarlaRecursiveMutex)
  166. };
  167. // -----------------------------------------------------------------------
  168. // Helper class to lock&unlock a mutex during a function scope.
  169. template <class Mutex>
  170. class CarlaScopeLocker
  171. {
  172. public:
  173. CarlaScopeLocker(const Mutex& mutex) noexcept
  174. : fMutex(mutex)
  175. {
  176. fMutex.lock();
  177. }
  178. ~CarlaScopeLocker() noexcept
  179. {
  180. fMutex.unlock();
  181. }
  182. private:
  183. const Mutex& fMutex;
  184. CARLA_PREVENT_HEAP_ALLOCATION
  185. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeLocker)
  186. };
  187. // -----------------------------------------------------------------------
  188. // Helper class to try-lock&unlock a mutex during a function scope.
  189. template <class Mutex>
  190. class CarlaScopeTryLocker
  191. {
  192. public:
  193. CarlaScopeTryLocker(const Mutex& mutex) noexcept
  194. : fMutex(mutex),
  195. fLocked(mutex.tryLock()) {}
  196. ~CarlaScopeTryLocker() noexcept
  197. {
  198. if (fLocked)
  199. fMutex.unlock();
  200. }
  201. bool wasLocked() const noexcept
  202. {
  203. return fLocked;
  204. }
  205. bool wasNotLocked() const noexcept
  206. {
  207. return !fLocked;
  208. }
  209. private:
  210. const Mutex& fMutex;
  211. const bool fLocked;
  212. CARLA_PREVENT_HEAP_ALLOCATION
  213. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeTryLocker)
  214. };
  215. // -----------------------------------------------------------------------
  216. // Helper class to unlock&lock a mutex during a function scope.
  217. template <class Mutex>
  218. class CarlaScopeUnlocker
  219. {
  220. public:
  221. CarlaScopeUnlocker(const Mutex& mutex) noexcept
  222. : fMutex(mutex)
  223. {
  224. fMutex.unlock();
  225. }
  226. ~CarlaScopeUnlocker() noexcept
  227. {
  228. fMutex.lock();
  229. }
  230. private:
  231. const Mutex& fMutex;
  232. CARLA_PREVENT_HEAP_ALLOCATION
  233. CARLA_DECLARE_NON_COPY_CLASS(CarlaScopeUnlocker)
  234. };
  235. // -----------------------------------------------------------------------
  236. // Define types
  237. typedef CarlaScopeLocker<CarlaMutex> CarlaMutexLocker;
  238. typedef CarlaScopeLocker<CarlaRecursiveMutex> CarlaRecursiveMutexLocker;
  239. typedef CarlaScopeTryLocker<CarlaMutex> CarlaMutexTryLocker;
  240. typedef CarlaScopeTryLocker<CarlaRecursiveMutex> CarlaRecursiveMutexTryLocker;
  241. typedef CarlaScopeUnlocker<CarlaMutex> CarlaMutexUnlocker;
  242. typedef CarlaScopeUnlocker<CarlaRecursiveMutex> CarlaRecursiveMutexUnlocker;
  243. // -----------------------------------------------------------------------
  244. #endif // CARLA_MUTEX_HPP_INCLUDED