Mutex.hpp (9067B)
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