1 /*************************************************************************** 2 * * 3 * LinuxSampler - modular, streaming capable sampler * 4 * * 5 * Copyright (C) 2003, 2004 by Benno Senoner and Christian Schoenebeck * 6 * Copyright (C) 2005 - 2017 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 __CONDITION_H__ 25 #define __CONDITION_H__ 26 27 #include "Mutex.h" 28 29 #if defined(WIN32) 30 #include <windows.h> 31 #endif 32 33 namespace LinuxSampler { 34 35 #if defined(WIN32) 36 class ConditionInternal; 37 #endif 38 39 /** 40 * Thread safe boolean condition. 41 * 42 * This is not meant to be used for real time operation! 43 */ 44 class Condition : public Mutex { 45 public: 46 /** @brief Constructor 47 * 48 * Creates a new thread safe condition variable. 49 * 50 * Note that the default bahavior of the underlying mutex is 51 * @c NON_RECURSIVE by default, because in general if your design 52 * requires the Condition object's lock state to be recursive instead, 53 * then most probably this may result in dead locks or even undefined 54 * behavior, because the underlying OS API for conditions may not be 55 * compatible with recursive mutexes! 56 * 57 * @param bInitialCondition - optional: starting condition 58 * (default = false) 59 * @param mutexType - optional: fundamental behavior of underlying mutex 60 * (default: @c NON_RECURSIVE) 61 */ 62 Condition(bool bInitialCondition = false, Mutex::type_t mutexType = Mutex::NON_RECURSIVE); 63 64 /** 65 * Destructor 66 */ 67 virtual ~Condition(); 68 69 /** 70 * Blocks the calling thread if current condition equals 71 * \a bCondition, in this case the calling thread will be blocked 72 * until condition turns. Upon successful return the Condition 73 * object is locked, so the calling thread can safely run it's 74 * critical section and has to explicitly call Unlock() right after 75 * it left it's critcal section. 76 * 77 * @e Note: If you don't provide a timeout value or if you provide a 78 * timeout value of exactly 0s and 0ns, then this call will block 79 * without any timeout, or in other words: @e infinity! 80 * 81 * @param bCondition - block in case of this condition 82 * @param TimeoutSeconds - optional: max. wait time in seconds 83 * (default: 0s) 84 * @param TimeoutNanoSeconds - optional: max wait time in nano 85 * seconds (default: 0ns) 86 * @returns 0 on success, a value less than 0 if timeout exceeded 87 */ 88 int WaitIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L); 89 90 /** 91 * Same as WaitIf(), except that WaitAndUnlockIf() will unlock the 92 * Condition object, so only use this call if you don't need to 93 * enter a thread critical section, otherwise use WaitIf() instead! 94 * 95 * @e Note: If you don't provide a timeout value or if you provide a 96 * timeout value of exactly 0s and 0ns, then this call will block 97 * without any timeout, or in other words: @e infinity! 98 * 99 * @param bCondition - block in case of this condition 100 * @param TimeoutSeconds - optional: max. wait time in seconds 101 * (default: 0s) 102 * @param TimeoutNanoSeconds - optional: max wait time in nano 103 * seconds (default: 0ns) 104 * @returns 0 on success, a value less than 0 if timeout exceeded 105 * @see WaitIf() 106 */ 107 int WaitAndUnlockIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L); 108 109 /** 110 * You should use this method instead of WaitIf() in case the calling 111 * thread already owns the Condition object's underlying mutex lock by 112 * previously calling Lock() before. Essentially the only difference to 113 * WaitIf() is that PreLockedWaitIf() does not call Lock() by itself. 114 */ 115 int PreLockedWaitIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L); 116 117 /** 118 * You should use this method instead of WaitAndUnlockIf() in case the 119 * calling thread already owns the Condition object's underlying mutex 120 * lock by previously calling Lock() before. Essentially the only 121 * difference to WaitAndUnlockIf() is that PreLockedWaitAndUnlockIf() 122 * does not call Lock() by itself. 123 */ 124 int PreLockedWaitAndUnlockIf(bool bCondition, long TimeoutSeconds = 0L, long TimeoutNanoSeconds = 0L); 125 126 /** 127 * Set Condition object to \a bCondition. Upon change of the 128 * condition, other threads waiting for \a bCondition will be 129 * awakened. (Note the condition will not be locked for the calling 130 * thread after this method returns!) 131 * 132 * @param bCondition - new condition 133 */ 134 void Set(bool bCondition); 135 136 /** 137 * You should use this method instead of Set() in case the calling 138 * thread already owns the Condition object's underlying mutex lock by 139 * previously calling Lock() before. Essentially the only difference to 140 * Set() is that PreLockedSet() does not call Lock() by itself. 141 */ 142 void PreLockedSet(bool bCondition); 143 144 /** 145 * Returns the current boolean state of this condition object. This 146 * method never blocks, it returns immediately and doesn't use any 147 * system calls. 148 * 149 * @e Caution: this method is not thread safe! If you need to use 150 * the condition state in a thread critical context you must call 151 * @c Lock() and @c Unlock() respectively by yourself! 152 */ 153 bool GetUnsafe(); 154 155 #ifdef WIN32 156 /** 157 * Resets the condition. This is only needed on Windows, after 158 * a thread waiting for a condition has been stopped with 159 * StopThread. 160 */ 161 void Reset(); 162 #endif 163 164 protected: 165 int WaitIfInternal(bool bLock, bool bCondition, long TimeoutSeconds, long TimeoutNanoSeconds); 166 void SetInternal(bool bLock, bool bCondition); 167 168 #if defined(WIN32) 169 friend class ConditionInternal; 170 struct win32thread_cond_t { 171 int waiters_count_; ///< Number of waiting threads. 172 CRITICAL_SECTION waiters_count_lock_; ///< Serialize access to <waiters_count_>. 173 HANDLE sema_; ///< Semaphore used to queue up threads waiting for the condition to become signaled. 174 HANDLE waiters_done_; ///< An auto-reset event used by the broadcast/signal thread to wait for all the waiting thread(s) to wake up and be released from the semaphore. 175 size_t was_broadcast_; ///< Keeps track of whether we were broadcasting or signaling. This allows us to optimize the code if we're just signaling. 176 } __win32_true_condition, __win32_false_condition; 177 #else 178 pthread_cond_t __posix_true_condition; 179 pthread_cond_t __posix_false_condition; 180 #endif 181 bool bCondition; 182 }; 183 184 } // namespace LinuxSampler 185 186 #endif // __CONDITION_H__ 187