1 /*
2  * Copyright (C) 2002 - David W. Durham
3  *
4  * This file is part of ReZound, an audio editing application.
5  *
6  * ReZound is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * ReZound is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  */
20 #ifndef __CConditionVariable_H__
21 #define __CConditionVariable_H__
22 
23 #include "../../config/common.h"
24 
25 /*
26  * This is a multi-platform condition variable wrapper.
27  *
28  * Its public interface looks like:
29 
30 	class CConditionVariable
31 	{
32 	public:
33 		CConditionVariable();
34 		virtual ~CConditionVariable() throw();
35 
36 		// returns false if it timed out, else true
37 		// NOTE: if timeout is >= 0, and wait() returns false, there's no guarantee that the condition-predicate is false, so it may need to be checked
38 		bool wait(CMutex &mutex,int timeout=-1);
39 
40 		void signal();		// slightly more efficient if there is only going to be a single waiter
41 		void broadcast();	// use if there are multiple waiters
42 	};
43 
44 
45 	---------------------------------------------------------------------------
46 
47 	Example use:
48 
49 	CMutex m;
50 	CConditionVariable c;
51 
52 	// --- code that waits for condition to be true -----
53 
54 	m.lock();
55 	while(desired condition IS NOT true)
56 		c.wait(m); // the thread will wake up every time the condition variable is signaled..
57 
58 	// now condition IS true
59 		...
60 	m.unlock();
61 
62 	...
63 
64 
65 	// --- code that causes condition to be true ------
66 
67 	m.lock();
68 	... something that causes condition to be true ...
69 	c.broadcast(); (or c.signal())
70 	m.unlock();
71 
72 	...
73 
74 
75 
76 	Now, if it can be known that only one thread will ever
77 	be waiting on the condition, c.signal() can be used
78 	to be more efficient.  In doubt, use c.broadcast()
79 	broadcast() wakes up all the threads waiting
80 
81 	Also, a waiting thread is not supposed to wake up until
82 	a signaler *unlocks* the mutex.  Hence signal() can
83 	be called before or after the condition is actually true
84 	as long as it's done while the mutex is locked.
85 */
86 
87 #include "CMutex.h"
88 
89 #if defined(_WIN32)
90 	// *** WIN32 implementation ***
91 
92 	// doing this to avoid including windows.h
93 	//   must use this below because CRITICAL_SECTION is a typedef and it causes internal compiler errors
94 	struct _RTL_CRITICAL_SECTION;
95 
96 	class CConditionVariable
97 	{
98 	public:
99 
100 		CConditionVariable();
101 		~CConditionVariable() throw();
102 
103 		// returns false if it timed out, else true
104 		// NOTE: if timeout is >= 0, and wait() returns false, there's no guarantee that the condition-predicate is false, so it may need to be checked
105 		bool wait(CMutex &mutex,int timeout_ms=-1);
106 
107 		void signal();
108 
109 		void broadcast();
110 
111 	private:
112 
113 		enum {
114 			SIGNAL = 0,
115 			BROADCAST = 1,
116 			MAX_EVENTS = 2
117 		};
118 
119 		// Count of the number of waiters.
120 		unsigned waiters_count_;
121 
122 		// Serialize access to <waiters_count_>.
123 		_RTL_CRITICAL_SECTION *waiters_count_lock_;
124 
125 		// Signal and broadcast event HANDLEs.
126 		void* events_[MAX_EVENTS]; // ??? would make this HANDLE, but really don't think I need to include a huge windows.h header file for a void * typedef
127 
128 	};
129 
130 #else
131 	// *** posix implementation ***
132 
133 	#include <pthread.h>
134 
135 	class CConditionVariable
136 	{
137 	public:
138 
139 		CConditionVariable();
140 		virtual ~CConditionVariable() throw();
141 
142 		// returns false if it timed out, else true
143 		// NOTE: if timeout is >= 0, and wait() returns false, there's no guarantee that the condition-predicate is false, so it may need to be checked
144 		bool wait(CMutex &mutex,int timeout=-1);
145 
146 		void signal();
147 
148 		void broadcast();
149 
150 	private:
151 		pthread_cond_t cond;
152 
153 	};
154 
155 #endif
156 
157 #endif
158