DISTRHO Plugin Framework
Mutex.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2021 Filipe Coelho <falktx@falktx.com>
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any purpose with
6  * or without fee is hereby granted, provided that the above copyright notice and this
7  * permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
10  * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
11  * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
13  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
14  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16 
17 #ifndef DISTRHO_MUTEX_HPP_INCLUDED
18 #define DISTRHO_MUTEX_HPP_INCLUDED
19 
20 #include "../DistrhoUtils.hpp"
21 
22 #ifdef DISTRHO_OS_WINDOWS
23 # ifndef NOMINMAX
24 # define NOMINMAX
25 # endif
26 # include <winsock2.h>
27 # include <windows.h>
28 #endif
29 
30 #include <pthread.h>
31 
33 
34 class Signal;
35 
36 // -----------------------------------------------------------------------
37 // Mutex class
38 
39 class Mutex
40 {
41 public:
42  /*
43  * Constructor.
44  */
45  Mutex(const bool inheritPriority = true) noexcept
46  : fMutex()
47  {
48  pthread_mutexattr_t attr;
49  pthread_mutexattr_init(&attr);
50  pthread_mutexattr_setprotocol(&attr, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE);
51  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
52  pthread_mutex_init(&fMutex, &attr);
53  pthread_mutexattr_destroy(&attr);
54  }
55 
56  /*
57  * Destructor.
58  */
59  ~Mutex() noexcept
60  {
61  pthread_mutex_destroy(&fMutex);
62  }
63 
64  /*
65  * Lock the mutex.
66  */
67  bool lock() const noexcept
68  {
69  return (pthread_mutex_lock(&fMutex) == 0);
70  }
71 
72  /*
73  * Try to lock the mutex.
74  * Returns true if successful.
75  */
76  bool tryLock() const noexcept
77  {
78  return (pthread_mutex_trylock(&fMutex) == 0);
79  }
80 
81  /*
82  * Unlock the mutex.
83  */
84  void unlock() const noexcept
85  {
86  pthread_mutex_unlock(&fMutex);
87  }
88 
89 private:
90  mutable pthread_mutex_t fMutex;
91 
92  DISTRHO_DECLARE_NON_COPYABLE(Mutex)
93 };
94 
95 // -----------------------------------------------------------------------
96 // RecursiveMutex class
97 
99 {
100 public:
101  /*
102  * Constructor.
103  */
104  RecursiveMutex() noexcept
105 #ifdef DISTRHO_OS_WINDOWS
106  : fSection()
107 #else
108  : fMutex()
109 #endif
110  {
111 #ifdef DISTRHO_OS_WINDOWS
112  InitializeCriticalSection(&fSection);
113 #else
114  pthread_mutexattr_t attr;
115  pthread_mutexattr_init(&attr);
116  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
117  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
118  pthread_mutex_init(&fMutex, &attr);
119  pthread_mutexattr_destroy(&attr);
120 #endif
121  }
122 
123  /*
124  * Destructor.
125  */
126  ~RecursiveMutex() noexcept
127  {
128 #ifdef DISTRHO_OS_WINDOWS
129  DeleteCriticalSection(&fSection);
130 #else
131  pthread_mutex_destroy(&fMutex);
132 #endif
133  }
134 
135  /*
136  * Lock the mutex.
137  */
138  bool lock() const noexcept
139  {
140 #ifdef DISTRHO_OS_WINDOWS
141  EnterCriticalSection(&fSection);
142  return true;
143 #else
144  return (pthread_mutex_lock(&fMutex) == 0);
145 #endif
146  }
147 
148  /*
149  * Try to lock the mutex.
150  * Returns true if successful.
151  */
152  bool tryLock() const noexcept
153  {
154 #ifdef DISTRHO_OS_WINDOWS
155  return (TryEnterCriticalSection(&fSection) != FALSE);
156 #else
157  return (pthread_mutex_trylock(&fMutex) == 0);
158 #endif
159  }
160 
161  /*
162  * Unlock the mutex.
163  */
164  void unlock() const noexcept
165  {
166 #ifdef DISTRHO_OS_WINDOWS
167  LeaveCriticalSection(&fSection);
168 #else
169  pthread_mutex_unlock(&fMutex);
170 #endif
171  }
172 
173 private:
174 #ifdef DISTRHO_OS_WINDOWS
175  mutable CRITICAL_SECTION fSection;
176 #else
177  mutable pthread_mutex_t fMutex;
178 #endif
179 
180  DISTRHO_DECLARE_NON_COPYABLE(RecursiveMutex)
181 };
182 
183 // -----------------------------------------------------------------------
184 // Signal class
185 
186 class Signal
187 {
188 public:
189  /*
190  * Constructor.
191  */
192  Signal() noexcept
193  : fCondition(),
194  fMutex(),
195  fTriggered(false)
196  {
197  pthread_condattr_t cattr;
198  pthread_condattr_init(&cattr);
199  pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
200  pthread_cond_init(&fCondition, &cattr);
201  pthread_condattr_destroy(&cattr);
202 
203  pthread_mutexattr_t mattr;
204  pthread_mutexattr_init(&mattr);
205  pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
206  pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
207  pthread_mutex_init(&fMutex, &mattr);
208  pthread_mutexattr_destroy(&mattr);
209  }
210 
211  /*
212  * Destructor.
213  */
214  ~Signal() noexcept
215  {
216  pthread_cond_destroy(&fCondition);
217  pthread_mutex_destroy(&fMutex);
218  }
219 
220  /*
221  * Wait for a signal.
222  */
223  void wait() noexcept
224  {
225  pthread_mutex_lock(&fMutex);
226 
227  while (! fTriggered)
228  {
229  try {
230  pthread_cond_wait(&fCondition, &fMutex);
231  } DISTRHO_SAFE_EXCEPTION("pthread_cond_wait");
232  }
233 
234  fTriggered = false;
235 
236  pthread_mutex_unlock(&fMutex);
237  }
238 
239  /*
240  * Wake up all waiting threads.
241  */
242  void signal() noexcept
243  {
244  pthread_mutex_lock(&fMutex);
245 
246  if (! fTriggered)
247  {
248  fTriggered = true;
249  pthread_cond_broadcast(&fCondition);
250  }
251 
252  pthread_mutex_unlock(&fMutex);
253  }
254 
255 private:
256  pthread_cond_t fCondition;
257  pthread_mutex_t fMutex;
258  volatile bool fTriggered;
259 
260  DISTRHO_PREVENT_HEAP_ALLOCATION
261  DISTRHO_DECLARE_NON_COPYABLE(Signal)
262 };
263 
264 // -----------------------------------------------------------------------
265 // Helper class to lock&unlock a mutex during a function scope.
266 
267 template <class Mutex>
269 {
270 public:
271  ScopeLocker(const Mutex& mutex) noexcept
272  : fMutex(mutex)
273  {
274  fMutex.lock();
275  }
276 
277  ~ScopeLocker() noexcept
278  {
279  fMutex.unlock();
280  }
281 
282 private:
283  const Mutex& fMutex;
284 
285  DISTRHO_PREVENT_HEAP_ALLOCATION
286  DISTRHO_DECLARE_NON_COPYABLE(ScopeLocker)
287 };
288 
289 // -----------------------------------------------------------------------
290 // Helper class to try-lock&unlock a mutex during a function scope.
291 
292 template <class Mutex>
294 {
295 public:
296  ScopeTryLocker(const Mutex& mutex) noexcept
297  : fMutex(mutex),
298  fLocked(mutex.tryLock()) {}
299 
300  ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept
301  : fMutex(mutex),
302  fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {}
303 
304  ~ScopeTryLocker() noexcept
305  {
306  if (fLocked)
307  fMutex.unlock();
308  }
309 
310  bool wasLocked() const noexcept
311  {
312  return fLocked;
313  }
314 
315  bool wasNotLocked() const noexcept
316  {
317  return !fLocked;
318  }
319 
320 private:
321  const Mutex& fMutex;
322  const bool fLocked;
323 
324  DISTRHO_PREVENT_HEAP_ALLOCATION
325  DISTRHO_DECLARE_NON_COPYABLE(ScopeTryLocker)
326 };
327 
328 // -----------------------------------------------------------------------
329 // Helper class to unlock&lock a mutex during a function scope.
330 
331 template <class Mutex>
333 {
334 public:
335  ScopeUnlocker(const Mutex& mutex) noexcept
336  : fMutex(mutex)
337  {
338  fMutex.unlock();
339  }
340 
341  ~ScopeUnlocker() noexcept
342  {
343  fMutex.lock();
344  }
345 
346 private:
347  const Mutex& fMutex;
348 
349  DISTRHO_PREVENT_HEAP_ALLOCATION
350  DISTRHO_DECLARE_NON_COPYABLE(ScopeUnlocker)
351 };
352 
353 // -----------------------------------------------------------------------
354 // Define types
355 
358 
361 
364 
365 // -----------------------------------------------------------------------
366 
368 
369 #endif // DISTRHO_MUTEX_HPP_INCLUDED
Definition: Mutex.hpp:40
Definition: Mutex.hpp:99
Definition: Mutex.hpp:269
Definition: Mutex.hpp:294
Definition: Mutex.hpp:333
Definition: Mutex.hpp:187
#define END_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:834
#define START_NAMESPACE_DISTRHO
Definition: DistrhoInfo.hpp:828