Dusk Audio Framework
Loading...
Searching...
No Matches
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 DAF_MUTEX_HPP_INCLUDED
18#define DAF_MUTEX_HPP_INCLUDED
19
20#include "../DafUtils.hpp"
21
22#ifdef DAF_OS_WINDOWS
23# ifndef NOMINMAX
24# define NOMINMAX
25# endif
26# include <winsock2.h>
27# include <windows.h>
28#endif
29
30// MSVC has no pthread, use the native Win32 synchronization primitives instead.
31// NOTE: SRWLOCK and CONDITION_VARIABLE require Windows Vista or later,
32// which the MSVC toolchain targets by default (_WIN32_WINNT >= 0x0600).
33#ifndef _MSC_VER
34#include <pthread.h>
35#endif
36
38
39class Signal;
40
41// -----------------------------------------------------------------------
42// Mutex class
43
44class Mutex
45{
46public:
47 /*
48 * Constructor.
49 */
50 Mutex(const bool inheritPriority = true) noexcept
51 : fMutex()
52 {
53 #ifdef _MSC_VER
54 // SRWLOCK is non-recursive, matching PTHREAD_MUTEX_NORMAL used below.
55 // It has no priority-inheritance option, so the argument is ignored.
56 (void)inheritPriority;
57 InitializeSRWLock(&fMutex);
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 _MSC_VER
74 // SRWLOCK needs no cleanup
75 #else
76 pthread_mutex_destroy(&fMutex);
77 #endif
78 }
79
80 /*
81 * Lock the mutex.
82 */
83 bool lock() const noexcept
84 {
85 #ifdef _MSC_VER
86 AcquireSRWLockExclusive(&fMutex);
87 return true;
88 #else
89 return (pthread_mutex_lock(&fMutex) == 0);
90 #endif
91 }
92
93 /*
94 * Try to lock the mutex.
95 * Returns true if successful.
96 */
97 bool tryLock() const noexcept
98 {
99 #ifdef _MSC_VER
100 return (TryAcquireSRWLockExclusive(&fMutex) != FALSE);
101 #else
102 return (pthread_mutex_trylock(&fMutex) == 0);
103 #endif
104 }
105
106 /*
107 * Unlock the mutex.
108 */
109 void unlock() const noexcept
110 {
111 #ifdef _MSC_VER
112 ReleaseSRWLockExclusive(&fMutex);
113 #else
114 pthread_mutex_unlock(&fMutex);
115 #endif
116 }
117
118private:
119 #ifdef _MSC_VER
120 mutable SRWLOCK fMutex;
121 #else
122 mutable pthread_mutex_t fMutex;
123 #endif
124
125 DAF_DECLARE_NON_COPYABLE(Mutex)
126};
127
128// -----------------------------------------------------------------------
129// RecursiveMutex class
130
131class RecursiveMutex
132{
133public:
134 /*
135 * Constructor.
136 */
137 RecursiveMutex() noexcept
138 #ifdef DAF_OS_WINDOWS
139 : fSection()
140 #else
141 : fMutex()
142 #endif
143 {
144 #ifdef DAF_OS_WINDOWS
145 InitializeCriticalSection(&fSection);
146 #else
147 pthread_mutexattr_t attr;
148 pthread_mutexattr_init(&attr);
149 pthread_mutexattr_setprotocol(&attr, PTHREAD_PRIO_INHERIT);
150 pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
151 pthread_mutex_init(&fMutex, &attr);
152 pthread_mutexattr_destroy(&attr);
153 #endif
154 }
155
156 /*
157 * Destructor.
158 */
159 ~RecursiveMutex() noexcept
160 {
161 #ifdef DAF_OS_WINDOWS
162 DeleteCriticalSection(&fSection);
163 #else
164 pthread_mutex_destroy(&fMutex);
165 #endif
166 }
167
168 /*
169 * Lock the mutex.
170 */
171 bool lock() const noexcept
172 {
173 #ifdef DAF_OS_WINDOWS
174 EnterCriticalSection(&fSection);
175 return true;
176 #else
177 return (pthread_mutex_lock(&fMutex) == 0);
178 #endif
179 }
180
181 /*
182 * Try to lock the mutex.
183 * Returns true if successful.
184 */
185 bool tryLock() const noexcept
186 {
187 #ifdef DAF_OS_WINDOWS
188 return (TryEnterCriticalSection(&fSection) != FALSE);
189 #else
190 return (pthread_mutex_trylock(&fMutex) == 0);
191 #endif
192 }
193
194 /*
195 * Unlock the mutex.
196 */
197 void unlock() const noexcept
198 {
199 #ifdef DAF_OS_WINDOWS
200 LeaveCriticalSection(&fSection);
201 #else
202 pthread_mutex_unlock(&fMutex);
203 #endif
204 }
205
206private:
207 #ifdef DAF_OS_WINDOWS
208 mutable CRITICAL_SECTION fSection;
209 #else
210 mutable pthread_mutex_t fMutex;
211 #endif
212
213 DAF_DECLARE_NON_COPYABLE(RecursiveMutex)
214};
215
216// -----------------------------------------------------------------------
217// Signal class
218
219class Signal
220{
221public:
222 /*
223 * Constructor.
224 */
225 Signal() noexcept
226 : fCondition(),
227 fMutex(),
228 fTriggered(false)
229 {
230 #ifdef _MSC_VER
231 InitializeConditionVariable(&fCondition);
232 InitializeCriticalSection(&fMutex);
233 #else
234 pthread_condattr_t cattr;
235 pthread_condattr_init(&cattr);
236 pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_PRIVATE);
237 pthread_cond_init(&fCondition, &cattr);
238 pthread_condattr_destroy(&cattr);
239
240 pthread_mutexattr_t mattr;
241 pthread_mutexattr_init(&mattr);
242 pthread_mutexattr_setprotocol(&mattr, PTHREAD_PRIO_INHERIT);
243 pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_NORMAL);
244 pthread_mutex_init(&fMutex, &mattr);
245 pthread_mutexattr_destroy(&mattr);
246 #endif
247 }
248
249 /*
250 * Destructor.
251 */
252 ~Signal() noexcept
253 {
254 #ifdef _MSC_VER
255 // CONDITION_VARIABLE needs no cleanup
256 DeleteCriticalSection(&fMutex);
257 #else
258 pthread_cond_destroy(&fCondition);
259 pthread_mutex_destroy(&fMutex);
260 #endif
261 }
262
263 /*
264 * Wait for a signal.
265 */
266 void wait() noexcept
267 {
268 #ifdef _MSC_VER
269 EnterCriticalSection(&fMutex);
270
271 while (! fTriggered)
272 {
273 // spurious wakeups and failures are handled by the surrounding loop
274 SleepConditionVariableCS(&fCondition, &fMutex, INFINITE);
275 }
276
277 fTriggered = false;
278
279 LeaveCriticalSection(&fMutex);
280 #else
281 pthread_mutex_lock(&fMutex);
282
283 while (! fTriggered)
284 {
285 try {
286 pthread_cond_wait(&fCondition, &fMutex);
287 } DAF_SAFE_EXCEPTION("pthread_cond_wait");
288 }
289
290 fTriggered = false;
291
292 pthread_mutex_unlock(&fMutex);
293 #endif
294 }
295
296 /*
297 * Wake up all waiting threads.
298 */
299 void signal() noexcept
300 {
301 #ifdef _MSC_VER
302 EnterCriticalSection(&fMutex);
303
304 if (! fTriggered)
305 {
306 fTriggered = true;
307 WakeAllConditionVariable(&fCondition);
308 }
309
310 LeaveCriticalSection(&fMutex);
311 #else
312 pthread_mutex_lock(&fMutex);
313
314 if (! fTriggered)
315 {
316 fTriggered = true;
317 pthread_cond_broadcast(&fCondition);
318 }
319
320 pthread_mutex_unlock(&fMutex);
321 #endif
322 }
323
324private:
325 #ifdef _MSC_VER
326 CONDITION_VARIABLE fCondition;
327 CRITICAL_SECTION fMutex;
328 #else
329 pthread_cond_t fCondition;
330 pthread_mutex_t fMutex;
331 #endif
332 volatile bool fTriggered;
333
334 DAF_PREVENT_HEAP_ALLOCATION
335 DAF_DECLARE_NON_COPYABLE(Signal)
336};
337
338// -----------------------------------------------------------------------
339// Helper class to lock&unlock a mutex during a function scope.
340
341template <class Mutex>
342class ScopeLocker
343{
344public:
345 ScopeLocker(const Mutex& mutex) noexcept
346 : fMutex(mutex)
347 {
348 fMutex.lock();
349 }
350
351 ~ScopeLocker() noexcept
352 {
353 fMutex.unlock();
354 }
355
356private:
357 const Mutex& fMutex;
358
359 DAF_PREVENT_HEAP_ALLOCATION
360 DAF_DECLARE_NON_COPYABLE(ScopeLocker)
361};
362
363// -----------------------------------------------------------------------
364// Helper class to try-lock&unlock a mutex during a function scope.
365
366template <class Mutex>
367class ScopeTryLocker
368{
369public:
370 ScopeTryLocker(const Mutex& mutex) noexcept
371 : fMutex(mutex),
372 fLocked(mutex.tryLock()) {}
373
374 ScopeTryLocker(const Mutex& mutex, const bool forceLock) noexcept
375 : fMutex(mutex),
376 fLocked(forceLock ? mutex.lock() : mutex.tryLock()) {}
377
378 ~ScopeTryLocker() noexcept
379 {
380 if (fLocked)
381 fMutex.unlock();
382 }
383
384 bool wasLocked() const noexcept
385 {
386 return fLocked;
387 }
388
389 bool wasNotLocked() const noexcept
390 {
391 return !fLocked;
392 }
393
394private:
395 const Mutex& fMutex;
396 const bool fLocked;
397
398 DAF_PREVENT_HEAP_ALLOCATION
399 DAF_DECLARE_NON_COPYABLE(ScopeTryLocker)
400};
401
402// -----------------------------------------------------------------------
403// Helper class to unlock&lock a mutex during a function scope.
404
405template <class Mutex>
406class ScopeUnlocker
407{
408public:
409 ScopeUnlocker(const Mutex& mutex) noexcept
410 : fMutex(mutex)
411 {
412 fMutex.unlock();
413 }
414
415 ~ScopeUnlocker() noexcept
416 {
417 fMutex.lock();
418 }
419
420private:
421 const Mutex& fMutex;
422
423 DAF_PREVENT_HEAP_ALLOCATION
424 DAF_DECLARE_NON_COPYABLE(ScopeUnlocker)
425};
426
427// -----------------------------------------------------------------------
428// Define types
429
430typedef ScopeLocker<Mutex> MutexLocker;
431typedef ScopeLocker<RecursiveMutex> RecursiveMutexLocker;
432
433typedef ScopeTryLocker<Mutex> MutexTryLocker;
434typedef ScopeTryLocker<RecursiveMutex> RecursiveMutexTryLocker;
435
436typedef ScopeUnlocker<Mutex> MutexUnlocker;
437typedef ScopeUnlocker<RecursiveMutex> RecursiveMutexUnlocker;
438
439// -----------------------------------------------------------------------
440
442
443#endif // DAF_MUTEX_HPP_INCLUDED
Definition Mutex.hpp:45
Definition Mutex.hpp:343
Definition Mutex.hpp:368
Definition Mutex.hpp:407
Definition Mutex.hpp:220
#define END_NAMESPACE_DAF
Definition DafInfo.hpp:996
#define START_NAMESPACE_DAF
Definition DafInfo.hpp:990