diff --git a/include/bx/mutex.h b/include/bx/mutex.h index 777e577..eddcd03 100644 --- a/include/bx/mutex.h +++ b/include/bx/mutex.h @@ -7,21 +7,9 @@ #define BX_MUTEX_H_HEADER_GUARD #include "bx.h" -#include "cpu.h" -#include "os.h" -#include "sem.h" #if BX_CONFIG_SUPPORTS_THREADING -#if 0 \ - || BX_PLATFORM_ANDROID \ - || BX_PLATFORM_LINUX \ - || BX_PLATFORM_NACL \ - || BX_PLATFORM_IOS \ - || BX_PLATFORM_OSX -# include -#endif // - namespace bx { /// @@ -46,11 +34,7 @@ namespace bx void unlock(); private: -#if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT - CRITICAL_SECTION m_handle; -#else - pthread_mutex_t m_handle; -#endif // BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT + BX_ALIGN_DECL(16, uint8_t) m_internal[64]; }; /// diff --git a/include/bx/sem.h b/include/bx/sem.h index acc2359..41cff1b 100644 --- a/include/bx/sem.h +++ b/include/bx/sem.h @@ -10,21 +10,6 @@ #if BX_CONFIG_SUPPORTS_THREADING -#if BX_PLATFORM_POSIX -# include -# include -# include -# include -#elif BX_PLATFORM_XBOX360 || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT || BX_PLATFORM_XBOXONE -# include -# include -# if BX_PLATFORM_XBOXONE -# include -# endif // BX_PLATFORM_XBOXONE -#endif // BX_PLATFORM_ - -#include "mutex.h" - namespace bx { /// @@ -49,17 +34,7 @@ namespace bx bool wait(int32_t _msecs = -1); private: -#if BX_PLATFORM_POSIX -# if BX_CONFIG_SEMAPHORE_PTHREAD - pthread_mutex_t m_mutex; - pthread_cond_t m_cond; - int32_t m_count; -# else - sem_t m_handle; -# endif // BX_CONFIG_SEMAPHORE_PTHREAD -#elif BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT - HANDLE m_handle; -#endif // BX_PLATFORM_ + BX_ALIGN_DECL(16, uint8_t) m_internal[64]; }; } // namespace bx diff --git a/include/bx/spscqueue.h b/include/bx/spscqueue.h index 3f75496..6f4265f 100644 --- a/include/bx/spscqueue.h +++ b/include/bx/spscqueue.h @@ -9,6 +9,7 @@ #include "bx.h" #include "cpu.h" #include "mutex.h" +#include "sem.h" #include "uint32_t.h" #include diff --git a/include/bx/thread.h b/include/bx/thread.h index 9515236..266e62e 100644 --- a/include/bx/thread.h +++ b/include/bx/thread.h @@ -7,21 +7,6 @@ #define BX_THREAD_H_HEADER_GUARD #include "bx.h" - -#if BX_PLATFORM_POSIX -# include -# if defined(__FreeBSD__) -# include -# endif -# if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200) -# include -# endif // BX_PLATFORM_ -#elif BX_PLATFORM_WINRT -using namespace Platform; -using namespace Windows::Foundation; -using namespace Windows::System::Threading; -#endif // BX_PLATFORM_ - #include "sem.h" #if BX_CONFIG_SUPPORTS_THREADING @@ -62,16 +47,10 @@ namespace bx void setThreadName(const char* _name); private: + friend class ThreadInternal; int32_t entry(); -#if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT - static DWORD WINAPI threadFunc(LPVOID _arg); - HANDLE m_handle; - DWORD m_threadId; -#elif BX_PLATFORM_POSIX - static void* threadFunc(void* _arg); - pthread_t m_handle; -#endif // BX_PLATFORM_ + BX_ALIGN_DECL(16, uint8_t) m_internal[64]; ThreadFn m_fn; void* m_userData; @@ -98,17 +77,11 @@ namespace bx void set(void* _ptr); private: -#if BX_PLATFORM_WINDOWS - uint32_t m_id; -#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT) - pthread_key_t m_id; -#endif // BX_PLATFORM_* + BX_ALIGN_DECL(16, uint8_t) m_internal[64]; }; } // namespace bx #endif // BX_CONFIG_SUPPORTS_THREADING -#include "thread.inl" - #endif // BX_THREAD_H_HEADER_GUARD diff --git a/include/bx/thread.inl b/include/bx/thread.inl deleted file mode 100644 index 38fc49d..0000000 --- a/include/bx/thread.inl +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2010-2017 Branimir Karadzic. All rights reserved. - * License: https://github.com/bkaradzic/bx#license-bsd-2-clause - */ - -#ifndef BX_THREAD_H_HEADER_GUARD -# error "Must be included from bx/thread.h!" -#endif // BX_THREAD_H_HEADER_GUARD - -#if BX_CONFIG_SUPPORTS_THREADING - -namespace bx -{ -#if BX_PLATFORM_WINDOWS - inline TlsData::TlsData() - { - m_id = TlsAlloc(); - BX_CHECK(TLS_OUT_OF_INDEXES != m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() ); - } - - inline TlsData::~TlsData() - { - BOOL result = TlsFree(m_id); - BX_CHECK(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result); - } - - inline void* TlsData::get() const - { - return TlsGetValue(m_id); - } - - inline void TlsData::set(void* _ptr) - { - TlsSetValue(m_id, _ptr); - } - -#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT) - - inline TlsData::TlsData() - { - int result = pthread_key_create(&m_id, NULL); - BX_CHECK(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result); - } - - inline TlsData::~TlsData() - { - int result = pthread_key_delete(m_id); - BX_CHECK(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result); - } - - inline void* TlsData::get() const - { - return pthread_getspecific(m_id); - } - - inline void TlsData::set(void* _ptr) - { - int result = pthread_setspecific(m_id, _ptr); - BX_CHECK(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result); - } -#endif // BX_PLATFORM_* - -} // namespace bx - -#endif // BX_CONFIG_SUPPORTS_THREADING diff --git a/src/mutex.cpp b/src/mutex.cpp index 00e5176..d0b61c3 100644 --- a/src/mutex.cpp +++ b/src/mutex.cpp @@ -7,17 +7,17 @@ #if BX_CONFIG_SUPPORTS_THREADING -#if 0 \ - || BX_PLATFORM_ANDROID \ - || BX_PLATFORM_LINUX \ - || BX_PLATFORM_NACL \ - || BX_PLATFORM_IOS \ +#if BX_PLATFORM_ANDROID \ + || BX_PLATFORM_LINUX \ + || BX_PLATFORM_NACL \ + || BX_PLATFORM_IOS \ || BX_PLATFORM_OSX # include -#elif 0 \ - || BX_PLATFORM_WINDOWS \ - || BX_PLATFORM_WINRT \ - || BX_PLATFORM_XBOX360 +#elif BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE +# include # include #endif // BX_PLATFORM_ @@ -50,7 +50,7 @@ namespace bx InitializeCriticalSectionEx(_mutex, 4000, 0); // docs recommend 4000 spincount as sane default #else InitializeCriticalSection(_mutex); -#endif +#endif // BX_PLATFORM_ return 0; } @@ -63,28 +63,36 @@ namespace bx Mutex::Mutex() { + BX_STATIC_ASSERT(sizeof(pthread_mutex_t) <= sizeof(m_internal) ); + pthread_mutexattr_t attr; + #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT #else pthread_mutexattr_init(&attr); pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); -#endif // BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_WINRT - pthread_mutex_init(&m_handle, &attr); +#endif // BX_PLATFORM_ + + pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; + pthread_mutex_init(handle, &attr); } Mutex::~Mutex() { - pthread_mutex_destroy(&m_handle); + pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; + pthread_mutex_destroy(handle); } void Mutex::lock() { - pthread_mutex_lock(&m_handle); + pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; + pthread_mutex_lock(handle); } void Mutex::unlock() { - pthread_mutex_unlock(&m_handle); + pthread_mutex_t* handle = (pthread_mutex_t*)m_internal; + pthread_mutex_unlock(handle); } } // namespace bx diff --git a/src/sem.cpp b/src/sem.cpp index 2d3ca15..69bc3cb 100644 --- a/src/sem.cpp +++ b/src/sem.cpp @@ -9,29 +9,56 @@ #if BX_PLATFORM_POSIX # include +# include # include # include -# include -#elif BX_PLATFORM_XBOXONE -# include -#elif BX_PLATFORM_XBOX360 || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT +#elif BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE # include # include +# if BX_PLATFORM_XBOXONE +# include +# endif // BX_PLATFORM_XBOXONE #endif // BX_PLATFORM_ namespace bx { + struct SemaphoreInternal + { +#if BX_PLATFORM_POSIX +# if BX_CONFIG_SEMAPHORE_PTHREAD + pthread_mutex_t m_mutex; + pthread_cond_t m_cond; + int32_t m_count; +# else + sem_t m_handle; +# endif // BX_CONFIG_SEMAPHORE_PTHREAD +#elif BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE + HANDLE m_handle; +#endif // BX_PLATFORM_ + }; + #if BX_PLATFORM_POSIX # if BX_CONFIG_SEMAPHORE_PTHREAD Semaphore::Semaphore() : m_count(0) { + BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) ); + + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + int result; - result = pthread_mutex_init(&m_mutex, NULL); + + result = pthread_mutex_init(&si->m_mutex, NULL); BX_CHECK(0 == result, "pthread_mutex_init %d", result); - result = pthread_cond_init(&m_cond, NULL); + result = pthread_cond_init(&si->m_cond, NULL); BX_CHECK(0 == result, "pthread_cond_init %d", result); BX_UNUSED(result); @@ -39,11 +66,13 @@ namespace bx Semaphore::~Semaphore() { + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + int result; - result = pthread_cond_destroy(&m_cond); + result = pthread_cond_destroy(&si->m_cond); BX_CHECK(0 == result, "pthread_cond_destroy %d", result); - result = pthread_mutex_destroy(&m_mutex); + result = pthread_mutex_destroy(&si->m_mutex); BX_CHECK(0 == result, "pthread_mutex_destroy %d", result); BX_UNUSED(result); @@ -51,18 +80,20 @@ namespace bx void Semaphore::post(uint32_t _count) { - int result = pthread_mutex_lock(&m_mutex); + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + + int result = pthread_mutex_lock(&si->m_mutex); BX_CHECK(0 == result, "pthread_mutex_lock %d", result); for (uint32_t ii = 0; ii < _count; ++ii) { - result = pthread_cond_signal(&m_cond); + result = pthread_cond_signal(&si->m_cond); BX_CHECK(0 == result, "pthread_cond_signal %d", result); } m_count += _count; - result = pthread_mutex_unlock(&m_mutex); + result = pthread_mutex_unlock(&si->m_mutex); BX_CHECK(0 == result, "pthread_mutex_unlock %d", result); BX_UNUSED(result); @@ -70,7 +101,9 @@ namespace bx bool Semaphore::wait(int32_t _msecs) { - int result = pthread_mutex_lock(&m_mutex); + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + + int result = pthread_mutex_lock(&si->m_mutex); BX_CHECK(0 == result, "pthread_mutex_lock %d", result); # if BX_PLATFORM_NACL || BX_PLATFORM_OSX @@ -79,7 +112,7 @@ namespace bx while (0 == result && 0 >= m_count) { - result = pthread_cond_wait(&m_cond, &m_mutex); + result = pthread_cond_wait(&si->m_cond, &si->m_mutex); } # elif BX_PLATFORM_IOS if (-1 == _msecs) @@ -87,7 +120,7 @@ namespace bx while (0 == result && 0 >= m_count) { - result = pthread_cond_wait(&m_cond, &m_mutex); + result = pthread_cond_wait(&si->m_cond, &si->m_mutex); } } else @@ -99,7 +132,7 @@ namespace bx while (0 == result && 0 >= m_count) { - result = pthread_cond_timedwait_relative_np(&m_cond, &m_mutex, &ts); + result = pthread_cond_timedwait_relative_np(&si->m_cond, &si->m_mutex, &ts); } } # else @@ -111,7 +144,7 @@ namespace bx while (0 == result && 0 >= m_count) { - result = pthread_cond_timedwait(&m_cond, &m_mutex, &ts); + result = pthread_cond_timedwait(&si->m_cond, &si->m_mutex, &ts); } # endif // BX_PLATFORM_NACL || BX_PLATFORM_OSX bool ok = 0 == result; @@ -121,7 +154,7 @@ namespace bx --m_count; } - result = pthread_mutex_unlock(&m_mutex); + result = pthread_mutex_unlock(&si->m_mutex); BX_CHECK(0 == result, "pthread_mutex_unlock %d", result); BX_UNUSED(result); @@ -133,24 +166,32 @@ namespace bx Semaphore::Semaphore() { - int32_t result = sem_init(&m_handle, 0, 0); + BX_STATIC_ASSERT(sizeof(SemaphoreInternal) <= sizeof(m_internal) ); + + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + + int32_t result = sem_init(&si->m_handle, 0, 0); BX_CHECK(0 == result, "sem_init failed. errno %d", errno); BX_UNUSED(result); } Semaphore::~Semaphore() { - int32_t result = sem_destroy(&m_handle); + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + + int32_t result = sem_destroy(&si->m_handle); BX_CHECK(0 == result, "sem_destroy failed. errno %d", errno); BX_UNUSED(result); } void Semaphore::post(uint32_t _count) { + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + int32_t result; for (uint32_t ii = 0; ii < _count; ++ii) { - result = sem_post(&m_handle); + result = sem_post(&si->m_handle); BX_CHECK(0 == result, "sem_post failed. errno %d", errno); } BX_UNUSED(result); @@ -158,16 +199,18 @@ namespace bx bool Semaphore::wait(int32_t _msecs) { + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + # if BX_PLATFORM_NACL || BX_PLATFORM_OSX BX_CHECK(-1 == _msecs, "NaCl and OSX don't support sem_timedwait at this moment."); BX_UNUSED(_msecs); - return 0 == sem_wait(&m_handle); + return 0 == sem_wait(&si->m_handle); # else if (0 > _msecs) { int32_t result; do { - result = sem_wait(&m_handle); + result = sem_wait(&si->m_handle); } // keep waiting when interrupted by a signal handler... while (-1 == result && EINTR == errno); BX_CHECK(0 == result, "sem_wait failed. errno %d", errno); @@ -178,40 +221,51 @@ namespace bx clock_gettime(CLOCK_REALTIME, &ts); ts.tv_sec += _msecs/1000; ts.tv_nsec += (_msecs%1000)*1000; - return 0 == sem_timedwait(&m_handle, &ts); + return 0 == sem_timedwait(&si->m_handle, &ts); # endif // BX_PLATFORM_ } # endif // BX_CONFIG_SEMAPHORE_PTHREAD -#elif BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT +#elif BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE Semaphore::Semaphore() { + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + #if BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT - m_handle = CreateSemaphoreExW(NULL, 0, LONG_MAX, NULL, 0, SEMAPHORE_ALL_ACCESS); + si->m_handle = CreateSemaphoreExW(NULL, 0, LONG_MAX, NULL, 0, SEMAPHORE_ALL_ACCESS); #else - m_handle = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL); + si->m_handle = CreateSemaphoreA(NULL, 0, LONG_MAX, NULL); #endif - BX_CHECK(NULL != m_handle, "Failed to create Semaphore!"); + BX_CHECK(NULL != si->m_handle, "Failed to create Semaphore!"); } Semaphore::~Semaphore() { - CloseHandle(m_handle); + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + + CloseHandle(si->m_handle); } void Semaphore::post(uint32_t _count) { - ReleaseSemaphore(m_handle, _count, NULL); + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + + ReleaseSemaphore(si->m_handle, _count, NULL); } bool Semaphore::wait(int32_t _msecs) { + SemaphoreInternal* si = (SemaphoreInternal*)m_internal; + DWORD milliseconds = (0 > _msecs) ? INFINITE : _msecs; #if BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT - return WAIT_OBJECT_0 == WaitForSingleObjectEx(m_handle, milliseconds, FALSE); + return WAIT_OBJECT_0 == WaitForSingleObjectEx(si->m_handle, milliseconds, FALSE); #else - return WAIT_OBJECT_0 == WaitForSingleObject(m_handle, milliseconds); + return WAIT_OBJECT_0 == WaitForSingleObject(si->m_handle, milliseconds); #endif } #endif // BX_PLATFORM_ diff --git a/src/thread.cpp b/src/thread.cpp index fea7e8b..0937405 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -5,24 +5,92 @@ #include +#if BX_PLATFORM_ANDROID \ + || BX_PLATFORM_LINUX \ + || BX_PLATFORM_NACL \ + || BX_PLATFORM_IOS \ + || BX_PLATFORM_OSX +# include +# if defined(__FreeBSD__) +# include +# endif +# if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200) +# include +# endif // BX_PLATFORM_ +#elif BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE +# include +# include +# include +# if BX_PLATFORM_WINRT +using namespace Platform; +using namespace Windows::Foundation; +using namespace Windows::System::Threading; +# endif // BX_PLATFORM_WINRT +#endif // BX_PLATFORM_ + #if BX_CONFIG_SUPPORTS_THREADING namespace bx { - Thread::Thread() -#if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT - : m_handle(INVALID_HANDLE_VALUE) - , m_threadId(UINT32_MAX) + struct ThreadInternal + { +#if BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE + static DWORD WINAPI threadFunc(LPVOID _arg); + HANDLE m_handle; + DWORD m_threadId; #elif BX_PLATFORM_POSIX - : m_handle(0) + static void* threadFunc(void* _arg); + pthread_t m_handle; #endif // BX_PLATFORM_ - , m_fn(NULL) + }; + +#if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT + DWORD WINAPI ThreadInternal::threadFunc(LPVOID _arg) + { + Thread* thread = (Thread*)_arg; + int32_t result = thread->entry(); + return result; + } +#else + void* ThreadInternal::threadFunc(void* _arg) + { + Thread* thread = (Thread*)_arg; + union + { + void* ptr; + int32_t i; + } cast; + cast.i = thread->entry(); + return cast.ptr; + } +#endif // BX_PLATFORM_ + + Thread::Thread() + : m_fn(NULL) , m_userData(NULL) , m_stackSize(0) , m_exitCode(0 /*EXIT_SUCCESS*/) , m_running(false) - { - } + { + BX_STATIC_ASSERT(sizeof(ThreadInternal) <= sizeof(m_internal) ); + + ThreadInternal* ti = (ThreadInternal*)m_internal; +#if BX_PLATFORM_WINDOWS \ + || BX_PLATFORM_WINRT \ + || BX_PLATFORM_XBOX360 \ + || BX_PLATFORM_XBOXONE + ti->m_handle = INVALID_HANDLE_VALUE; + ti->m_threadId = UINT32_MAX; +#elif BX_PLATFORM_POSIX + ti->m_handle = 0; +#endif // BX_PLATFORM_ + } Thread::~Thread() { @@ -41,21 +109,24 @@ namespace bx m_stackSize = _stackSize; m_running = true; + ThreadInternal* ti = (ThreadInternal*)m_internal; #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE - m_handle = ::CreateThread(NULL + ti->m_handle = ::CreateThread(NULL , m_stackSize - , (LPTHREAD_START_ROUTINE)threadFunc + , (LPTHREAD_START_ROUTINE)ti->threadFunc , this , 0 , NULL ); #elif BX_PLATFORM_WINRT - m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); + ti->m_handle = CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS); auto workItemHandler = ref new WorkItemHandler([=](IAsyncAction^) - { - m_exitCode = threadFunc(this); - SetEvent(m_handle); - }, CallbackContext::Any); + { + m_exitCode = ti->threadFunc(this); + SetEvent(ti->m_handle); + } + , CallbackContext::Any + ); ThreadPool::RunAsync(workItemHandler, WorkItemPriority::Normal, WorkItemOptions::TimeSliced); #elif BX_PLATFORM_POSIX @@ -72,12 +143,7 @@ namespace bx BX_CHECK(0 == result, "pthread_attr_setstacksize failed! %d", result); } - // sched_param sched; - // sched.sched_priority = 0; - // result = pthread_attr_setschedparam(&attr, &sched); - // BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result); - - result = pthread_create(&m_handle, &attr, &threadFunc, this); + result = pthread_create(&ti->m_handle, &attr, &ti->threadFunc, this); BX_CHECK(0 == result, "pthread_attr_setschedparam failed! %d", result); #else # error "Not implemented!" @@ -94,25 +160,27 @@ namespace bx void Thread::shutdown() { BX_CHECK(m_running, "Not running!"); + ThreadInternal* ti = (ThreadInternal*)m_internal; #if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 - WaitForSingleObject(m_handle, INFINITE); - GetExitCodeThread(m_handle, (DWORD*)&m_exitCode); - CloseHandle(m_handle); - m_handle = INVALID_HANDLE_VALUE; + WaitForSingleObject(ti->m_handle, INFINITE); + GetExitCodeThread(ti->m_handle, (DWORD*)&m_exitCode); + CloseHandle(ti->m_handle); + ti->m_handle = INVALID_HANDLE_VALUE; #elif BX_PLATFORM_WINRT - WaitForSingleObjectEx(m_handle, INFINITE, FALSE); - CloseHandle(m_handle); - m_handle = INVALID_HANDLE_VALUE; + WaitForSingleObjectEx(ti->m_handle, INFINITE, FALSE); + CloseHandle(ti->m_handle); + ti->m_handle = INVALID_HANDLE_VALUE; #elif BX_PLATFORM_POSIX union { void* ptr; int32_t i; } cast; - pthread_join(m_handle, &cast.ptr); + pthread_join(ti->m_handle, &cast.ptr); m_exitCode = cast.i; - m_handle = 0; + ti->m_handle = 0; #endif // BX_PLATFORM_ + m_running = false; } @@ -128,17 +196,19 @@ namespace bx void Thread::setThreadName(const char* _name) { + ThreadInternal* ti = (ThreadInternal*)m_internal; + BX_UNUSED(ti); #if BX_PLATFORM_OSX || BX_PLATFORM_IOS pthread_setname_np(_name); #elif (BX_CRT_GLIBC >= 21200) && ! BX_PLATFORM_HURD - pthread_setname_np(m_handle, _name); + pthread_setname_np(ti->m_handle, _name); #elif BX_PLATFORM_LINUX prctl(PR_SET_NAME,_name, 0, 0, 0); #elif BX_PLATFORM_BSD # ifdef __NetBSD__ - pthread_setname_np(m_handle, "%s", (void*)_name); + pthread_setname_np(ti->m_handle, "%s", (void*)_name); # else - pthread_set_name_np(m_handle, _name); + pthread_set_name_np(ti->m_handle, _name); # endif // __NetBSD__ #elif BX_PLATFORM_WINDOWS && BX_COMPILER_MSVC # pragma pack(push, 8) @@ -153,7 +223,7 @@ namespace bx ThreadName tn; tn.type = 0x1000; tn.name = _name; - tn.id = m_threadId; + tn.id = ti->m_threadId; tn.flags = 0; __try @@ -175,33 +245,83 @@ namespace bx int32_t Thread::entry() { #if BX_PLATFORM_WINDOWS - m_threadId = ::GetCurrentThreadId(); + ThreadInternal* ti = (ThreadInternal*)m_internal; + ti->m_threadId = ::GetCurrentThreadId(); #endif // BX_PLATFORM_WINDOWS m_sem.post(); return m_fn(m_userData); } -#if BX_PLATFORM_WINDOWS || BX_PLATFORM_XBOX360 || BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT - DWORD WINAPI Thread::threadFunc(LPVOID _arg) + struct TlsDataInternal { - Thread* thread = (Thread*)_arg; - int32_t result = thread->entry(); - return result; - } -#else - void* Thread::threadFunc(void* _arg) +#if BX_PLATFORM_WINDOWS + uint32_t m_id; +#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT) + pthread_key_t m_id; +#endif // BX_PLATFORM_* + }; + +#if BX_PLATFORM_WINDOWS + TlsData::TlsData() { - Thread* thread = (Thread*)_arg; - union - { - void* ptr; - int32_t i; - } cast; - cast.i = thread->entry(); - return cast.ptr; + BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) ); + + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + ti->m_id = TlsAlloc(); + BX_CHECK(TLS_OUT_OF_INDEXES != ti->m_id, "Failed to allocated TLS index (err: 0x%08x).", GetLastError() ); } -#endif // BX_PLATFORM_ + + TlsData::~TlsData() + { + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + BOOL result = TlsFree(ti->m_id); + BX_CHECK(0 != result, "Failed to free TLS index (err: 0x%08x).", GetLastError() ); BX_UNUSED(result); + } + + void* TlsData::get() const + { + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + return TlsGetValue(ti->m_id); + } + + void TlsData::set(void* _ptr) + { + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + TlsSetValue(ti->m_id, _ptr); + } + +#elif !(BX_PLATFORM_XBOXONE || BX_PLATFORM_WINRT) + + TlsData::TlsData() + { + BX_STATIC_ASSERT(sizeof(TlsDataInternal) <= sizeof(m_internal) ); + + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + int result = pthread_key_create(&ti->m_id, NULL); + BX_CHECK(0 == result, "pthread_key_create failed %d.", result); BX_UNUSED(result); + } + + TlsData::~TlsData() + { + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + int result = pthread_key_delete(ti->m_id); + BX_CHECK(0 == result, "pthread_key_delete failed %d.", result); BX_UNUSED(result); + } + + void* TlsData::get() const + { + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + return pthread_getspecific(ti->m_id); + } + + void TlsData::set(void* _ptr) + { + TlsDataInternal* ti = (TlsDataInternal*)m_internal; + int result = pthread_setspecific(ti->m_id, _ptr); + BX_CHECK(0 == result, "pthread_setspecific failed %d.", result); BX_UNUSED(result); + } +#endif // BX_PLATFORM_* } // namespace bx