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 __CMutex_H__
21 #define __CMutex_H__
22 
23 #include "../../config/common.h"
24 
25 //??? I should do an experiement to see how much smaller, if any, an application got by un-inlining this class and giving it a cpp file
26 
27 /*
28  * This is a multi-platform mutex wrapper. (pthreads and win32)
29  *
30  * There are no flags keeping up with the state of the mutex simply because used with a
31  * CConditionVariable the state information gets off since it unlocks the internal mutex
32  * without having a chance to change the flags
33  * One way around this (if I need the flags back) would be to have CConditionVariable
34  * have it's own internal mutex and it doesn't use this class
35  *
36  * The class's public interface looks like:
37 
38 	class CMutex
39 	{
40 	public:
41 		CMutex(bool recursive=true,const char *name=NULL) ;
42 		virtual ~CMutex() throw();
43 
44 		void lock();
45 
46 		// returns true if the lock was successful else false
47 		bool trylock(int timeout_ms=0) ;
48 
49 		void unlock();
50 	};
51 
52  *
53  *
54  * Additionally, there are 2 utility classes for dealing with CMutex objects
55  * Their public interfaces look like:
56 
57 	class CMutexLocker
58 	{
59 	public:
60 		// construct a locker object with no mutex assigned
FXIMPLEMENT(FXConstantParamValue,FXVerticalFrame,FXConstantParamValueMap,ARRAYNUMBER (FXConstantParamValueMap))61 		CMutexLocker();
62 
63 		// construct a locker object with the given mutex.. the mutex is locked/try-locked on construction
64 		CMutexLocker(CMutex &_m,int timeout_ms=-1);
65 
66 		// the destructor unlocks the mutex iff it was locked
67 		virtual ~CMutexLocker() throw();
68 
69 		// returned whether the mutex lock was obtained by this object (sometimes false if a try-lock occurred)
70 		bool didLock() const;
71 
72 		// unlocks the currently assigned mutex if it was locked, assigns a new mutex to this locked and locks/try-locks the new mutex
73 		// the locked status is returned
74 		bool reassign(CMutex &_m,int timeout_ms=-1);
75 
76 		// unlocks the currently assigned mutex if it was locked and leaves the locker object with no assigned mutex
77 		void unassign();
78 	};
79 
80 	// It SIMPLY unlock()s on ctor and lock()s on dtor
81 	class CMutexUnlocker
82 	{
83 	public:
84 		CMutexUnlocker(CMutex &_m);
85 		~CMutexUnlocker() throw();
86 	};
87 
88  */
89 
90 class AMutex
91 {
92 public:
93 	AMutex(){}
94 	virtual ~AMutex() throw() {}
95 
96 	void lock() { trylock(-1); }
97 
98 	// returns true if the lock was successful else false
99 	virtual bool trylock(int timeout_ms=0/*in milliseconds*/) {
100 		// had troubles with pure virtual here
101 		(void)timeout_ms; // for unreferenced formal parameter warning
102 		return false;
103 	}
104 
105 	virtual void unlock() {} // had troubles with pure virtual here
106 };
107 
108 
109 #ifdef _WIN32
110 	// *** WIN32 implementation ***
111 
112 	#include <stddef.h>
113 
114 	class CMutex : public AMutex
115 	{
116 	public:
117 
118 		/* if recursive is true, then the same thread can safely lock the mutex even if it already has a lock on it */
119 		CMutex(bool recursive=true,const char *name=NULL) ;
120 		virtual ~CMutex() throw() ;
121 
122 		void lock() { trylock(-1); }
123 
124 		// returns true if the lock was successful else false
125 		bool trylock(int timeout_ms=0/*in milliseconds*/);
126 
127 		void unlock();
128 
129 	private:
~FXConstantParamValue()130 		friend class CConditionVariable;
131 		void *mutex; // ??? would make this HANDLE, but really don't think I need to include a 30k line header file for it
132 
133 	};
134 
getDefaultWidth()135 	// this class only implements infinite trylock, and so can be used as an optimization when full blocking is all that is needed
136 	class CFastMutex : public AMutex
137 	{
138 	public:
139 		CFastMutex();
140 		virtual ~CFastMutex() throw() ;
141 
142 		bool trylock(int timeout_ms=0/*in milliseconds*/); // note: timeout_ms value is ignored
143 		void unlock();
144 
145 	private:
146 		void*	m_CriticalSection; // actually LPCRITICAL_SECTION, but we're not including windows.h
147 		int		m_ownerthread;
148 		int		m_lockcount;
149 	};
150 
setUnits(const FXString _units)151 #else
152 	// *** posix implementation ***
153 
154 	//#include <stddef.h>
155 
156 	class CMutex : public AMutex
157 	{
158 	public:
159 
160 		/* if recursive is true, then the same thread can safely lock the mutex even if it already has a lock on it */
161 		CMutex(bool recursive=true,const char *name=0);
162 		virtual ~CMutex() throw() ;
163 
164 		void lock() { trylock(-1); }
165 
166 		// returns true if the lock was successful else false
167 		bool trylock(int timeout_ms=0/*in milliseconds*/);
168 
169 		void unlock();
170 
171 	private:
172 		friend class CConditionVariable;
173 		void *mutex;
174 	};
175 
176 
177 	// dummy implementation... unless someone knows a quicker implementation?
178 	#define CFastMutex CMutex
179 
180 #endif
181 
onValueTextBoxChange(FXObject * sender,FXSelector sel,void * ptr)182 /*
183  * This class simply locks the given mutex on construct and unlocks on destruction
184  * it is useful to use where a lock should be obtained, then released on return or
185  * exception... when an object of this class goes out of scope, the lock will be
186  * released
187  *
188  * The construct can optionally take a second parameter that says not to wait when
189  * locking, but to do a trylock.  If this method is used, then it is necessary to
190  * call didLock() to see if a lock was obtained.
191  */
192 class CMutexLocker
193 {
194 public:
195 	// construct a locker object with no mutex assigned
196 	CMutexLocker();
197 
198 	// construct a locker object with the given mutex.. it blocks until the mutex is locked
199 	CMutexLocker(AMutex &_m);
200 
201 	// construct a locker object with the given mutex.. the mutex lock is attemped for the given timeout, -1 implies infinite
202 	CMutexLocker(AMutex &_m,int timeout_ms);
203 
204 	// the destructor unlocks the mutex iff it was locked
205 	virtual ~CMutexLocker() throw() ;
206 
207 	// returned whether the mutex lock was obtained by this object (sometimes false if a try-lock occurred)
208 	bool didLock() const { return m!=0; }
209 
210 	// unlocks the currently assigned mutex if it was locked, assigns a new mutex to this locked and locks/try-locks the new mutex
211 	// the locked status is returned
212 	bool reassign(AMutex &_m,int timeout_ms=-1);
213 
214 	// unlocks the currently assigned mutex if it was locked and leaves the locker object with no assigned mutex
215 	void unassign();
216 
217 	// returns a pointer to the current mutex, or NULL if there isn't one
218 	AMutex *getMutex() const { return m; }
219 
220 private:
221 	AMutex *m;
222 };
223 
224 // This is a seemingly strange needed class, but it is sometimes needed to respect mutex locking order when dealing with multiple mutexes
prvSetValue(const double value)225 //
226 // It SIMPLY unlock()s on ctor and lock()s on dtor
227 class CMutexUnlocker
228 {
229 public:
230 	CMutexUnlocker(AMutex &_m) : locked(false), m(_m) { m.unlock(); }
231 	~CMutexUnlocker() throw ();
232 
233 	void lock() { if(!locked) { m.lock(); locked=true; } }
234 private:
235 	CMutexUnlocker& operator=( const CMutexUnlocker & ) { return *this; } // explicitly not supported
236 
237 	bool locked;
238 	AMutex &m;
239 };
setScalar(const int scalar)240 
241 
242 #endif
243 
244