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