Merge changes from The Witness.

This commit is contained in:
Ignacio
2015-03-24 12:14:49 -07:00
parent 7e2a9d1adb
commit a083337473
57 changed files with 2061 additions and 916 deletions

View File

@ -14,6 +14,7 @@
#pragma intrinsic(_InterlockedIncrement, _InterlockedDecrement)
#pragma intrinsic(_InterlockedCompareExchange, _InterlockedExchange)
//#pragma intrinsic(_InterlockedExchangeAdd64)
/*
extern "C"
@ -147,6 +148,11 @@ namespace nv {
return (uint32)_InterlockedExchange((long *)value, (long)desired);
}
inline uint32 atomicAdd(uint32 * value, uint32 value_to_add) {
nvDebugCheck((intptr_t(value) & 3) == 0);
return (uint32)_InterlockedExchangeAdd((long*)value, (long)value_to_add);
}
#elif NV_CC_CLANG && (NV_OS_IOS || NV_OS_DARWIN)
NV_COMPILER_CHECK(sizeof(uint32) == sizeof(long));
@ -177,14 +183,14 @@ namespace nv {
inline uint32 atomicIncrement(uint32 * value)
{
nvDebugCheck((intptr_t(value) & 3) == 0);
return __sync_add_and_fetch(value, 1);
}
inline uint32 atomicDecrement(uint32 * value)
{
nvDebugCheck((intptr_t(value) & 3) == 0);
return __sync_sub_and_fetch(value, 1);
}
@ -204,6 +210,12 @@ namespace nv {
return __sync_lock_test_and_set(value, desired);
}
inline uint32 atomicAdd(uint32 * value, uint32 value_to_add) {
nvDebugCheck((intptr_t(value) & 3) == 0);
return __sync_add_and_fetch(value, value_to_add);
}
#elif NV_CC_CLANG && POSH_CPU_STRONGARM
NV_COMPILER_CHECK(sizeof(uint32) == sizeof(long));
@ -288,6 +300,12 @@ namespace nv {
// this is confusingly named, it doesn't actually do a test but always sets
return __sync_lock_test_and_set(value, desired);
}
inline uint32 atomicAdd(uint32 * value, uint32 value_to_add) {
nvDebugCheck((intptr_t(value) & 3) == 0);
return __sync_add_and_fetch(value, value_to_add);
}
#else
#error "Atomics not implemented."

View File

@ -60,7 +60,7 @@ void Event::post() {
//ACS: move this after the unlock?
if(m->wait_count>0) {
pthread_cond_signal(&m->pt_cond);
pthread_cond_signal(&m->pt_cond);
}
pthread_mutex_unlock(&m->pt_mutex);
@ -71,7 +71,7 @@ void Event::wait() {
while(m->count==0) {
m->wait_count++;
pthread_cond_wait(&m->pt_cond, &m->pt_mutex);
pthread_cond_wait(&m->pt_cond, &m->pt_mutex);
m->wait_count--;
}
m->count--;

View File

@ -13,6 +13,11 @@
#endif // NV_OS
#if NV_USE_TELEMETRY
#include <telemetry.h>
extern HTELEMETRY tmContext;
#endif
using namespace nv;
@ -20,12 +25,17 @@ using namespace nv;
struct Mutex::Private {
CRITICAL_SECTION mutex;
const char * name;
};
Mutex::Mutex () : m(new Private)
Mutex::Mutex (const char * name) : m(new Private)
{
InitializeCriticalSection(&m->mutex);
m->name = name;
#if NV_USE_TELEMETRY
tmLockName(tmContext, this, name);
#endif
}
Mutex::~Mutex ()
@ -35,16 +45,44 @@ Mutex::~Mutex ()
void Mutex::lock()
{
#if NV_USE_TELEMETRY
TmU64 matcher;
tmTryLockEx(tmContext, &matcher, 100/*0.1 ms*/, __FILE__, __LINE__, this, "blocked");
#endif
EnterCriticalSection(&m->mutex);
#if NV_USE_TELEMETRY
tmEndTryLockEx(tmContext, matcher, __FILE__, __LINE__, this, TMLR_SUCCESS);
tmSetLockState(tmContext, this, TMLS_LOCKED, "acquired");
#endif
}
bool Mutex::tryLock()
{
#if NV_USE_TELEMETRY
TmU64 matcher;
tmTryLockEx(tmContext, &matcher, 100/*0.1 ms*/, __FILE__, __LINE__, this, "blocked");
if (TryEnterCriticalSection(&m->mutex) != 0) {
tmEndTryLockEx(tmContext, matcher, __FILE__, __LINE__, this, TMLR_SUCCESS);
tmSetLockState(tmContext, this, TMLS_LOCKED, "acquired");
return true;
}
else {
tmEndTryLockEx(tmContext, matcher, __FILE__, __LINE__, this, TMLR_FAILED);
return false;
}
#else
return TryEnterCriticalSection(&m->mutex) != 0;
#endif
}
void Mutex::unlock()
{
#if NV_USE_TELEMETRY
tmSetLockState(tmContext, this, TMLS_RELEASED, "released");
#endif
LeaveCriticalSection(&m->mutex);
}
@ -52,12 +90,14 @@ void Mutex::unlock()
struct Mutex::Private {
pthread_mutex_t mutex;
const char * name;
};
Mutex::Mutex () : m(new Private)
Mutex::Mutex (const char * name) : m(new Private)
{
int result = pthread_mutex_init(&m->mutex , NULL);
int result = pthread_mutex_init(&m->mutex, NULL);
m->name = name;
nvDebugCheck(result == 0);
}

View File

@ -15,7 +15,7 @@ namespace nv
{
NV_FORBID_COPY(Mutex);
public:
Mutex ();
Mutex (const char * name);
~Mutex ();
void lock();

View File

@ -38,7 +38,7 @@ ParallelFor::~ParallelFor() {
#endif
}
void ParallelFor::run(uint count) {
void ParallelFor::run(uint count, bool calling_thread_process_work /*=false*/) {
#if ENABLE_PARALLEL_FOR
storeRelease(&this->count, count);
@ -48,6 +48,10 @@ void ParallelFor::run(uint count) {
// Start threads.
pool->start(worker, this);
if (calling_thread_process_work) {
worker(this);
}
// Wait for all threads to complete.
pool->wait();

View File

@ -18,7 +18,7 @@ namespace nv
ParallelFor(ForTask * task, void * context);
~ParallelFor();
void run(uint count);
void run(uint count, bool calling_thread_process_work = false);
// Invariant:
ForTask * task;

View File

@ -9,6 +9,12 @@
#include <unistd.h> // usleep
#endif
#if NV_USE_TELEMETRY
#include <telemetry.h>
extern HTELEMETRY tmContext;
#endif
using namespace nv;
struct Thread::Private
@ -21,6 +27,7 @@ struct Thread::Private
ThreadFunc * func;
void * arg;
const char * name;
};
@ -32,6 +39,39 @@ unsigned long __stdcall threadFunc(void * arg) {
return 0;
}
// SetThreadName implementation from msdn:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx
const DWORD MS_VC_EXCEPTION=0x406D1388;
#pragma pack(push,8)
typedef struct tagTHREADNAME_INFO
{
DWORD dwType; // Must be 0x1000.
LPCSTR szName; // Pointer to name (in user addr space).
DWORD dwThreadID; // Thread ID (-1=caller thread).
DWORD dwFlags; // Reserved for future use, must be zero.
} THREADNAME_INFO;
#pragma pack(pop)
static void setThreadName(DWORD dwThreadID, const char* threadName)
{
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
info.dwThreadID = dwThreadID;
info.dwFlags = 0;
__try
{
RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info );
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
}
}
#elif NV_OS_USE_PTHREAD
extern "C" void * threadFunc(void * arg) {
@ -46,6 +86,13 @@ extern "C" void * threadFunc(void * arg) {
Thread::Thread() : p(new Private)
{
p->thread = 0;
p->name = NULL;
}
Thread::Thread(const char * const name) : p(new Private)
{
p->thread = 0;
p->name = name;
}
Thread::~Thread()
@ -59,9 +106,20 @@ void Thread::start(ThreadFunc * func, void * arg)
p->arg = arg;
#if NV_OS_WIN32
p->thread = CreateThread(NULL, 0, threadFunc, p.ptr(), 0, NULL);
DWORD threadId;
p->thread = CreateThread(NULL, 0, threadFunc, p.ptr(), 0, &threadId);
//p->thread = (HANDLE)_beginthreadex (0, 0, threadFunc, p.ptr(), 0, NULL); // @@ So that we can call CRT functions...
nvDebugCheck(p->thread != NULL);
setThreadName(threadId, p->name);
#if NV_USE_TELEMETRY
tmThreadName(tmContext, threadId, p->name);
#endif
#elif NV_OS_ORBIS
int ret = scePthreadCreate(&p->thread, NULL, threadFunc, p.ptr(), p->name ? p->name : "nv::Thread");
nvDebugCheck(ret == 0);
// use any non-system core
scePthreadSetaffinity(p->thread, 0x3F);
scePthreadSetprio(p->thread, (SCE_KERNEL_PRIO_FIFO_DEFAULT + SCE_KERNEL_PRIO_FIFO_HIGHEST) / 2);
#elif NV_OS_USE_PTHREAD
int result = pthread_create(&p->thread, NULL, threadFunc, p.ptr());
nvDebugCheck(result == 0);

View File

@ -17,6 +17,7 @@ namespace nv
NV_FORBID_COPY(Thread);
public:
Thread();
Thread(const char * const name);
~Thread();
void start(ThreadFunc * func, void * arg);

View File

@ -14,7 +14,7 @@
using namespace nv;
#if PROTECT_THREAD_POOL
Mutex s_pool_mutex;
Mutex s_pool_mutex("thread pool");
#endif
AutoPtr<ThreadPool> s_pool;

View File

@ -12,7 +12,7 @@
// The thread pool creates one worker thread for each physical core.
// The threads are idle waiting for their start events so that they do not consume any resources while inactive.
// The thread pool runs the same function in all worker threads, the idea is to use this as the foundation of a custom task scheduler.
// When the thread pool starts, the main thread continues running, but the common use case is to inmmediately wait of the termination events of the worker threads.
// When the thread pool starts, the main thread continues running, but the common use case is to inmmediately wait for the termination events of the worker threads.
// @@ The start and wait methods could probably be merged.
namespace nv {

View File

@ -72,3 +72,10 @@ uint nv::hardwareThreadCount() {
#endif
}
uint nv::threadId() {
#if NV_OS_WIN32
return GetCurrentThreadId();
#else
return 0; // @@
#endif
}

View File

@ -90,6 +90,8 @@ namespace nv
void shutWorkers();
void setWorkerFunction(void * func);
uint threadId();
} // nv namespace