13
0
livetrax/libs/backends/wavesaudio/wavesapi/Threads/WCThreadSafe.h

412 lines
13 KiB
C++

/*
Copyright (C) 2014 Waves Audio Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef __WCThreadSafe_h_
#define __WCThreadSafe_h_
/* Copy to include
#include "Threads/WCThreadSafe.h"
*/
//
// * WCThreadSafe.h (used to be called XPlatformOSServices.hpp)
// *
// * Consistent C++ interfaces to common Operating System services.
// *
// *
// *
// *
// * Created 2004-December-13 by Udi Barzilai as XPlatformOSServices.hpp
// * Moved to WCThreadSafe.h by Shai 26/10/2005
// * 26/10/2005: ThreadMutex now inhetites from ThreadMutexInited
// * namespace changed to wvThread
#include "WavesPublicAPI/wstdint.h"
#include <string>
#include "BasicTypes/WUDefines.h"
#if defined(__linux__) || defined(__APPLE__)
#define XPLATFORMOSSERVICES_UNIX 1
#endif
#if defined(_WIN32)
#define XPLATFORMOSSERVICES_WIN32 1
#endif
#if XPLATFORMOSSERVICES_WIN32
#define XPLATFORMTHREADS_WINDOWS 1
#elif XPLATFORMOSSERVICES_UNIX
#define XPLATFORMTHREADS_POSIX 1
#endif
namespace wvNS {
typedef uint32_t WTThreadSafetyType;
const WTThreadSafetyType kNoThreadSafetyNeeded = 0;
const WTThreadSafetyType kpthreadsmutexThreadSafety = 1;
namespace wvThread
{
//#include "BasicTypes/WavesAPISetAligment.h"
//Packing affects the layout of classes, and commonly, if packing changes across header files, there can be problems.
#ifdef PLATFORM_WINDOWS
#pragma pack(push)
#pragma pack(8)
#endif
#ifdef __APPLE__
#ifdef __GNUC__
#pragma pack(push, 8)
#endif
#endif
//--------------------------------------------------------
typedef int32_t timediff; // in microseconds
static const timediff ktdOneSecond = 1000*1000;
//--------------------------------------------------------
class timestamp
{
protected:
typedef uint32_t tickcount;
tickcount m_nMicroseconds; // may wrap around
static const tickcount ms_knWraparoundThreshold = ~tickcount(0) ^ (~tickcount(0)>>1); // half the range
public:
timestamp() : m_nMicroseconds(0) { /* uninitialized */ }
timestamp(const timestamp &_ts) : m_nMicroseconds(_ts.m_nMicroseconds) {}
timestamp &operator=(const timestamp &_rhs) { m_nMicroseconds = _rhs.m_nMicroseconds; return *this; }
explicit timestamp(tickcount _i) : m_nMicroseconds(_i) {}
uint32_t ticks() const { return m_nMicroseconds; }
timediff operator-(timestamp _rhs) const { return timediff(m_nMicroseconds-_rhs.m_nMicroseconds); }
timestamp & operator+=(timediff _t) { m_nMicroseconds+=_t; return *this; }
timestamp & operator-=(timediff _t) { m_nMicroseconds-=_t; return *this; }
timestamp operator+(timediff _t) const { return timestamp(m_nMicroseconds+_t); }
timestamp operator-(timediff _t) const { return timestamp(m_nMicroseconds-_t); }
bool operator==(timestamp _rhs) const { return m_nMicroseconds==_rhs.m_nMicroseconds; }
bool operator!=(timestamp _rhs) const { return m_nMicroseconds!=_rhs.m_nMicroseconds; }
bool operator< (timestamp _rhs) const { return m_nMicroseconds-_rhs.m_nMicroseconds >= ms_knWraparoundThreshold; }
static timestamp null() { return timestamp(0); }
bool is_null() const { return m_nMicroseconds==0; }
};
//--------------------------------------------------------
#ifdef __APPLE__
bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface);
#endif // MACOS
//--------------------------------------------------------
timestamp now();
//--------------------------------------------------------
DllExport void sleep(timediff);
DllExport void sleep_milliseconds(unsigned int nMillisecs);
//--------------------------------------------------------
void yield();
//--------------------------------------------------------
typedef uintptr_t os_dependent_handle_type;
//--------------------------------------------------------
typedef int ThreadFunctionReturnType;
typedef void * ThreadFunctionArgument;
//--------------------------------------------------------
typedef ThreadFunctionReturnType (ThreadFunction)(ThreadFunctionArgument);
//--------------------------------------------------------
class ThreadHandle
{
public:
class OSDependent;
protected:
uintptr_t m_oshandle; // hopefully this is good enough for all systems
public:
static const ThreadHandle Invalid;
protected:
ThreadHandle(uintptr_t n) : m_oshandle(n) {}
public:
ThreadHandle() : m_oshandle(Invalid.m_oshandle) {}
bool is_invalid() const { return !m_oshandle || m_oshandle==Invalid.m_oshandle; }
};
//--------------------------------------------------------
class ThreadPriority
{
public: enum value { BelowNormal=1, Normal=2, AboveNormal=3, TimeCritical=4 };
protected: value m_value;
public: ThreadPriority(value v) : m_value(v) {}
public: operator value() const { return m_value; }
};
//--------------------------------------------------------
void SetMyThreadPriority(ThreadPriority);
//--------------------------------------------------------
ThreadHandle StartThread(ThreadFunction, ThreadFunctionArgument, ThreadPriority=ThreadPriority::Normal);
bool JoinThread(ThreadHandle, ThreadFunctionReturnType * = 0);
bool KillThread(ThreadHandle); // use only for abnormal termination
void Close(ThreadHandle); // should be called once for every handle obtained from StartThread.
//--------------------------------------------------------
//--------------------------------------------------------
class DllExport noncopyableobject
{
protected:
noncopyableobject() {}
private:
noncopyableobject(const noncopyableobject &);
noncopyableobject & operator=(const noncopyableobject &);
};
//--------------------------------------------------------
//--------------------------------------------------------
// Thread Mutex class that needs to be explicitly initialized
class DllExport ThreadMutexInited : public noncopyableobject
{
protected:
class OSDependentMutex;
OSDependentMutex* m_osdmutex;
public:
ThreadMutexInited();
~ThreadMutexInited();
void init();
void uninit();
inline bool is_init() { return 0 != m_osdmutex; }
void obtain();
bool tryobtain();
void release();
private:
ThreadMutexInited(const ThreadMutexInited&); // cannot be copied
ThreadMutexInited& operator=(const ThreadMutexInited&); // cannot be copied
public:
class lock : public noncopyableobject
{
protected:
ThreadMutexInited &m_mutex;
public:
inline lock(ThreadMutexInited &mtx) : m_mutex(mtx) { m_mutex.obtain(); }
inline ~lock() { m_mutex.release(); }
};
class trylock : public noncopyableobject
{
protected:
ThreadMutexInited &m_mutex;
bool m_bObtained;
public:
inline trylock(ThreadMutexInited &mtx) : m_mutex(mtx), m_bObtained(false) { m_bObtained = m_mutex.tryobtain(); }
inline ~trylock() { if (m_bObtained) m_mutex.release(); }
inline operator bool() const { return m_bObtained; }
};
};
//--------------------------------------------------------
// Thread Mutex class that is automatically initialized
class ThreadMutex : public ThreadMutexInited
{
public:
ThreadMutex() {init();}
};
//--------------------------------------------------------
class DllExport ThreadConditionSignal : public noncopyableobject
{
protected:
class OSDependentObject;
OSDependentObject &m_osdepobj;
protected:
void obtain_mutex();
bool tryobtain_mutex();
void release_mutex();
public:
class lock : public noncopyableobject
{
protected:
ThreadConditionSignal &m_tcs;
public:
lock(ThreadConditionSignal &tcs) : m_tcs(tcs) { m_tcs.obtain_mutex(); }
~lock() { m_tcs.release_mutex(); }
};
class trylock : public noncopyableobject
{
protected:
ThreadConditionSignal &m_tcs;
bool m_bObtained;
public:
trylock(ThreadConditionSignal &tcs) : m_tcs(tcs), m_bObtained(false) { m_bObtained = m_tcs.tryobtain_mutex(); }
~trylock() { if (m_bObtained) m_tcs.release_mutex(); }
operator bool() const { return m_bObtained; }
};
public:
ThreadConditionSignal();
~ThreadConditionSignal();
// IMPORTANT: All of the functions below MUST be called ONLY while holding a lock for this object !!!
void await_condition();
bool await_condition(timediff tdTimeout);
void signal_condition_single();
void signal_condition_broadcast();
};
//--------------------------------------------------------
//--------------------------------------------------------
// A doorbell is a simple communication mechanism that allows
// one thread two wake another when there is some work to be done.
// The signal is 'clear on read'. This class is not intended for
// multi-way communication (i.e. more than two threads).
//#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR (!XPLATFORMTHREADS_WINDOWS && !XPLATFORMOSSERVICES_MACOS)
#ifdef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
#undef XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
#endif
#define XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR 1
#if XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
class doorbell_type
{
protected:
ThreadConditionSignal m_signal;
bool m_rang;
protected:
template<bool wait_forever> bool wait_for_ring_internal(timediff timeout)
{// mutex
ThreadConditionSignal::lock guard(m_signal);
if (!m_rang)
{
if (wait_forever)
{
m_signal.await_condition();
}
else
{
m_signal.await_condition(timeout);
}
}
const bool rang = m_rang;
m_rang = false;
return rang;
}// mutex
public:
doorbell_type() : m_rang(false) {}
inline ~doorbell_type() {}
inline void ring()
{// mutex
ThreadConditionSignal::lock guard(m_signal);
m_rang = true;
m_signal.signal_condition_single();
}// mutex
inline bool wait_for_ring() { return wait_for_ring_internal<true>(0); }
inline bool wait_for_ring(timediff timeout) { return wait_for_ring_internal<false>(timeout); }
};
#else
class doorbell_type : public noncopyableobject
{
protected:
os_dependent_handle_type m_os_dependent_handle;
protected:
template<bool wait_forever> bool wait_for_ring_internal(timediff);
public:
doorbell_type();
~doorbell_type();
void ring();
bool wait_for_ring();
bool wait_for_ring(timediff timeout);
};
#endif // XPLATFORMTHREADS_DOORBELL_INLINE_USING_COND_VAR
//--------------------------------------------------------
//---------------------------------------------------------------
class DllExport WCThreadRef // Class which holds the threadRef, DWORD in Windows and pthread_t in POSIX (Mac, Unix)
{
public:
class OSDependent; // the class which contains the OS Dependent implementation
WCThreadRef() : m_osThreadRef(0) {}
bool is_invalid() const { return m_osThreadRef == 0;}
operator uintptr_t() const {return m_osThreadRef;}
protected:
uintptr_t m_osThreadRef;
WCThreadRef(uintptr_t n) : m_osThreadRef(n) {}
friend DllExport bool operator==(const WCThreadRef& first, const WCThreadRef& second);
friend DllExport bool operator!=(const WCThreadRef& first, const WCThreadRef& second);
friend DllExport bool operator<(const WCThreadRef& first, const WCThreadRef& second);
friend DllExport bool operator>(const WCThreadRef& first, const WCThreadRef& second);
};
DllExport WCThreadRef GetCurrentThreadRef(); // getting the current thread reference - cross-platform implemented
bool IsThreadExists(const WCThreadRef& threadRef); // correct to the very snapshot of time of execution
//---------------------------------------------------------------
class DllExport WCAtomicLock
{
public:
WCAtomicLock() : m_the_lock(0) {}
bool obtain(const uint32_t in_num_trys = 1);
void release();
private:
int32_t m_the_lock;
};
//#include "BasicTypes/WavesAPIResetAligment.h"
#ifdef PLATFORM_WINDOWS
#pragma pack(pop)
#endif
#ifdef __APPLE__
#ifdef __GNUC__
#pragma pack(pop)
#endif
#endif
class WCStThreadMutexLocker
{
public:
WCStThreadMutexLocker(wvNS::wvThread::ThreadMutexInited& in_mutex) :
m_mutex(in_mutex)
{
m_mutex.obtain();
}
~WCStThreadMutexLocker()
{
m_mutex.release();
}
protected:
wvNS::wvThread::ThreadMutexInited& m_mutex;
WCStThreadMutexLocker(const WCStThreadMutexLocker&);
WCStThreadMutexLocker& operator=(const WCStThreadMutexLocker&);
};
} // namespace wvThread
} //namespace wvNS {
#endif // #ifndef __WCThreadSafe_h_