DPF

DISTRHO Plugin Framework
Log | Files | Refs | Submodules | README | LICENSE

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