Bladeren bron

Moved mutex/semaphore/thread implementation details to .cpp file.

Branimir Karadžić 8 jaren geleden
bovenliggende
commit
f7abed893f
8 gewijzigde bestanden met toevoegingen van 285 en 235 verwijderingen
  1. 1 17
      include/bx/mutex.h
  2. 1 26
      include/bx/sem.h
  3. 1 0
      include/bx/spscqueue.h
  4. 3 30
      include/bx/thread.h
  5. 0 65
      include/bx/thread.inl
  6. 23 15
      src/mutex.cpp
  7. 85 31
      src/sem.cpp
  8. 171 51
      src/thread.cpp

+ 1 - 17
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 <pthread.h>
-#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];
 	};
 
 	///

+ 1 - 26
include/bx/sem.h

@@ -10,21 +10,6 @@
 
 #if BX_CONFIG_SUPPORTS_THREADING
 
-#if BX_PLATFORM_POSIX
-#	include <errno.h>
-#	include <semaphore.h>
-#	include <time.h>
-#	include <pthread.h>
-#elif BX_PLATFORM_XBOX360 || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT || BX_PLATFORM_XBOXONE
-#	include <windows.h>
-#	include <limits.h>
-#	if BX_PLATFORM_XBOXONE
-#		include <synchapi.h>
-#	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

+ 1 - 0
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 <list>

+ 3 - 30
include/bx/thread.h

@@ -7,21 +7,6 @@
 #define BX_THREAD_H_HEADER_GUARD
 
 #include "bx.h"
-
-#if BX_PLATFORM_POSIX
-#	include <pthread.h>
-#	if defined(__FreeBSD__)
-#		include <pthread_np.h>
-#	endif
-#	if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
-#		include <sys/prctl.h>
-#	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

+ 0 - 65
include/bx/thread.inl

@@ -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

+ 23 - 15
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 <pthread.h>
-#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 <windows.h>
 #	include <errno.h>
 #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

+ 85 - 31
src/sem.cpp

@@ -9,29 +9,56 @@
 
 #if BX_PLATFORM_POSIX
 #	include <errno.h>
+#	include <pthread.h>
 #	include <semaphore.h>
 #	include <time.h>
-#	include <pthread.h>
-#elif BX_PLATFORM_XBOXONE
-#	include <synchapi.h>
-#elif BX_PLATFORM_XBOX360 || BX_PLATFORM_WINDOWS || BX_PLATFORM_WINRT
+#elif  BX_PLATFORM_WINDOWS \
+	|| BX_PLATFORM_WINRT   \
+	|| BX_PLATFORM_XBOX360 \
+	|| BX_PLATFORM_XBOXONE
 #	include <windows.h>
 #	include <limits.h>
+#	if BX_PLATFORM_XBOXONE
+#		include <synchapi.h>
+#	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_

+ 171 - 51
src/thread.cpp

@@ -5,24 +5,92 @@
 
 #include <bx/thread.h>
 
+#if    BX_PLATFORM_ANDROID \
+	|| BX_PLATFORM_LINUX   \
+	|| BX_PLATFORM_NACL    \
+	|| BX_PLATFORM_IOS     \
+	|| BX_PLATFORM_OSX
+#	include <pthread.h>
+#	if defined(__FreeBSD__)
+#		include <pthread_np.h>
+#	endif
+#	if BX_PLATFORM_LINUX && (BX_CRT_GLIBC < 21200)
+#		include <sys/prctl.h>
+#	endif // BX_PLATFORM_
+#elif  BX_PLATFORM_WINDOWS \
+	|| BX_PLATFORM_WINRT   \
+	|| BX_PLATFORM_XBOX360 \
+	|| BX_PLATFORM_XBOXONE
+#	include <windows.h>
+#	include <limits.h>
+#	include <errno.h>
+#	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_
+	};
+
+#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_
-		, m_fn(NULL)
+
+	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;
+#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()
+	{
+		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() );
 	}
-#else
-	void* Thread::threadFunc(void* _arg)
+
+	TlsData::~TlsData()
 	{
-		Thread* thread = (Thread*)_arg;
-		union
-		{
-			void* ptr;
-			int32_t i;
-		} cast;
-		cast.i = thread->entry();
-		return cast.ptr;
+		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);
 	}
-#endif // BX_PLATFORM_
+
+	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