1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * 6 * Copyright (C) 2005 - 2020 Christian Schoenebeck * 7 * * 8 * This program is free software; you can redistribute it and/or modify * 9 * it under the terms of the GNU General Public License as published by * 10 * the Free Software Foundation; either version 2 of the License, or * 11 * (at your option) any later version. * 12 * * 13 * This program is distributed in the hope that it will be useful, * 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 16 * GNU General Public License for more details. * 17 * * 18 * You should have received a copy of the GNU General Public License * 19 * along with this program; if not, write to the Free Software * 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, * 21 * MA 02111-1307 USA * 22 ***************************************************************************/ 23 24 #ifndef __MUTEX_H__ 25 #define __MUTEX_H__ 26 27 // enable this for detecting mutex misusage and for debugging dead locks 28 // (these features then still need to be enabled by Mutex::setDebugEnabled()) 29 //#define DEBUG_MUTEX 1 30 31 #if defined(WIN32) 32 #include <windows.h> 33 #else 34 #include <pthread.h> 35 #endif 36 37 namespace LinuxSampler { 38 39 /** @brief Mutual exclusive objects 40 * 41 * This class provides the classical thread / process synchronisation 42 * technique called Mutex. It is used to protect critical sections, that is 43 * resources (typically data structures) from being used at the same time by 44 * different threads or processes which otherwise might turn into undefined 45 * and of course undesired behavior. 46 * 47 * Note: as this technique might block the calling thread and also implies 48 * a system call, this should not be used directly in realtime sensitive 49 * threads! 50 */ 51 class Mutex { 52 public: 53 enum type_t { 54 RECURSIVE, 55 NON_RECURSIVE 56 }; 57 58 /** @brief Constructor 59 * 60 * Creates a new Mutex object. The optional @a type argument defines 61 * the fundamental behavior of the Mutex object: 62 * 63 * - If @c RECURSIVE is passed (which is the default type) then the 64 * mutex will manage an additional lock count such that it allows the 65 * same thread to call Lock() multiple times; each time that thread 66 * calls Lock() the lock count will be increased by one, each time it 67 * calls Unlock() it will be decreased by one, and other threads will 68 * only be unblocked once the lock count fell to zero again. 69 * 70 * - If @c NON_RECURSIVE is passed then it is considered to be an error 71 * if the same thread calls Lock() while already owning the lock, and 72 * likewise it is considered to be an error if Unlock() is called if 73 * the calling thread hasn't locked the mutex. 74 * 75 * You should invest the required time to review your design in order to 76 * decide which mutex behavior fits to your design. Even though it might 77 * be tempting to stick with the lazy approach by using the @c RECURSIVE 78 * type, using the @c NON_RECURSIVE type does make sense if your design 79 * does not require a recursive mutex, because modern developer tools 80 * assist you spotting potential threading bugs in your code while using 81 * the @c NON_RECURSIVE type which can avoid developers' biggest fear of 82 * undefined behavior, plus also keep in mind that certain OS APIs are 83 * not compatible with recursive mutexes at all! 84 * 85 * @param type - optional: the fundamental behavior type for this mutex 86 * (default: @c RECURSIVE) 87 */ 88 Mutex(type_t type = RECURSIVE); 89 90 /** 91 * Destructor 92 */ 93 virtual ~Mutex(); 94 95 /** @brief Lock this Mutex. 96 * 97 * If this Mutex object is currently be locked by another thread, 98 * then the calling thread will be blocked until the other thread 99 * unlocks this Mutex object. The calling thread though can safely 100 * call this method several times without danger to be blocked 101 * himself. 102 * 103 * The calling thread should call Unlock() as soon as the critical 104 * section was left. 105 */ 106 void Lock(); 107 108 /** @brief Try to lock this Mutex. 109 * 110 * Same as Lock() except that this method won't block the calling 111 * thread in case this Mutex object is currently locked by another 112 * thread. So this call will always immediately return and the 113 * return value has to be checked if the locking request was 114 * successful or not. 115 * 116 * @returns true if the Mutex object could be locked, false if the 117 * Mutex is currently locked by another thread 118 */ 119 bool Trylock(); 120 121 /** @brief Unlock this Mutex. 122 * 123 * If other threads are currently blocked and waiting due to a 124 * Lock() call, one of them will be awaken. 125 */ 126 void Unlock(); 127 128 #if DEBUG_MUTEX 129 /** @brief Enable bug detection and debugging features. 130 * 131 * By passing @c true to this method, bug detection and debugging features 132 * will be enabled for this Mutex object. For instance this will trigger an 133 * assertion fault if a thread attempts to Unlock() a thread it does not own 134 * a lock on, or when locking more than once while not using mutex type 135 * @c RECURSIVE and much more. Additionally this will also record the name 136 * of the thread currently holding a lock, and the backtrace of that 137 * thread's lock. The latter information can then be used to debug 138 * deadlocks. 139 * 140 * By default this is turned off and must be enabled for individual Mutex 141 * objects, because otherwise it would cause a large number of false 142 * positives (i.e. in certain edge cases like thread constructors / 143 * destructors for instance). 144 * 145 * @param b - whether to enable bug detection / debugging features 146 */ setDebugEnabled(bool b)147 void setDebugEnabled(bool b) { 148 debugSelf = b; 149 } 150 #endif 151 152 protected: 153 #if defined(WIN32) 154 HANDLE hMutex; 155 #else 156 pthread_mutex_t __posix_mutex; 157 pthread_mutexattr_t __posix_mutexattr; 158 #endif 159 type_t type; 160 #if DEBUG_MUTEX 161 std::string owner; ///< Name of the thread owning the current lock. 162 long long int count; ///< How many times the owner currently acquired the lock recursively. 163 std::string backtrace; ///< Call stack trace of (last) lock. 164 bool debugSelf; ///< Whether bug detection and debugging features are enabled. 165 #endif 166 }; 167 168 // Lock guard for exception safe locking 169 class LockGuard { 170 public: LockGuard(Mutex & m)171 LockGuard(Mutex& m) : pm(&m) { 172 m.Lock(); 173 } 174 175 /** 176 * Empty LockGuard. This constructor can be used to implement conditional 177 * mutex protection like: 178 * @code 179 * Mutex m; 180 * LockGuard g; 181 * if (requiresMutexProtection()) g = LockGuard(m); 182 * @endcode 183 */ LockGuard()184 LockGuard() : pm(NULL) { 185 } 186 LockGuard(const LockGuard & g)187 LockGuard(const LockGuard& g) : pm(g.pm) { 188 if (pm) pm->Lock(); 189 } 190 ~LockGuard()191 ~LockGuard() { 192 if (pm) pm->Unlock(); 193 } 194 private: 195 Mutex* pm; 196 }; 197 198 } // namespace LinuxSampler 199 200 #endif // __MUTEX_H__ 201