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 # include <winsock2.h>
24 # include <windows.h>
25 #endif
26 
27 #include <pthread.h>
28 
29 START_NAMESPACE_DISTRHO
30 
31 class Signal;
32 
33 // -----------------------------------------------------------------------
34 // Mutex class
35 
36 class Mutex
37 {
38 public:
39  /*
40  * Constructor.
41  */
42  Mutex(const bool inheritPriority = true) noexcept
43  : fMutex()
44  {
45  pthread_mutexattr_t attr;
46  pthread_mutexattr_init(&attr);
47  pthread_mutexattr_setprotocol(&attr, inheritPriority ? PTHREAD_PRIO_INHERIT : PTHREAD_PRIO_NONE);
48  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
49  pthread_mutex_init(&fMutex, &attr);
50  pthread_mutexattr_destroy(&attr);
51  }
52 
53  /*
54  * Destructor.
55  */
56  ~Mutex() noexcept
57  {
58  pthread_mutex_destroy(&fMutex);
59  }
60 
61  /*
62  * Lock the mutex.
63  */
64  bool lock() const noexcept
65  {
66  return (pthread_mutex_lock(&fMutex) == 0);
67  }
68 
69  /*
70  * Try to lock the mutex.
71  * Returns true if successful.
72  */
73  bool tryLock() const noexcept
74  {
75  return (pthread_mutex_trylock(&fMutex) == 0);
76  }
77 
78  /*
79  * Unlock the mutex.
80  */
81  void unlock() const noexcept
82  {
83  pthread_mutex_unlock(&fMutex);
84  }
85 
86 private:
87  mutable pthread_mutex_t fMutex;
88 
89  DISTRHO_DECLARE_NON_COPYABLE(Mutex)
90 };
91 
92 // -----------------------------------------------------------------------
93 // RecursiveMutex class
94 
96 {
97 public:
98  /*
99  * Constructor.
100  */
101  RecursiveMutex() noexcept
102 #ifdef DISTRHO_OS_WINDOWS
103  : fSection()
104 #else
105  : fMutex()
106 #endif
107  {
108 #ifdef DISTRHO_OS_WINDOWS
109  InitializeCriticalSection(&fSection);
110 #else
111  pthread_mutexattr_t attr;
112  pthread_mutexattr_init(&attr);
113  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
114  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
115  pthread_mutex_init(&fMutex, &attr);
116  pthread_mutexattr_destroy(&attr);
117 #endif
118  }
119 
120  /*
121  * Destructor.
122  */
123  ~RecursiveMutex() noexcept
124  {
125 #ifdef DISTRHO_OS_WINDOWS
126  DeleteCriticalSection(&fSection);
127 #else
128  pthread_mutex_destroy(&fMutex);
129 #endif
130  }
131 
132  /*
133  * Lock the mutex.
134  */
135  bool lock() const noexcept
136  {
137 #ifdef DISTRHO_OS_WINDOWS
138  EnterCriticalSection(&fSection);
139  return true;
140 #else
141  return (pthread_mutex_lock(&fMutex) == 0);
142 #endif
143  }
144 
145  /*
146  * Try to lock the mutex.
147  * Returns true if successful.
148  */
149  bool tryLock() const noexcept
150  {
151 #ifdef DISTRHO_OS_WINDOWS
152  return (TryEnterCriticalSection(&fSection) != FALSE);
153 #else
154  return (pthread_mutex_trylock(&fMutex) == 0);
155 #endif
156  }
157 
158  /*
159  * Unlock the mutex.
160  */
161  void unlock() const noexcept
162  {
163 #ifdef DISTRHO_OS_WINDOWS
164  LeaveCriticalSection(&fSection);
165 #else
166  pthread_mutex_unlock(&fMutex);
167 #endif
168  }
169 
170 private:
171 #ifdef DISTRHO_OS_WINDOWS
172  mutable CRITICAL_SECTION fSection;
173 #else
174  mutable pthread_mutex_t fMutex;
175 #endif
176 
177  DISTRHO_DECLARE_NON_COPYABLE(RecursiveMutex)
178 };
179 
180 // -----------------------------------------------------------------------
181 // Signal class
182 
183 class Signal
184 {
185 public:
186  /*
187  * Constructor.
188  */
189  Signal() noexcept
190  : fCondition(),
191  fMutex(),
192  fTriggered(false)
193  {
194  pthread_condattr_t cattr;
195  pthread_condattr_init(&cattr);
196  pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
197  pthread_cond_init(&fCondition, &cattr);
198  pthread_condattr_destroy(&cattr);
199 
200  pthread_mutexattr_t mattr;
201  pthread_mutexattr_init(&mattr);
202  pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
203  pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
204  pthread_mutex_init(&fMutex, &mattr);
205  pthread_mutexattr_destroy(&mattr);
206  }
207 
208  /*
209  * Destructor.
210  */
211  ~Signal() noexcept
212  {
213  pthread_cond_destroy(&fCondition);
214  pthread_mutex_destroy(&fMutex);
215  }
216 
217  /*
218  * Wait for a signal.
219  */
220  void wait() noexcept
221  {
222  pthread_mutex_lock(&fMutex);
223 
224  while (! fTriggered)
225  {
226  try {
227  pthread_cond_wait(&fCondition, &fMutex);
228  } DISTRHO_SAFE_EXCEPTION("pthread_cond_wait");
229  }
230 
231  fTriggered = false;
232 
233  pthread_mutex_unlock(&fMutex);
234  }
235 
236  /*
237  * Wake up all waiting threads.
238  */
239  void signal() noexcept
240  {
241  pthread_mutex_lock(&fMutex);
242 
243  if (! fTriggered)
244  {
245  fTriggered = true;
246  pthread_cond_broadcast(&fCondition);
247  }
248 
249  pthread_mutex_unlock(&fMutex);
250  }
251 
252 private:
253  pthread_cond_t fCondition;
254  pthread_mutex_t fMutex;
255  volatile bool fTriggered;
256 
257  DISTRHO_PREVENT_HEAP_ALLOCATION
258  DISTRHO_DECLARE_NON_COPYABLE(Signal)
259 };
260 
261 // -----------------------------------------------------------------------
262 // Helper class to lock&unlock a mutex during a function scope.
263 
264 template <class Mutex>
266 {
267 public:
268  ScopeLocker(const Mutex& mutex) noexcept
269  : fMutex(mutex)
270  {
271  fMutex.lock();
272  }
273 
274  ~ScopeLocker() noexcept
275  {
276  fMutex.unlock();
277  }
278 
279 private:
280  const Mutex& fMutex;
281 
282  DISTRHO_PREVENT_HEAP_ALLOCATION
283  DISTRHO_DECLARE_NON_COPYABLE(ScopeLocker)
284 };
285 
286 // -----------------------------------------------------------------------
287 // Helper class to try-lock&unlock a mutex during a function scope.
288 
289 template <class Mutex>
291 {
292 public:
293  ScopeTryLocker(const Mutex& mutex) noexcept
294  : fMutex(mutex),
295  fLocked(mutex.tryLock()) {}
296 
297  ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept
298  : fMutex(mutex),
299  fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {}
300 
301  ~ScopeTryLocker() noexcept
302  {
303  if (fLocked)
304  fMutex.unlock();
305  }
306 
307  bool wasLocked() const noexcept
308  {
309  return fLocked;
310  }
311 
312  bool wasNotLocked() const noexcept
313  {
314  return !fLocked;
315  }
316 
317 private:
318  const Mutex& fMutex;
319  const bool fLocked;
320 
321  DISTRHO_PREVENT_HEAP_ALLOCATION
322  DISTRHO_DECLARE_NON_COPYABLE(ScopeTryLocker)
323 };
324 
325 // -----------------------------------------------------------------------
326 // Helper class to unlock&lock a mutex during a function scope.
327 
328 template <class Mutex>
330 {
331 public:
332  ScopeUnlocker(const Mutex& mutex) noexcept
333  : fMutex(mutex)
334  {
335  fMutex.unlock();
336  }
337 
338  ~ScopeUnlocker() noexcept
339  {
340  fMutex.lock();
341  }
342 
343 private:
344  const Mutex& fMutex;
345 
346  DISTRHO_PREVENT_HEAP_ALLOCATION
347  DISTRHO_DECLARE_NON_COPYABLE(ScopeUnlocker)
348 };
349 
350 // -----------------------------------------------------------------------
351 // Define types
352 
355 
358 
361 
362 // -----------------------------------------------------------------------
363 
364 END_NAMESPACE_DISTRHO
365 
366 #endif // DISTRHO_MUTEX_HPP_INCLUDED
Signal
Definition: Mutex.hpp:183
ScopeLocker
Definition: Mutex.hpp:265
RecursiveMutex
Definition: Mutex.hpp:95
Mutex
Definition: Mutex.hpp:36
ScopeUnlocker
Definition: Mutex.hpp:329
ScopeTryLocker
Definition: Mutex.hpp:290