2 Copyright (C) 2013 Waves Audio Ltd.
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.
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.
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.
19 #ifndef __WCThreadSafe_h_
20 #define __WCThreadSafe_h_
23 #include "Threads/WCThreadSafe.h"
27 // * WCThreadSafe.h (used to be called XPlatformOSServices.hpp)
29 // * Consistent C++ interfaces to common Operating System services.
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
39 #include "WavesPublicAPI/wstdint.h"
42 #include "BasicTypes/WUDefines.h"
44 #if defined(__linux__) || defined(__MACOS__)
45 #define XPLATFORMOSSERVICES_UNIX 1
49 #define XPLATFORMOSSERVICES_WIN32 1
52 #if XPLATFORMOSSERVICES_WIN32
53 #define XPLATFORMTHREADS_WINDOWS 1
54 #elif XPLATFORMOSSERVICES_UNIX
55 #define XPLATFORMTHREADS_POSIX 1
58 typedef uint32_t WTThreadSafetyType;
59 const WTThreadSafetyType kNoThreadSafetyNeeded = 0;
60 const WTThreadSafetyType kpthreadsmutexThreadSafety = 1;
65 //#include "BasicTypes/WavesAPISetAligment.h"
66 //Packing affects the layout of classes, and commonly, if packing changes across header files, there can be problems.
78 //--------------------------------------------------------
79 typedef int32_t timediff; // in microseconds
80 static const timediff ktdOneSecond = 1000*1000;
81 //--------------------------------------------------------
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
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; }
106 //--------------------------------------------------------
108 bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface);
110 //--------------------------------------------------------
112 //--------------------------------------------------------
113 DllExport void sleep(timediff);
114 DllExport void sleep_milliseconds(unsigned int nMillisecs);
115 //--------------------------------------------------------
117 //--------------------------------------------------------
121 typedef uintptr_t os_dependent_handle_type;
123 //--------------------------------------------------------
124 typedef int ThreadFunctionReturnType;
125 typedef void * ThreadFunctionArgument;
126 //--------------------------------------------------------
127 typedef ThreadFunctionReturnType (ThreadFunction)(ThreadFunctionArgument);
128 //--------------------------------------------------------
134 uintptr_t m_oshandle; // hopefully this is good enough for all systems
136 static const ThreadHandle Invalid;
138 ThreadHandle(uintptr_t n) : m_oshandle(n) {}
140 ThreadHandle() : m_oshandle(Invalid.m_oshandle) {}
141 bool is_invalid() const { return !m_oshandle || m_oshandle==Invalid.m_oshandle; }
143 //--------------------------------------------------------
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; }
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 //--------------------------------------------------------
163 //--------------------------------------------------------
164 class DllExport noncopyableobject
167 noncopyableobject() {}
169 noncopyableobject(const noncopyableobject &);
170 noncopyableobject & operator=(const noncopyableobject &);
172 //--------------------------------------------------------
175 //--------------------------------------------------------
176 // Thread Mutex class that needs to be explicitly initialized
177 class DllExport ThreadMutexInited : public noncopyableobject
180 class OSDependentMutex;
181 OSDependentMutex* m_osdmutex;
185 ~ThreadMutexInited();
189 inline bool is_init() { return 0 != m_osdmutex; }
195 ThreadMutexInited(const ThreadMutexInited&); // cannot be copied
196 ThreadMutexInited& operator=(const ThreadMutexInited&); // cannot be copied
199 class lock : public noncopyableobject
202 ThreadMutexInited &m_mutex;
204 inline lock(ThreadMutexInited &mtx) : m_mutex(mtx) { m_mutex.obtain(); }
205 inline ~lock() { m_mutex.release(); }
207 class trylock : public noncopyableobject
210 ThreadMutexInited &m_mutex;
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; }
218 //--------------------------------------------------------
220 // Thread Mutex class that is automatically initialized
221 class ThreadMutex : public ThreadMutexInited
224 ThreadMutex() {init();}
227 //--------------------------------------------------------
228 class DllExport ThreadConditionSignal : public noncopyableobject
231 class OSDependentObject;
232 OSDependentObject &m_osdepobj;
236 bool tryobtain_mutex();
237 void release_mutex();
240 class lock : public noncopyableobject
243 ThreadConditionSignal &m_tcs;
245 lock(ThreadConditionSignal &tcs) : m_tcs(tcs) { m_tcs.obtain_mutex(); }
246 ~lock() { m_tcs.release_mutex(); }
248 class trylock : public noncopyableobject
251 ThreadConditionSignal &m_tcs;
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; }
260 ThreadConditionSignal();
261 ~ThreadConditionSignal();
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();
269 //--------------------------------------------------------
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
284 #define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR 1
285 #if XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
289 ThreadConditionSignal m_signal;
292 template<bool wait_forever> bool wait_for_ring_internal(timediff timeout)
294 ThreadConditionSignal::lock guard(m_signal);
299 m_signal.await_condition();
303 m_signal.await_condition(timeout);
306 const bool rang = m_rang;
312 doorbell_type() : m_rang(false) {}
313 inline ~doorbell_type() {}
316 ThreadConditionSignal::lock guard(m_signal);
318 m_signal.signal_condition_single();
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); }
324 class doorbell_type : public noncopyableobject
327 os_dependent_handle_type m_os_dependent_handle;
329 template<bool wait_forever> bool wait_for_ring_internal(timediff);
334 bool wait_for_ring();
335 bool wait_for_ring(timediff timeout);
337 #endif // XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
338 //--------------------------------------------------------
340 //---------------------------------------------------------------
341 class DllExport WCThreadRef // Class which holds the threadRef, DWORD in Windows and pthread_t in POSIX (Mac, Unix)
344 class OSDependent; // the class which contains the OS Dependent implementation
346 WCThreadRef() : m_osThreadRef(0) {}
347 bool is_invalid() const { return m_osThreadRef == 0;}
349 operator uintptr_t() const {return m_osThreadRef;}
352 uintptr_t m_osThreadRef;
353 WCThreadRef(uintptr_t n) : m_osThreadRef(n) {}
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);
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
364 //---------------------------------------------------------------
366 class DllExport WCAtomicLock
369 WCAtomicLock() : m_the_lock(0) {}
370 bool obtain(const uint32_t in_num_trys = 1);
376 //#include "BasicTypes/WavesAPIResetAligment.h"
387 class WCStThreadMutexLocker
390 WCStThreadMutexLocker(wvNS::wvThread::ThreadMutexInited& in_mutex) :
396 ~WCStThreadMutexLocker()
401 wvNS::wvThread::ThreadMutexInited& m_mutex;
402 WCStThreadMutexLocker(const WCStThreadMutexLocker&);
403 WCStThreadMutexLocker& operator=(const WCStThreadMutexLocker&);
406 } // namespace wvThread
410 #endif // #ifndef __WCThreadSafe_h_