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