Paul Davis
000609901b
This follows the letter sent from Waves Audio Ltd. to Paul Davis dated February 20th 2014 agreeing to release this code under the GNU Public License, version 2, with copyright owned by Waves Audio Ltd
412 lines
13 KiB
C++
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_
|