mirror of
https://github.com/Ardour/ardour.git
synced 2026-01-25 06:37:29 +01:00
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:
parent
0a6af1420f
commit
1de00ab6bb
84 changed files with 21936 additions and 0 deletions
844
libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
Normal file
844
libs/backends/wavesaudio/wavesapi/threads/WCThreadSafe.cpp
Normal 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 {
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue