comparison DPF-Prymula-audioplugins/dpf/distrho/extra/Mutex.hpp @ 3:84e66ea83026

DPF-Prymula-audioplugins-0.231015-2
author prymula <prymula76@outlook.com>
date Mon, 16 Oct 2023 21:53:34 +0200
parents
children
comparison
equal deleted inserted replaced
2:cf2cb71d31dd 3:84e66ea83026
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
38 START_NAMESPACE_DISTRHO
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
125 class RecursiveMutex
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>
297 class ScopeLocker
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>
322 class ScopeTryLocker
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>
361 class ScopeUnlocker
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
385 typedef ScopeLocker<Mutex> MutexLocker;
386 typedef ScopeLocker<RecursiveMutex> RecursiveMutexLocker;
387
388 typedef ScopeTryLocker<Mutex> MutexTryLocker;
389 typedef ScopeTryLocker<RecursiveMutex> RecursiveMutexTryLocker;
390
391 typedef ScopeUnlocker<Mutex> MutexUnlocker;
392 typedef ScopeUnlocker<RecursiveMutex> RecursiveMutexUnlocker;
393
394 // -----------------------------------------------------------------------
395
396 END_NAMESPACE_DISTRHO
397
398 #endif // DISTRHO_MUTEX_HPP_INCLUDED