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