2011-09-27 17:48:46 +00:00
|
|
|
// This code is in the public domain -- castano@gmail.com
|
|
|
|
|
|
|
|
#include "Thread.h"
|
|
|
|
|
|
|
|
#if NV_OS_WIN32
|
2011-09-27 18:12:32 +00:00
|
|
|
#include "Win32.h"
|
2011-09-27 17:48:46 +00:00
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
#include <pthread.h>
|
|
|
|
#include <unistd.h> // usleep
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
using namespace nv;
|
|
|
|
|
|
|
|
struct Thread::Private
|
|
|
|
{
|
|
|
|
#if NV_OS_WIN32
|
2011-09-27 18:12:32 +00:00
|
|
|
HANDLE thread;
|
2011-09-27 17:48:46 +00:00
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
pthread_t thread;
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
ThreadFunc * func;
|
|
|
|
void * arg;
|
|
|
|
};
|
|
|
|
|
2011-09-27 18:12:32 +00:00
|
|
|
|
2011-09-27 17:48:46 +00:00
|
|
|
#if NV_OS_WIN32
|
|
|
|
|
|
|
|
unsigned long __stdcall threadFunc(void * arg) {
|
|
|
|
Thread * thread = (Thread *)arg;
|
|
|
|
thread->func(thread->arg);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
|
2011-09-27 17:48:46 +00:00
|
|
|
extern "C" void * threadFunc(void * arg) {
|
|
|
|
Thread * thread = (Thread *)arg;
|
2011-09-27 18:12:32 +00:00
|
|
|
thread->func(thread->arg);
|
|
|
|
pthread_exit(0);
|
2011-09-27 17:48:46 +00:00
|
|
|
}
|
2011-09-27 18:12:32 +00:00
|
|
|
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
Thread::Thread() : p(new Private)
|
|
|
|
{
|
|
|
|
p->thread = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
Thread::~Thread()
|
|
|
|
{
|
2011-09-27 18:12:32 +00:00
|
|
|
nvDebugCheck(p->thread == 0);
|
2011-09-27 17:48:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Thread::start(ThreadFunc * func, void * arg)
|
|
|
|
{
|
|
|
|
this->func = func;
|
|
|
|
this->arg = arg;
|
|
|
|
|
|
|
|
#if NV_OS_WIN32
|
2011-09-27 18:12:32 +00:00
|
|
|
p->thread = CreateThread(NULL, 0, threadFunc, this, 0, NULL);
|
|
|
|
//p->thread = (HANDLE)_beginthreadex (0, 0, threadFunc, this, 0, NULL); // @@ So that we can call CRT functions...
|
|
|
|
nvDebugCheck(p->thread != NULL);
|
2011-09-27 17:48:46 +00:00
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
int result = pthread_create(&p->thread, NULL, threadFunc, this);
|
|
|
|
nvDebugCheck(result == 0);
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Thread::wait()
|
|
|
|
{
|
|
|
|
#if NV_OS_WIN32
|
|
|
|
DWORD status = WaitForSingleObject (p->thread, INFINITE);
|
|
|
|
nvCheck (status == WAIT_OBJECT_0);
|
|
|
|
BOOL ok = CloseHandle (p->thread);
|
|
|
|
p->thread = NULL;
|
|
|
|
nvCheck (ok);
|
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
int result = pthread_join(p->thread, NULL);
|
2011-09-27 17:48:46 +00:00
|
|
|
p->thread = 0;
|
2011-09-27 18:12:32 +00:00
|
|
|
nvDebugCheck(result == 0);
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Thread::isRunning () const
|
|
|
|
{
|
|
|
|
#if NV_OS_WIN32
|
2011-09-27 18:12:32 +00:00
|
|
|
return p->thread != NULL;
|
2011-09-27 17:48:46 +00:00
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
return p->thread != 0;
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ void Thread::spinWait(uint count)
|
|
|
|
{
|
2011-09-27 18:12:32 +00:00
|
|
|
for (uint i = 0; i < count; i++) {}
|
2011-09-27 17:48:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ void Thread::yield()
|
|
|
|
{
|
|
|
|
#if NV_OS_WIN32
|
2011-09-27 18:12:32 +00:00
|
|
|
SwitchToThread();
|
2011-09-27 17:48:46 +00:00
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
int result = sched_yield();
|
|
|
|
nvDebugCheck(result == 0);
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ void Thread::sleep(uint ms)
|
|
|
|
{
|
|
|
|
#if NV_OS_WIN32
|
2011-09-27 18:12:32 +00:00
|
|
|
Sleep(ms);
|
2011-09-27 17:48:46 +00:00
|
|
|
#elif NV_OS_UNIX
|
2011-09-27 18:12:32 +00:00
|
|
|
usleep(1000 * ms);
|
2011-09-27 17:48:46 +00:00
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static*/ void Thread::wait(Thread * threads, uint count)
|
|
|
|
{
|
|
|
|
/*#if NV_OS_WIN32
|
|
|
|
// @@ Is there any advantage in doing this?
|
|
|
|
nvDebugCheck(count < MAXIMUM_WAIT_OBJECTS);
|
|
|
|
|
|
|
|
HANDLE * handles = new HANDLE[count];
|
|
|
|
for (uint i = 0; i < count; i++) {
|
|
|
|
handles[i] = threads->p->thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD result = WaitForMultipleObjects(count, handles, TRUE, INFINITE);
|
|
|
|
|
|
|
|
|
|
|
|
delete [] handles;
|
|
|
|
#else*/
|
|
|
|
for (uint i = 0; i < count; i++) {
|
|
|
|
threads[i].wait();
|
|
|
|
}
|
|
|
|
//#endif
|
2011-09-27 18:12:32 +00:00
|
|
|
}
|
|
|
|
|