1 #ifndef __WCThreadSafe_h_
2 #define __WCThreadSafe_h_
5 #include "Threads/WCThreadSafe.h"
9 // * WCThreadSafe.h (used to be called XPlatformOSServices.hpp)
11 // * Consistent C++ interfaces to common Operating System services.
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
21 #include "WavesPublicAPI/wstdint.h"
24 #include "BasicTypes/WUDefines.h"
26 #if defined(__linux__) || defined(__APPLE__)
27 #define XPLATFORMOSSERVICES_UNIX 1
31 #define XPLATFORMOSSERVICES_WIN32 1
34 #if XPLATFORMOSSERVICES_WIN32
35 #define XPLATFORMTHREADS_WINDOWS 1
36 #elif XPLATFORMOSSERVICES_UNIX
37 #define XPLATFORMTHREADS_POSIX 1
40 typedef uint32_t WTThreadSafetyType;
41 const WTThreadSafetyType kNoThreadSafetyNeeded = 0;
42 const WTThreadSafetyType kpthreadsmutexThreadSafety = 1;
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
60 //--------------------------------------------------------
61 typedef int32_t timediff; // in microseconds
62 static const timediff ktdOneSecond = 1000*1000;
63 //--------------------------------------------------------
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
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; }
88 //--------------------------------------------------------
90 bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface);
92 //--------------------------------------------------------
94 //--------------------------------------------------------
95 DllExport void sleep(timediff);
96 DllExport void sleep_milliseconds(unsigned int nMillisecs);
97 //--------------------------------------------------------
99 //--------------------------------------------------------
103 typedef uintptr_t os_dependent_handle_type;
105 //--------------------------------------------------------
106 typedef int ThreadFunctionReturnType;
107 typedef void * ThreadFunctionArgument;
108 //--------------------------------------------------------
109 typedef ThreadFunctionReturnType (ThreadFunction)(ThreadFunctionArgument);
110 //--------------------------------------------------------
116 uintptr_t m_oshandle; // hopefully this is good enough for all systems
118 static const ThreadHandle Invalid;
120 ThreadHandle(uintptr_t n) : m_oshandle(n) {}
122 ThreadHandle() : m_oshandle(Invalid.m_oshandle) {}
123 bool is_invalid() const { return !m_oshandle || m_oshandle==Invalid.m_oshandle; }
125 //--------------------------------------------------------
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; }
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 //--------------------------------------------------------
145 //--------------------------------------------------------
146 class DllExport noncopyableobject
149 noncopyableobject() {}
151 noncopyableobject(const noncopyableobject &);
152 noncopyableobject & operator=(const noncopyableobject &);
154 //--------------------------------------------------------
157 //--------------------------------------------------------
158 // Thread Mutex class that needs to be explicitly initialized
159 class DllExport ThreadMutexInited : public noncopyableobject
162 class OSDependentMutex;
163 OSDependentMutex* m_osdmutex;
167 ~ThreadMutexInited();
171 inline bool is_init() { return 0 != m_osdmutex; }
177 ThreadMutexInited(const ThreadMutexInited&); // cannot be copied
178 ThreadMutexInited& operator=(const ThreadMutexInited&); // cannot be copied
181 class lock : public noncopyableobject
184 ThreadMutexInited &m_mutex;
186 inline lock(ThreadMutexInited &mtx) : m_mutex(mtx) { m_mutex.obtain(); }
187 inline ~lock() { m_mutex.release(); }
189 class trylock : public noncopyableobject
192 ThreadMutexInited &m_mutex;
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; }
200 //--------------------------------------------------------
202 // Thread Mutex class that is automatically initialized
203 class ThreadMutex : public ThreadMutexInited
206 ThreadMutex() {init();}
209 //--------------------------------------------------------
210 class DllExport ThreadConditionSignal : public noncopyableobject
213 class OSDependentObject;
214 OSDependentObject &m_osdepobj;
218 bool tryobtain_mutex();
219 void release_mutex();
222 class lock : public noncopyableobject
225 ThreadConditionSignal &m_tcs;
227 lock(ThreadConditionSignal &tcs) : m_tcs(tcs) { m_tcs.obtain_mutex(); }
228 ~lock() { m_tcs.release_mutex(); }
230 class trylock : public noncopyableobject
233 ThreadConditionSignal &m_tcs;
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; }
242 ThreadConditionSignal();
243 ~ThreadConditionSignal();
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();
251 //--------------------------------------------------------
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
266 #define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR 1
267 #if XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
271 ThreadConditionSignal m_signal;
274 template<bool wait_forever> bool wait_for_ring_internal(timediff timeout)
276 ThreadConditionSignal::lock guard(m_signal);
281 m_signal.await_condition();
285 m_signal.await_condition(timeout);
288 const bool rang = m_rang;
294 doorbell_type() : m_rang(false) {}
295 inline ~doorbell_type() {}
298 ThreadConditionSignal::lock guard(m_signal);
300 m_signal.signal_condition_single();
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); }
306 class doorbell_type : public noncopyableobject
309 os_dependent_handle_type m_os_dependent_handle;
311 template<bool wait_forever> bool wait_for_ring_internal(timediff);
316 bool wait_for_ring();
317 bool wait_for_ring(timediff timeout);
319 #endif // XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
320 //--------------------------------------------------------
322 //---------------------------------------------------------------
323 class DllExport WCThreadRef // Class which holds the threadRef, DWORD in Windows and pthread_t in POSIX (Mac, Unix)
326 class OSDependent; // the class which contains the OS Dependent implementation
328 WCThreadRef() : m_osThreadRef(0) {}
329 bool is_invalid() const { return m_osThreadRef == 0;}
331 operator uintptr_t() const {return m_osThreadRef;}
334 uintptr_t m_osThreadRef;
335 WCThreadRef(uintptr_t n) : m_osThreadRef(n) {}
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);
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
346 //---------------------------------------------------------------
348 class DllExport WCAtomicLock
351 WCAtomicLock() : m_the_lock(0) {}
352 bool obtain(const uint32_t in_num_trys = 1);
358 //#include "BasicTypes/WavesAPIResetAligment.h"
359 #ifdef PLATFORM_WINDOWS
369 class WCStThreadMutexLocker
372 WCStThreadMutexLocker(wvNS::wvThread::ThreadMutexInited& in_mutex) :
378 ~WCStThreadMutexLocker()
383 wvNS::wvThread::ThreadMutexInited& m_mutex;
384 WCStThreadMutexLocker(const WCStThreadMutexLocker&);
385 WCStThreadMutexLocker& operator=(const WCStThreadMutexLocker&);
388 } // namespace wvThread
392 #endif // #ifndef __WCThreadSafe_h_