new audio engine backend for native CoreAudio audio I/O, and PortMIDI for MIDI.

Code builds, runs and functions. Full code review still pending, and some possibly changes to organization of code within the backend is possible
This commit is contained in:
Paul Davis 2014-02-24 14:39:10 -05:00
parent 0a6af1420f
commit 1de00ab6bb
84 changed files with 21936 additions and 0 deletions

View file

@ -0,0 +1,844 @@
/*
Copyright (C) 2013 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.
*/
#include "Threads/WCThreadSafe.h"
#if XPLATFORMTHREADS_WINDOWS
#define _WIN32_WINNT 0x0500 // need at least Windows2000 (for TryEnterCriticalSection() and SignalObjectAndWait()
#include "IncludeWindows.h"
#include <process.h>
#endif // XPLATFORMTHREADS_WINDOWS
#if defined(__MACOS__)
#include <CoreServices/CoreServices.h>
#include <stdio.h>
#endif // __MACOS__
#if XPLATFORMTHREADS_POSIX
#include </usr/include/unistd.h> // avoid the framework version and use the /usr/include version
#include <pthread.h>
#include <sched.h>
#include <sys/time.h>
#include <errno.h>
#include <signal.h>
// We do this externs because <stdio.h> comes from MSL
extern "C" FILE *popen(const char *command, const char *type);
extern "C" int pclose(FILE *stream);
static int (*BSDfread)( void *, size_t, size_t, FILE * ) = 0;
#include <string.h>
#endif //XPLATFORMTHREADS_POSIX
#include "Akupara/threading/atomic_ops.hpp"
namespace wvNS {
static const unsigned int knMicrosecondsPerSecond = 1000*1000;
static const unsigned int knNanosecondsPerMicrosecond = 1000;
static const unsigned int knNanosecondsPerSecond = knMicrosecondsPerSecond*knNanosecondsPerMicrosecond;
namespace wvThread
{
//--------------------------------------------------------------------------------
static inline bool EnsureThreadingInitialized()
{
bool bRetval = true;
return bRetval;
}
//--------------------------------------------------------------------------------
//--------------------------------------------------------------------------------
static uint32_t CalculateTicksPerMicrosecond();
static uint32_t CalculateTicksPerMicrosecond()
{
uint32_t nTicksPerMicrosecond=0;
#if defined(_WIN32)
LARGE_INTEGER TSC;
::QueryPerformanceFrequency(&TSC);
nTicksPerMicrosecond = uint32_t (TSC.QuadPart / knMicrosecondsPerSecond);
#elif defined(__linux__) && defined(__i386__)
static const timediff sktd_TSC_MeasurementPeriod = 40*1000; // delay for CalculateTicksPerMicrosecond() to measure the TSC frequency
uint64_t Tstart, Tend;
timeval tvtmp, tvstart, tvend;
//--------------------- begin measurement code
// poll to align to a tick of gettimeofday
::gettimeofday(&tvtmp,0);
do {
::gettimeofday(&tvstart,0);
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tstart)); // RDTSC
} while (tvtmp.tv_usec!=tvstart.tv_usec);
// delay some
::usleep(sktd_TSC_MeasurementPeriod);
//
::gettimeofday(&tvtmp,0);
do {
::gettimeofday(&tvend,0);
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (Tend)); // RDTSC
} while (tvtmp.tv_usec!=tvend.tv_usec);
//--------------------- end measurement code
suseconds_t elapsed_usec = (tvend.tv_sec-tvstart.tv_sec)*knMicrosecondsPerSecond + (tvend.tv_usec-tvstart.tv_usec);
uint64_t elapsed_ticks = Tend-Tstart;
nTicksPerMicrosecond = uint32_t (elapsed_ticks/elapsed_usec);
#endif
return nTicksPerMicrosecond;
}
#if defined(__MACOS__) //&& !defined(__MACH__)
bool FindNetInterfaceByIPAddress(const char *sIP, char *sInterface) // sIP and sInterface are both char[16]
{
FILE *fProcess , *pSubcall;
char sLine[256]="", *pToken, sCommand[150];
bool res = false;
int iret;
fProcess = popen("ifconfig -l inet", "r");
if (fProcess)
{
memset(sInterface, '\0', 16);
iret = BSDfread(sLine, sizeof(char), sizeof(sLine), fProcess);
pToken = strtok(sLine, " ");
while (pToken)
{
sprintf(sCommand, "ifconfig %s | grep \"inet %s \"", pToken, sIP);
pSubcall = popen(sCommand, "r");
if (pSubcall)
{
char sSubline[100]="";
if (BSDfread(sSubline, sizeof(char), sizeof(sSubline), pSubcall))
{
// found
strcpy(sInterface, pToken);
res = true;
pclose(pSubcall);
break;
}
}
pclose(pSubcall);
pToken = strtok(NULL, " ");
}
}
pclose(fProcess);
return res;
}
#endif // MACOS
timestamp now(void)
{
EnsureThreadingInitialized();
static const uint32_t nTicksPerMicrosecond = CalculateTicksPerMicrosecond();
#if defined(_WIN32)
if (nTicksPerMicrosecond)
{
LARGE_INTEGER TSC;
::QueryPerformanceCounter(&TSC);
return timestamp(uint32_t(TSC.QuadPart/nTicksPerMicrosecond));
}
else return timestamp(0);
#elif defined(__MACOS__)
if (nTicksPerMicrosecond) {} // prevent 'unused' warnings
UnsignedWide usecs;
::Microseconds(&usecs);
return timestamp(usecs.lo);
#elif defined(__linux__) && defined(__i386__) && defined(__gnu_linux__)
uint64_t TSC;
__asm__ __volatile__ (".byte 0x0f, 0x31" : "=A" (TSC)); // RDTSC
return timestamp(TSC/nTicksPerMicrosecond);
#elif defined(__linux__) && defined(__PPC__) && defined(__gnu_linux__)
#warning need to implement maybe
#else
#error Dont know how to get microseconds timer !
#endif // defined(_WIN32)
}
void sleep_milliseconds(unsigned int nMillisecs)
{
EnsureThreadingInitialized();
#if XPLATFORMTHREADS_WINDOWS
::Sleep(nMillisecs);
#elif XPLATFORMTHREADS_POSIX
::usleep(nMillisecs*1000);
#else
#error Not implemented for your OS
#endif
}
#if XPLATFORMTHREADS_WINDOWS
inline DWORD win32_milliseconds(timediff td) { return (td+499)/1000; }
#endif
void sleep(timediff _td)
{
if (_td>0)
{
EnsureThreadingInitialized();
#if XPLATFORMTHREADS_WINDOWS
::Sleep(win32_milliseconds(_td)); // This is the best we can do in windows
#elif XPLATFORMTHREADS_POSIX
::usleep(_td);
#else
#error Not implemented for your OS
#endif
}
}
#if XPLATFORMTHREADS_WINDOWS
void yield() { ::Sleep(0); }
#elif XPLATFORMTHREADS_POSIX
void yield() { ::sched_yield(); }
#endif
class ThreadMutexInited::OSDependentMutex : public noncopyableobject
{
#if defined (XPLATFORMTHREADS_WINDOWS)
protected:
CRITICAL_SECTION m_critsec;
public:
inline OSDependentMutex() { EnsureThreadingInitialized(); ::InitializeCriticalSection(&m_critsec); }
inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::DeleteCriticalSection (&m_critsec); }
inline void obtain() { EnsureThreadingInitialized(); ::EnterCriticalSection (&m_critsec); }
inline void release() { EnsureThreadingInitialized(); ::LeaveCriticalSection (&m_critsec); }
inline bool tryobtain() { EnsureThreadingInitialized(); return TryEnterCriticalSection(&m_critsec)!=FALSE; }
#elif defined (XPLATFORMTHREADS_POSIX)
protected:
pthread_mutex_t m_ptmutex;
public:
inline OSDependentMutex()
{
EnsureThreadingInitialized();
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
::pthread_mutex_init (&m_ptmutex, &attr);
}
inline ~OSDependentMutex() { EnsureThreadingInitialized(); ::pthread_mutex_destroy(&m_ptmutex); }
inline void obtain() { EnsureThreadingInitialized(); ::pthread_mutex_lock (&m_ptmutex); }
inline void release() { EnsureThreadingInitialized(); ::pthread_mutex_unlock (&m_ptmutex); }
inline bool tryobtain() { EnsureThreadingInitialized(); return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
#endif
};
ThreadMutexInited::ThreadMutexInited() :
m_osdmutex(0) {}
void ThreadMutexInited::init()
{
if (! is_init())
{
m_osdmutex = new OSDependentMutex;
}
}
void ThreadMutexInited::uninit()
{
if (is_init())
{
delete m_osdmutex;
m_osdmutex = 0;
}
}
ThreadMutexInited::~ThreadMutexInited()
{
uninit();
}
void ThreadMutexInited::obtain()
{
if (is_init())
{
m_osdmutex->obtain();
}
}
void ThreadMutexInited::release()
{
if (is_init())
{
m_osdmutex->release();
}
}
bool ThreadMutexInited::tryobtain()
{
bool retVal = true;
if (is_init())
{
retVal = m_osdmutex->tryobtain();
}
return retVal;
}
class ThreadConditionSignal::OSDependentObject : public noncopyableobject
{
#if defined (XPLATFORMTHREADS_POSIX)
protected:
pthread_cond_t m_ptcond;
pthread_mutex_t m_ptmutex;
public:
inline OSDependentObject()
{
EnsureThreadingInitialized();
::pthread_mutex_init(&m_ptmutex,0);
::pthread_cond_init(&m_ptcond, 0);
}
inline ~OSDependentObject() { ::pthread_cond_destroy(&m_ptcond), ::pthread_mutex_destroy(&m_ptmutex); }
inline void signal_unicast() { ::pthread_cond_signal(&m_ptcond); }
inline void signal_broadcast() { ::pthread_cond_broadcast(&m_ptcond); }
inline void await_signal() { ::pthread_cond_wait(&m_ptcond, &m_ptmutex); }
inline bool await_signal(timediff td)
{
timespec tspecDeadline;
timeval tvNow;
::gettimeofday(&tvNow,0);
tspecDeadline.tv_nsec = (tvNow.tv_usec + td%knMicrosecondsPerSecond)*knNanosecondsPerMicrosecond;
tspecDeadline.tv_sec = tvNow.tv_sec + td/knMicrosecondsPerSecond;
if (!(tspecDeadline.tv_nsec < suseconds_t(knNanosecondsPerSecond)))
++tspecDeadline.tv_sec, tspecDeadline.tv_nsec-=knNanosecondsPerSecond;
return ::pthread_cond_timedwait(&m_ptcond, &m_ptmutex, &tspecDeadline) != ETIMEDOUT;
}
void obtain_mutex() { ::pthread_mutex_lock(&m_ptmutex); }
bool tryobtain_mutex() { return ::pthread_mutex_trylock(&m_ptmutex)!=EBUSY; }
void release_mutex() { ::pthread_mutex_unlock(&m_ptmutex); }
#elif XPLATFORMTHREADS_WINDOWS
protected:
unsigned int m_nWaiterCount;
CRITICAL_SECTION m_csectWaiterCount;
HANDLE m_hndSemaphoreSignaller; // We keep this semaphore always at 0 count (non-signalled). We use it to release a controlled number of threads.
HANDLE m_hndEventAllWaitersReleased; // auto-reset
HANDLE m_hndMutex; // the mutex associated with the condition
bool m_bBroadcastSignalled; // means that the last waiter must signal m_hndEventAllWaitersReleased when done waiting
protected:
// - - - - - - - - - - - - - - - - - - - - - - - -
bool await_signal_win32(DWORD dwTimeout)
{
::EnterCriticalSection(&m_csectWaiterCount);
++m_nWaiterCount;
::LeaveCriticalSection(&m_csectWaiterCount);
// This is the actual wait for the signal
bool bWaitSucceeded = ::SignalObjectAndWait(m_hndMutex, m_hndSemaphoreSignaller, dwTimeout, FALSE) == WAIT_OBJECT_0;
//
::EnterCriticalSection(&m_csectWaiterCount);
bool bLastWaiter = --m_nWaiterCount==0 && m_bBroadcastSignalled;
::LeaveCriticalSection(&m_csectWaiterCount);
// re-acquire the mutex
if (bLastWaiter)
::SignalObjectAndWait(m_hndEventAllWaitersReleased, m_hndMutex, INFINITE, FALSE);
else
::WaitForSingleObject(m_hndMutex, INFINITE);
return bWaitSucceeded;
}
public:
inline bool await_signal(timediff td) { return await_signal_win32((win32_milliseconds(td))); }
inline void await_signal() { await_signal_win32(INFINITE); }
OSDependentObject() : m_nWaiterCount(0), m_bBroadcastSignalled(false)
{
EnsureThreadingInitialized();
::InitializeCriticalSection(&m_csectWaiterCount);
m_hndEventAllWaitersReleased = ::CreateEvent(
0, // security
FALSE, // auto-reset
FALSE, // initial state non-sognalled
0); // name
m_hndSemaphoreSignaller = ::CreateSemaphore(
0, // security
0, // initial count (and will stay this way)
0x100000, // maximum count (should be as large as the maximum number of waiting threads)
0); // name
m_hndMutex = ::CreateMutex(
0, // security
FALSE, // not owned initially
0); // name
//if (m_hndEventAllWaitersReleased==INVALID_HANDLE_VALUE || m_hndSemaphoreSignaller==INVALID_HANDLE_VALUE)
// throw something();
}
~OSDependentObject()
{
::CloseHandle(m_hndMutex);
::CloseHandle(m_hndSemaphoreSignaller);
::CloseHandle(m_hndEventAllWaitersReleased);
::DeleteCriticalSection(&m_csectWaiterCount);
}
inline void signal_unicast()
{
::EnterCriticalSection(&m_csectWaiterCount);
unsigned int nWaiters = m_nWaiterCount;
::LeaveCriticalSection(&m_csectWaiterCount);
if (nWaiters)
::ReleaseSemaphore(m_hndSemaphoreSignaller, 1, 0); // release 1 semaphore credit to release one waiting thread
}
void signal_broadcast()
{
::EnterCriticalSection(&m_csectWaiterCount);
unsigned int nWaiters = m_nWaiterCount;
if (nWaiters)
{
m_bBroadcastSignalled = true;
::ReleaseSemaphore(m_hndSemaphoreSignaller, nWaiters, 0); // release as many credits as there are waiting threads
::LeaveCriticalSection(&m_csectWaiterCount);
::WaitForSingleObject(m_hndEventAllWaitersReleased, INFINITE);
// at this point all threads are waiting on m_hndMutex, which would be released outside this function call
m_bBroadcastSignalled = false;
}
else
// no one is waiting
::LeaveCriticalSection(&m_csectWaiterCount);
}
//------------------------------------------------
inline void obtain_mutex() { ::WaitForSingleObject(m_hndMutex, INFINITE); }
inline bool tryobtain_mutex() { return ::WaitForSingleObject(m_hndMutex,0) == WAIT_OBJECT_0; }
inline void release_mutex() { ::ReleaseMutex(m_hndMutex); }
//------------------------------------------------
#endif // OS switch
};
void ThreadConditionSignal::obtain_mutex()
{
m_osdepobj.obtain_mutex();
}
bool ThreadConditionSignal::tryobtain_mutex() { return m_osdepobj.tryobtain_mutex(); }
void ThreadConditionSignal::release_mutex()
{
m_osdepobj.release_mutex();
}
void ThreadConditionSignal::await_condition() { m_osdepobj.await_signal(); }
bool ThreadConditionSignal::await_condition(timediff tdTimeout) { return m_osdepobj.await_signal(tdTimeout); }
void ThreadConditionSignal::signal_condition_single() { m_osdepobj.signal_unicast(); }
void ThreadConditionSignal::signal_condition_broadcast() { m_osdepobj.signal_broadcast(); }
ThreadConditionSignal::ThreadConditionSignal() : m_osdepobj(*new OSDependentObject) {}
ThreadConditionSignal::~ThreadConditionSignal() { delete &m_osdepobj; }
#if XPLATFORMTHREADS_POSIX
namespace // anon
{
inline int max_FIFO_schedparam()
{
static const int max_priority = ::sched_get_priority_max(SCHED_FIFO);
return max_priority;
}
inline int schedparam_by_percentage(unsigned short percentage)
{
return (max_FIFO_schedparam()*10*percentage+500)/1000;
}
class POSIXThreadPriority
{
public:
int m_SchedPolicy;
int m_SchedPriority;
POSIXThreadPriority(ThreadPriority pri)
{
switch (pri)
{
case ThreadPriority::TimeCritical: m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(80); break;
case ThreadPriority::AboveNormal: m_SchedPolicy=SCHED_FIFO, m_SchedPriority=schedparam_by_percentage(20); break;
case ThreadPriority::BelowNormal: // fall through to normal; nothing is below normal in POSIX
case ThreadPriority::Normal: // fall through to default
default: m_SchedPolicy=SCHED_OTHER, m_SchedPriority=0; break;
}
}
};
} // namespace anonymous
#endif // XPLATFORMTHREADS_POSIX
#if XPLATFORMTHREADS_WINDOWS
namespace // anon
{
inline int WinThreadPriority(ThreadPriority pri)
{
switch (pri)
{
case ThreadPriority::BelowNormal: return THREAD_PRIORITY_BELOW_NORMAL;
case ThreadPriority::AboveNormal: return THREAD_PRIORITY_ABOVE_NORMAL;
case ThreadPriority::TimeCritical: return THREAD_PRIORITY_TIME_CRITICAL;
case ThreadPriority::Normal: // fall through to default
default: return THREAD_PRIORITY_NORMAL;
}
}
} // namespace anon
#endif // XPLATFORMTHREADS_WINDOWS
void SetMyThreadPriority(ThreadPriority pri)
{
#if XPLATFORMTHREADS_WINDOWS
::SetThreadPriority(::GetCurrentThread(), WinThreadPriority(pri));
#endif // XPLATFORMTHREADS_WINDOWS
#if XPLATFORMTHREADS_POSIX
const POSIXThreadPriority posixpri(pri);
sched_param sparam;
::memset(&sparam, 0, sizeof(sparam));
sparam.sched_priority = posixpri.m_SchedPriority;
#if defined(__linux__)
::sched_setscheduler(0, posixpri.m_SchedPolicy, &sparam); // linux uses this function instead of pthread_
#else
pthread_setschedparam(pthread_self(), posixpri.m_SchedPolicy, &sparam);
#endif
#endif // XPLATFORMTHREADS_POSIX
}
struct ThreadWrapperData
{
ThreadFunction *func;
ThreadFunctionArgument arg;
};
#if XPLATFORMTHREADS_WINDOWS
static unsigned int __stdcall ThreadWrapper(void * arg)
{
register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
ThreadFunction *func=twd->func;
ThreadFunctionArgument farg=twd->arg;
delete twd;
return DWORD(func(farg));
}
#elif XPLATFORMTHREADS_POSIX
static void * ThreadWrapper(void *arg)
{
register ThreadWrapperData *twd = reinterpret_cast<ThreadWrapperData*>(arg);
ThreadFunction *func=twd->func;
ThreadFunctionArgument farg=twd->arg;
delete twd;
return reinterpret_cast<void*>(func(farg));
}
typedef void*(ThreadWrapperFunction)(void*);
static ThreadWrapperFunction *ThunkedThreadWrapper = ThreadWrapper;
#endif // OS switch
class ThreadHandle::OSDependent
{
public:
static void StartThread(ThreadWrapperData *, ThreadHandle &, ThreadPriority);
static bool KillThread(ThreadHandle);
static bool JoinThread(ThreadHandle, ThreadFunctionReturnType*);
static void Close(ThreadHandle);
#if XPLATFORMTHREADS_WINDOWS
static inline uintptr_t from_oshandle(HANDLE h) { return reinterpret_cast<uintptr_t>(h); }
static inline HANDLE to_oshandle(uintptr_t h) { return reinterpret_cast<HANDLE>(h); }
#elif XPLATFORMTHREADS_POSIX
static inline uintptr_t from_oshandle(pthread_t pt) { return uintptr_t(pt); }
static inline pthread_t to_oshandle(uintptr_t h) { return pthread_t(h); }
#endif // OS switch
};
#if XPLATFORMTHREADS_WINDOWS
const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(INVALID_HANDLE_VALUE));
#elif XPLATFORMTHREADS_POSIX
const ThreadHandle ThreadHandle::Invalid(OSDependent::from_oshandle(0));
#endif // OS switch
inline void ThreadHandle::OSDependent::StartThread(ThreadWrapperData *ptwdata, ThreadHandle &th, ThreadPriority pri)
{
#if XPLATFORMTHREADS_WINDOWS
uintptr_t h = ::_beginthreadex(
0, // no security attributes, not inheritable
0, // default stack size
ThreadWrapper, // function to call
(void*)(ptwdata), // argument for function
0, // creation flags
0 // where to store thread ID
);
if (h)
{
th.m_oshandle = h;
if (pri!=ThreadPriority::Normal)
::SetThreadPriority(to_oshandle(h), WinThreadPriority(pri));
}
else
th=Invalid;
#elif XPLATFORMTHREADS_POSIX
pthread_attr_t my_thread_attr, *pmy_thread_attr = 0;
sched_param my_schedparam;
if (pri!=ThreadPriority::Normal)
{
pmy_thread_attr = &my_thread_attr;
const POSIXThreadPriority posixpriority(pri);
int result;
result = pthread_attr_init (pmy_thread_attr);
result = pthread_attr_setschedpolicy(pmy_thread_attr, posixpriority.m_SchedPolicy);
memset(&my_schedparam, 0, sizeof(my_schedparam));
my_schedparam.sched_priority = posixpriority.m_SchedPriority;
result = pthread_attr_setschedparam(pmy_thread_attr, &my_schedparam);
}
pthread_t pt;
int anyerr = pthread_create(
&pt, // variable for thread handle
pmy_thread_attr, // default attributes
ThunkedThreadWrapper,
ptwdata
);
if (anyerr)
th=Invalid;
else
th.m_oshandle = OSDependent::from_oshandle(pt);
#endif
}
inline bool ThreadHandle::OSDependent::KillThread(ThreadHandle h)
{
#if XPLATFORMTHREADS_WINDOWS
return ::TerminateThread(to_oshandle(h.m_oshandle), (DWORD)-1) != 0;
#elif XPLATFORMTHREADS_POSIX
return pthread_cancel(to_oshandle(h.m_oshandle)) == 0;
#endif
}
bool ThreadHandle::OSDependent::JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
{
#if XPLATFORMTHREADS_WINDOWS
const bool kbReturnedOk = (WAIT_OBJECT_0 == ::WaitForSingleObject(OSDependent::to_oshandle(h.m_oshandle), INFINITE));
if (kbReturnedOk && pretval)
{
DWORD dwExitCode;
::GetExitCodeThread(to_oshandle(h.m_oshandle), &dwExitCode);
*pretval = (ThreadFunctionReturnType)(dwExitCode);
}
return kbReturnedOk;
#endif
#if XPLATFORMTHREADS_POSIX
ThreadFunctionReturnType ptrExitCode = 0;
int join_return_code = pthread_join(to_oshandle(h.m_oshandle), (void**)ptrExitCode);
const bool kbReturnedOk = (0 == join_return_code);
if (0 != pretval)
{
*pretval = ptrExitCode;
}
return kbReturnedOk;
#endif
}
#if XPLATFORMTHREADS_WINDOWS
inline void ThreadHandle::OSDependent::Close(ThreadHandle h)
{
::CloseHandle(OSDependent::to_oshandle(h.m_oshandle));
}
#endif // XPLATFORMTHREADS_WINDOWS
#if XPLATFORMTHREADS_POSIX
inline void ThreadHandle::OSDependent::Close(ThreadHandle) {}
#endif // XPLATFORMTHREADS_POSIX
//**********************************************************************************************
class WCThreadRef::OSDependent
{
public:
static void GetCurrentThreadRef(WCThreadRef& tid);
#if XPLATFORMTHREADS_WINDOWS
static inline uintptr_t from_os(DWORD thread_id) { return (uintptr_t)(thread_id); }
static inline DWORD to_os(uintptr_t thread_id) { return (DWORD)(thread_id); }
#elif XPLATFORMTHREADS_POSIX
static inline uintptr_t from_os(pthread_t thread_id) { return (uintptr_t)(thread_id); }
static inline pthread_t to_os(uintptr_t thread_id) { return pthread_t(thread_id); }
#endif // OS switch
};
//**********************************************************************************************
inline void WCThreadRef::OSDependent::GetCurrentThreadRef(WCThreadRef& tid)
{
#if XPLATFORMTHREADS_WINDOWS
DWORD thread_id = ::GetCurrentThreadId();
tid.m_osThreadRef = OSDependent::from_os(thread_id);
#elif XPLATFORMTHREADS_POSIX
pthread_t thread_id = ::pthread_self();
tid.m_osThreadRef = OSDependent::from_os(thread_id);
#endif // OS switch
}
//**********************************************************************************************
ThreadHandle StartThread(ThreadFunction func, ThreadFunctionArgument arg, ThreadPriority thpri)
{
EnsureThreadingInitialized();
ThreadWrapperData *ptwdata = new ThreadWrapperData;
ptwdata->func = func;
ptwdata->arg = arg;
ThreadHandle thToReturn;
ThreadHandle::OSDependent::StartThread(ptwdata, thToReturn, thpri);
return thToReturn;
}
bool KillThread(ThreadHandle h)
{
EnsureThreadingInitialized();
return ThreadHandle::OSDependent::KillThread(h);
}
bool JoinThread(ThreadHandle h, ThreadFunctionReturnType *pretval)
{
EnsureThreadingInitialized();
return ThreadHandle::OSDependent::JoinThread(h, pretval);
}
void Close(ThreadHandle h)
{
EnsureThreadingInitialized();
return ThreadHandle::OSDependent::Close(h);
}
//*******************************************************************************************
WCThreadRef GetCurrentThreadRef()
{
EnsureThreadingInitialized(); // Is it necessary?
WCThreadRef tRefToReturn;
WCThreadRef::OSDependent::GetCurrentThreadRef(tRefToReturn);
return tRefToReturn;
}
//*******************************************************************************************
bool IsThreadExists(const WCThreadRef& threadRef)
{
#if XPLATFORMTHREADS_WINDOWS
DWORD dwThreadId = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
HANDLE handle = ::OpenThread(SYNCHRONIZE, // dwDesiredAccess - use of the thread handle in any of the wait functions
FALSE, // bInheritHandle - processes do not inherit this handle
dwThreadId);
// Now we have the handle, check if the associated thread exists:
DWORD retVal = WaitForSingleObject(handle, 0);
if (retVal == WAIT_FAILED)
return false; // the thread does not exists
else
return true; // the thread exists
#elif XPLATFORMTHREADS_POSIX
pthread_t pthreadRef = WCThreadRef::OSDependent::to_os((uintptr_t)threadRef);
int retVal = pthread_kill(pthreadRef, 0); // send a signal to the thread, but do nothing
if (retVal == ESRCH)
return false; // the thread does not exists
else
return true; // the thread exists
#endif // OS switch
}
//*******************************************************************************************
bool operator==(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef == second.m_osThreadRef);
}
bool operator!=(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef != second.m_osThreadRef);
}
bool operator<(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef < second.m_osThreadRef);
}
bool operator>(const WCThreadRef& first, const WCThreadRef& second)
{
return (first.m_osThreadRef > second.m_osThreadRef);
}
bool WCAtomicLock::obtain(const uint32_t in_num_trys)
{
bool retVal = false;
uint32_t timeOut = in_num_trys;
while (true)
{
retVal = Akupara::threading::atomic::compare_and_store<int32_t>(&m_the_lock, int32_t(0), int32_t(1));
if (retVal)
{
break;
}
else
{
if (--timeOut == 0)
{
break;
}
sleep_milliseconds(1000);
}
}
return retVal;
}
void WCAtomicLock::release()
{
m_the_lock = 0;
}
} // namespace wvThread
} // namespace wvNS {