alter platform-dependent preprocessor macros to use the same names as the rest of...
[ardour.git] / libs / backends / wavesaudio / wavesapi / threads / WCThreadSafe.h
1 #ifndef __WCThreadSafe_h_
2         #define __WCThreadSafe_h_
3
4 /* Copy to include
5 #include "Threads/WCThreadSafe.h"
6 */
7
8 //
9 // * WCThreadSafe.h (used to be called XPlatformOSServices.hpp)
10 // *
11 // * Consistent C++ interfaces to common Operating System services.
12 // *
13 // *
14 // *
15 // *
16 // * Created 2004-December-13 by Udi Barzilai as XPlatformOSServices.hpp
17 // * Moved to WCThreadSafe.h by Shai 26/10/2005
18 // * 26/10/2005:        ThreadMutex now inhetites from ThreadMutexInited
19 // *                            namespace changed to wvThread
20
21 #include "WavesPublicAPI/wstdint.h"
22 #include <string>
23
24 #include "BasicTypes/WUDefines.h"
25
26 #if defined(__linux__) || defined(__APPLE__)
27         #define XPLATFORMOSSERVICES_UNIX  1
28 #endif
29
30 #if defined(_WIN32)
31         #define XPLATFORMOSSERVICES_WIN32 1
32 #endif
33
34 #if XPLATFORMOSSERVICES_WIN32
35         #define XPLATFORMTHREADS_WINDOWS 1
36 #elif XPLATFORMOSSERVICES_UNIX
37         #define XPLATFORMTHREADS_POSIX   1
38 #endif
39 namespace wvNS {
40 typedef uint32_t WTThreadSafetyType;
41 const WTThreadSafetyType kNoThreadSafetyNeeded = 0;
42 const WTThreadSafetyType kpthreadsmutexThreadSafety = 1;
43
44
45 namespace wvThread
46 {
47     //#include "BasicTypes/WavesAPISetAligment.h"
48     //Packing affects the layout of classes, and commonly, if packing changes across header files, there can be problems. 
49 #ifdef PLATFORM_WINDOWS
50 #pragma pack(push)
51 #pragma pack(8)
52 #endif
53
54 #ifdef __APPLE__
55 #ifdef __GNUC__
56 #pragma pack(push, 8)
57 #endif
58 #endif
59
60         //--------------------------------------------------------
61         typedef  int32_t timediff;    // in microseconds
62         static const timediff ktdOneSecond = 1000*1000;
63         //--------------------------------------------------------
64         class timestamp
65         {
66         protected:
67                 typedef uint32_t tickcount;
68                 tickcount m_nMicroseconds;  // may wrap around
69                 static const tickcount ms_knWraparoundThreshold = ~tickcount(0) ^ (~tickcount(0)>>1);  // half the range
70
71         public:
72         timestamp() : m_nMicroseconds(0) { /* uninitialized */ }
73         timestamp(const timestamp &_ts) : m_nMicroseconds(_ts.m_nMicroseconds) {}
74         timestamp &operator=(const timestamp &_rhs) { m_nMicroseconds = _rhs.m_nMicroseconds; return *this; }
75         explicit timestamp(tickcount _i) : m_nMicroseconds(_i) {}
76         uint32_t ticks() const { return m_nMicroseconds; }
77                 timediff operator-(timestamp _rhs) const { return timediff(m_nMicroseconds-_rhs.m_nMicroseconds); }
78                 timestamp & operator+=(timediff _t) { m_nMicroseconds+=_t; return *this; }
79                 timestamp & operator-=(timediff _t) { m_nMicroseconds-=_t; return *this; }
80                 timestamp operator+(timediff _t) const { return timestamp(m_nMicroseconds+_t); }
81                 timestamp operator-(timediff _t) const { return timestamp(m_nMicroseconds-_t); }
82                 bool operator==(timestamp _rhs) const { return m_nMicroseconds==_rhs.m_nMicroseconds; }
83                 bool operator!=(timestamp _rhs) const { return m_nMicroseconds!=_rhs.m_nMicroseconds; }
84                 bool operator< (timestamp _rhs) const { return m_nMicroseconds-_rhs.m_nMicroseconds >= ms_knWraparoundThreshold; }
85         static timestamp null() { return timestamp(0); }
86         bool is_null() const { return m_nMicroseconds==0; }
87         };
88         //--------------------------------------------------------
89 #ifdef __APPLE__
90         bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface);
91 #endif // MACOS
92         //--------------------------------------------------------
93         timestamp now();
94         //--------------------------------------------------------
95         DllExport void sleep(timediff);
96         DllExport void sleep_milliseconds(unsigned int nMillisecs);
97         //--------------------------------------------------------
98     void yield();
99     //--------------------------------------------------------
100
101
102
103         typedef uintptr_t os_dependent_handle_type;
104
105         //--------------------------------------------------------
106         typedef int    ThreadFunctionReturnType;
107         typedef void * ThreadFunctionArgument;
108         //--------------------------------------------------------
109         typedef ThreadFunctionReturnType (ThreadFunction)(ThreadFunctionArgument);
110         //--------------------------------------------------------
111         class ThreadHandle
112         {
113         public:
114                 class OSDependent;
115         protected:
116                 uintptr_t m_oshandle;                                                                   // hopefully this is good enough for all systems
117         public:
118                 static const ThreadHandle Invalid;
119         protected:
120                 ThreadHandle(uintptr_t n) : m_oshandle(n) {} 
121         public:
122                 ThreadHandle() : m_oshandle(Invalid.m_oshandle) {}
123                 bool is_invalid() const { return !m_oshandle || m_oshandle==Invalid.m_oshandle; }
124         };
125         //--------------------------------------------------------
126         class ThreadPriority
127         {
128         public: enum value { BelowNormal=1, Normal=2, AboveNormal=3, TimeCritical=4 };
129         protected: value m_value;
130         public: ThreadPriority(value v) : m_value(v) {}
131         public: operator value() const { return m_value; }
132         };
133         //--------------------------------------------------------
134         void SetMyThreadPriority(ThreadPriority);
135         //--------------------------------------------------------
136         ThreadHandle StartThread(ThreadFunction, ThreadFunctionArgument, ThreadPriority=ThreadPriority::Normal);
137         bool JoinThread(ThreadHandle, ThreadFunctionReturnType * = 0);
138         bool KillThread(ThreadHandle);  // use only for abnormal termination
139         void Close(ThreadHandle); // should be called once for every handle obtained from StartThread.
140         //--------------------------------------------------------
141
142
143
144     
145         //--------------------------------------------------------
146     class DllExport noncopyableobject
147         {
148         protected:
149                 noncopyableobject() {}
150         private:
151                 noncopyableobject(const noncopyableobject &);
152                 noncopyableobject & operator=(const noncopyableobject &);
153         };
154         //--------------------------------------------------------
155
156
157         //--------------------------------------------------------
158         // Thread Mutex class that needs to be explicitly initialized
159         class DllExport ThreadMutexInited : public noncopyableobject
160         {
161         protected:
162                 class OSDependentMutex;
163                 OSDependentMutex* m_osdmutex;
164
165         public:
166                 ThreadMutexInited();
167                 ~ThreadMutexInited();
168
169                 void init();
170                 void uninit();
171                 inline bool is_init() { return 0 != m_osdmutex; }
172                 void obtain();
173                 bool tryobtain();
174                 void release();
175         
176         private:
177                 ThreadMutexInited(const ThreadMutexInited&);            // cannot be copied
178                 ThreadMutexInited& operator=(const ThreadMutexInited&); // cannot be copied
179
180         public:
181                 class lock : public noncopyableobject
182                 {
183                 protected:
184                         ThreadMutexInited &m_mutex;
185                 public:
186                         inline lock(ThreadMutexInited &mtx) : m_mutex(mtx) { m_mutex.obtain(); }
187                         inline ~lock() { m_mutex.release(); }
188                 };
189                 class trylock : public noncopyableobject
190                 {
191                 protected:
192                         ThreadMutexInited &m_mutex;
193                         bool         m_bObtained;
194                 public:
195                         inline trylock(ThreadMutexInited &mtx) : m_mutex(mtx), m_bObtained(false) { m_bObtained = m_mutex.tryobtain(); }
196                         inline ~trylock() { if (m_bObtained) m_mutex.release(); }
197                         inline operator bool() const { return m_bObtained; }
198                 };
199         };
200         //--------------------------------------------------------
201
202         // Thread Mutex class that is automatically initialized
203         class ThreadMutex : public ThreadMutexInited 
204         {
205         public:
206                 ThreadMutex() {init();}
207         };
208         
209         //--------------------------------------------------------
210         class DllExport ThreadConditionSignal : public noncopyableobject
211         {
212         protected:
213                 class OSDependentObject;
214                 OSDependentObject &m_osdepobj;
215
216         protected:
217                 void obtain_mutex();
218                 bool tryobtain_mutex();
219                 void release_mutex();
220
221         public:
222                 class lock : public noncopyableobject
223                 {
224                 protected:
225                         ThreadConditionSignal &m_tcs;
226                 public:
227                         lock(ThreadConditionSignal &tcs) : m_tcs(tcs) { m_tcs.obtain_mutex(); }
228                         ~lock() { m_tcs.release_mutex(); }
229                 };
230                 class trylock : public noncopyableobject
231                 {
232                 protected:
233                         ThreadConditionSignal &m_tcs;
234                         bool                   m_bObtained;
235                 public:
236                         trylock(ThreadConditionSignal &tcs) : m_tcs(tcs), m_bObtained(false) { m_bObtained = m_tcs.tryobtain_mutex(); }
237                         ~trylock() { if (m_bObtained) m_tcs.release_mutex(); }
238                         operator bool() const { return m_bObtained; }
239                 };
240
241         public:
242                 ThreadConditionSignal();
243                 ~ThreadConditionSignal();
244
245                 // IMPORTANT: All of the functions below MUST be called ONLY while holding a lock for this object !!!
246                 void await_condition();
247                 bool await_condition(timediff tdTimeout);
248                 void signal_condition_single();
249                 void signal_condition_broadcast();
250         };
251         //--------------------------------------------------------
252
253
254
255
256
257         //--------------------------------------------------------
258         // A doorbell is a simple communication mechanism that allows
259         // one thread two wake another when there is some work to be done.
260         // The signal is 'clear on read'. This class is not intended for
261         // multi-way communication (i.e. more than two threads).
262 //#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR (!XPLATFORMTHREADS_WINDOWS && !XPLATFORMOSSERVICES_MACOS)
263 #ifdef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
264 #undef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
265 #endif
266 #define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR 1
267 #if XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
268         class doorbell_type
269         {
270         protected:
271                 ThreadConditionSignal m_signal;
272                 bool m_rang;
273         protected:
274                 template<bool wait_forever> bool wait_for_ring_internal(timediff timeout)
275                 {// mutex
276                         ThreadConditionSignal::lock guard(m_signal);
277                         if (!m_rang)
278                         {
279                                 if (wait_forever)
280                                 {
281                                         m_signal.await_condition();
282                                 }
283                                 else
284                                 {
285                                         m_signal.await_condition(timeout);
286                                 }
287                         }
288                         const bool rang = m_rang;
289                         m_rang = false;
290                         return rang;
291                 }// mutex
292
293         public:
294                 doorbell_type() : m_rang(false) {}
295                 inline ~doorbell_type() {}
296                 inline void ring()
297                 {// mutex
298                         ThreadConditionSignal::lock guard(m_signal);
299                         m_rang = true;
300                         m_signal.signal_condition_single();
301                 }// mutex
302                 inline bool wait_for_ring() { return wait_for_ring_internal<true>(0); }
303                 inline bool wait_for_ring(timediff timeout) { return wait_for_ring_internal<false>(timeout); }
304         };
305 #else
306         class doorbell_type : public noncopyableobject
307         {
308         protected:
309                 os_dependent_handle_type m_os_dependent_handle;
310         protected:
311                 template<bool wait_forever> bool wait_for_ring_internal(timediff);
312         public:
313                 doorbell_type();
314                 ~doorbell_type();
315                 void ring();
316                 bool wait_for_ring();
317                 bool wait_for_ring(timediff timeout);
318         };
319 #endif // XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
320         //--------------------------------------------------------
321
322         //---------------------------------------------------------------
323         class DllExport WCThreadRef     // Class which holds the threadRef, DWORD in Windows and pthread_t in POSIX (Mac, Unix)
324         {
325         public:
326                 class OSDependent;  // the class which contains the OS Dependent implementation
327
328                 WCThreadRef() : m_osThreadRef(0) {}
329                 bool is_invalid() const { return m_osThreadRef == 0;}
330
331                 operator uintptr_t() const {return m_osThreadRef;}
332
333         protected:
334                 uintptr_t m_osThreadRef;
335                 WCThreadRef(uintptr_t n) : m_osThreadRef(n) {} 
336
337                 friend DllExport bool operator==(const WCThreadRef& first, const WCThreadRef& second);
338                 friend DllExport bool operator!=(const WCThreadRef& first, const WCThreadRef& second);
339                 friend DllExport bool operator<(const WCThreadRef& first, const WCThreadRef& second);
340                 friend DllExport bool operator>(const WCThreadRef& first, const WCThreadRef& second);
341         };
342
343         DllExport WCThreadRef GetCurrentThreadRef();    // getting the current thread reference - cross-platform implemented
344         bool IsThreadExists(const WCThreadRef& threadRef);      // correct to the very snapshot of time of execution
345
346         //---------------------------------------------------------------
347
348     class DllExport WCAtomicLock
349     {
350     public:    
351         WCAtomicLock() : m_the_lock(0) {}
352                 bool obtain(const uint32_t in_num_trys = 1);
353                 void release();
354         private:
355             int32_t m_the_lock;
356     };
357
358     //#include "BasicTypes/WavesAPIResetAligment.h"
359 #ifdef PLATFORM_WINDOWS
360 #pragma pack(pop)
361 #endif
362
363 #ifdef __APPLE__
364 #ifdef __GNUC__
365 #pragma pack(pop)
366 #endif
367 #endif
368
369 class WCStThreadMutexLocker
370 {
371 public:
372     WCStThreadMutexLocker(wvNS::wvThread::ThreadMutexInited& in_mutex) : 
373     m_mutex(in_mutex)
374     {
375         m_mutex.obtain();
376     }
377     
378     ~WCStThreadMutexLocker()
379     {
380         m_mutex.release();
381     }
382 protected:
383     wvNS::wvThread::ThreadMutexInited& m_mutex;
384     WCStThreadMutexLocker(const WCStThreadMutexLocker&);
385     WCStThreadMutexLocker& operator=(const WCStThreadMutexLocker&);
386 };
387     
388 } // namespace wvThread
389
390
391 } //namespace wvNS {
392 #endif // #ifndef __WCThreadSafe_h_