DISTRHO Plugin Framework
Mutex.hpp
1 /*
2  * DISTRHO Plugin Framework (DPF)
3  * Copyright (C) 2012-2016 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(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  void lock() const noexcept
65  {
66  pthread_mutex_lock(&fMutex);
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_PREVENT_HEAP_ALLOCATION
90  DISTRHO_DECLARE_NON_COPY_CLASS(Mutex)
91 };
92 
93 // -----------------------------------------------------------------------
94 // RecursiveMutex class
95 
97 {
98 public:
99  /*
100  * Constructor.
101  */
102  RecursiveMutex() noexcept
103 #ifdef DISTRHO_OS_WINDOWS
104  : fSection()
105 #else
106  : fMutex()
107 #endif
108  {
109 #ifdef DISTRHO_OS_WINDOWS
110  InitializeCriticalSection(&fSection);
111 #else
112  pthread_mutexattr_t attr;
113  pthread_mutexattr_init(&attr);
114  pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
115  pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
116  pthread_mutex_init(&fMutex, &attr);
117  pthread_mutexattr_destroy(&attr);
118 #endif
119  }
120 
121  /*
122  * Destructor.
123  */
124  ~RecursiveMutex() noexcept
125  {
126 #ifdef DISTRHO_OS_WINDOWS
127  DeleteCriticalSection(&fSection);
128 #else
129  pthread_mutex_destroy(&fMutex);
130 #endif
131  }
132 
133  /*
134  * Lock the mutex.
135  */
136  void lock() const noexcept
137  {
138 #ifdef DISTRHO_OS_WINDOWS
139  EnterCriticalSection(&fSection);
140 #else
141  pthread_mutex_lock(&fMutex);
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_PREVENT_HEAP_ALLOCATION
178  DISTRHO_DECLARE_NON_COPY_CLASS(RecursiveMutex)
179 };
180 
181 // -----------------------------------------------------------------------
182 // Signal class
183 
184 class Signal
185 {
186 public:
187  /*
188  * Constructor.
189  */
190  Signal() noexcept
191  : fCondition(),
192  fMutex(),
193  fTriggered(false)
194  {
195  pthread_condattr_t cattr;
196  pthread_condattr_init(&cattr);
197  pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
198  pthread_cond_init(&fCondition, &cattr);
199  pthread_condattr_destroy(&cattr);
200 
201  pthread_mutexattr_t mattr;
202  pthread_mutexattr_init(&mattr);
203  pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
204  pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
205  pthread_mutex_init(&fMutex, &mattr);
206  pthread_mutexattr_destroy(&mattr);
207  }
208 
209  /*
210  * Destructor.
211  */
212  ~Signal() noexcept
213  {
214  pthread_cond_destroy(&fCondition);
215  pthread_mutex_destroy(&fMutex);
216  }
217 
218  /*
219  * Wait for a signal.
220  */
221  void wait() noexcept
222  {
223  pthread_mutex_lock(&fMutex);
224 
225  while (! fTriggered)
226  {
227  try {
228  pthread_cond_wait(&fCondition, &fMutex);
229  } DISTRHO_SAFE_EXCEPTION("pthread_cond_wait");
230  }
231 
232  fTriggered = false;
233 
234  pthread_mutex_unlock(&fMutex);
235  }
236 
237  /*
238  * Wake up all waiting threads.
239  */
240  void signal() noexcept
241  {
242  pthread_mutex_lock(&fMutex);
243 
244  if (! fTriggered)
245  {
246  fTriggered = true;
247  pthread_cond_broadcast(&fCondition);
248  }
249 
250  pthread_mutex_unlock(&fMutex);
251  }
252 
253 private:
254  pthread_cond_t fCondition;
255  pthread_mutex_t fMutex;
256  volatile bool fTriggered;
257 
258  DISTRHO_PREVENT_HEAP_ALLOCATION
259  DISTRHO_DECLARE_NON_COPY_CLASS(Signal)
260 };
261 
262 // -----------------------------------------------------------------------
263 // Helper class to lock&unlock a mutex during a function scope.
264 
265 template <class Mutex>
267 {
268 public:
269  ScopeLocker(const Mutex& mutex) noexcept
270  : fMutex(mutex)
271  {
272  fMutex.lock();
273  }
274 
275  ~ScopeLocker() noexcept
276  {
277  fMutex.unlock();
278  }
279 
280 private:
281  const Mutex& fMutex;
282 
283  DISTRHO_PREVENT_HEAP_ALLOCATION
284  DISTRHO_DECLARE_NON_COPY_CLASS(ScopeLocker)
285 };
286 
287 // -----------------------------------------------------------------------
288 // Helper class to try-lock&unlock a mutex during a function scope.
289 
290 template <class Mutex>
292 {
293 public:
294  ScopeTryLocker(const Mutex& mutex) noexcept
295  : fMutex(mutex),
296  fLocked(mutex.tryLock()) {}
297 
298  ~ScopeTryLocker() noexcept
299  {
300  if (fLocked)
301  fMutex.unlock();
302  }
303 
304  bool wasLocked() const noexcept
305  {
306  return fLocked;
307  }
308 
309  bool wasNotLocked() const noexcept
310  {
311  return !fLocked;
312  }
313 
314 private:
315  const Mutex& fMutex;
316  const bool fLocked;
317 
318  DISTRHO_PREVENT_HEAP_ALLOCATION
319  DISTRHO_DECLARE_NON_COPY_CLASS(ScopeTryLocker)
320 };
321 
322 // -----------------------------------------------------------------------
323 // Helper class to unlock&lock a mutex during a function scope.
324 
325 template <class Mutex>
327 {
328 public:
329  ScopeUnlocker(const Mutex& mutex) noexcept
330  : fMutex(mutex)
331  {
332  fMutex.unlock();
333  }
334 
335  ~ScopeUnlocker() noexcept
336  {
337  fMutex.lock();
338  }
339 
340 private:
341  const Mutex& fMutex;
342 
343  DISTRHO_PREVENT_HEAP_ALLOCATION
344  DISTRHO_DECLARE_NON_COPY_CLASS(ScopeUnlocker)
345 };
346 
347 // -----------------------------------------------------------------------
348 // Define types
349 
352 
355 
358 
359 // -----------------------------------------------------------------------
360 
361 END_NAMESPACE_DISTRHO
362 
363 #endif // DISTRHO_MUTEX_HPP_INCLUDED
Signal
Definition: Mutex.hpp:184
ScopeLocker
Definition: Mutex.hpp:266
RecursiveMutex
Definition: Mutex.hpp:96
Mutex
Definition: Mutex.hpp:36
ScopeUnlocker
Definition: Mutex.hpp:326
ScopeTryLocker
Definition: Mutex.hpp:291