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