diff --git a/.gitignore b/.gitignore index 93fae63..4d4ebf3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ ctags /build/ build.bat + +# vim temporaries +*.swp +*.un~ +*.~ diff --git a/include/eathread/eathread_callstack.h b/include/eathread/eathread_callstack.h index ebca218..f873797 100644 --- a/include/eathread/eathread_callstack.h +++ b/include/eathread/eathread_callstack.h @@ -323,7 +323,7 @@ namespace EA #endif - #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_SONY) + #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_SONY) || defined(EA_PLATFORM_MINGW) // GetPthreadStackInfo // // With some implementations of pthread, the stack base is returned by pthread as NULL if it's the main thread, diff --git a/include/eathread/eathread_futex.h b/include/eathread/eathread_futex.h index bd68e5c..8050535 100644 --- a/include/eathread/eathread_futex.h +++ b/include/eathread/eathread_futex.h @@ -114,6 +114,18 @@ #define _Must_inspect_result_ #endif + #ifndef _Out_ + #define _Out_ + #endif + + #ifndef _Inout_ + #define _Inout_ + #endif + + #ifndef _In_ + #define _In_ + #endif + struct _RTL_CRITICAL_SECTION; __declspec(dllimport) _Must_inspect_result_ int __stdcall InitializeCriticalSectionAndSpinCount(_Out_ _RTL_CRITICAL_SECTION* pCriticalSection, _In_ unsigned long dwSpinCount); __declspec(dllimport) void __stdcall InitializeCriticalSection(_Out_ _RTL_CRITICAL_SECTION* pCriticalSection); diff --git a/include/eathread/internal/config.h b/include/eathread/internal/config.h index cf0f050..f703267 100644 --- a/include/eathread/internal/config.h +++ b/include/eathread/internal/config.h @@ -114,7 +114,7 @@ EA_RESTORE_VC_WARNING() // Defined as 0 or 1 // #ifndef EA_POSIX_THREADS_AVAILABLE - #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_APPLE) + #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_MINGW) #define EA_POSIX_THREADS_AVAILABLE 1 #elif defined(EA_PLATFORM_SONY) #define EA_POSIX_THREADS_AVAILABLE 0 // POSIX threading API is present but use is discouraged by Sony. They want shipping code to use their scePthreads* API. @@ -484,9 +484,9 @@ EA_RESTORE_VC_WARNING() #define EATHREAD_GETCALLSTACK_SUPPORTED 1 #elif defined(EA_PLATFORM_WINDOWS_PHONE) && defined(EA_PROCESSOR_ARM) #define EATHREAD_GETCALLSTACK_SUPPORTED 0 - #elif defined(EA_PLATFORM_MICROSOFT) + #elif defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_MINGW) #define EATHREAD_GETCALLSTACK_SUPPORTED 1 - #elif defined(EA_PLATFORM_LINUX) + #elif defined(EA_PLATFORM_LINUX) && !defined(EA_PLATFORM_CYGWIN) #define EATHREAD_GETCALLSTACK_SUPPORTED 1 #elif defined(EA_PLATFORM_OSX) #define EATHREAD_GETCALLSTACK_SUPPORTED 1 @@ -537,7 +537,7 @@ EA_RESTORE_VC_WARNING() #elif defined(EA_PLATFORM_SONY) #define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 1 #elif defined(EA_USE_CPP11_CONCURRENCY) && EA_USE_CPP11_CONCURRENCY - // CPP11 doesn't not provided a mechanism to set thread affinities. + // CPP11 doesn't provide a mechanism to set thread affinities. #define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 0 #elif defined(EA_PLATFORM_ANDROID) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_UNIX) #define EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED 0 diff --git a/source/eathread_callstack.cpp b/source/eathread_callstack.cpp index 0095a2f..50ec4c9 100644 --- a/source/eathread_callstack.cpp +++ b/source/eathread_callstack.cpp @@ -4,9 +4,9 @@ #include -#if defined(EA_PLATFORM_WIN32) && EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP) +#if defined(EA_PLATFORM_WIN32) && EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP) && !defined(EA_PLATFORM_MINGW) #include "pc/eathread_callstack_win32.cpp" -#elif defined(EA_PLATFORM_MICROSOFT) && defined(EA_PROCESSOR_X86_64) +#elif defined(EA_PLATFORM_MICROSOFT) && defined(EA_PROCESSOR_X86_64) && !defined(EA_PLATFORM_MINGW) #include "pc/eathread_callstack_win64.cpp" #elif defined(EA_PLATFORM_SONY) #include "kettle/eathread_callstack_kettle.cpp" diff --git a/source/pc/eathread_thread_pc.cpp b/source/pc/eathread_thread_pc.cpp index c458a06..964515a 100644 --- a/source/pc/eathread_thread_pc.cpp +++ b/source/pc/eathread_thread_pc.cpp @@ -85,7 +85,7 @@ EA_DISABLE_VC_WARNING(6312 6322) EAThreadGlobalVars() {} EAThreadGlobalVars(const EAThreadGlobalVars&) {} - EAThreadGlobalVars& operator=(const EAThreadGlobalVars&) {} + EAThreadGlobalVars& operator=(const EAThreadGlobalVars&) { return *this; } }; EATHREAD_GLOBALVARS_CREATE_INSTANCE; diff --git a/source/unix/eathread_callstack_glibc.cpp b/source/unix/eathread_callstack_glibc.cpp index a8eb9c0..81475d9 100644 --- a/source/unix/eathread_callstack_glibc.cpp +++ b/source/unix/eathread_callstack_glibc.cpp @@ -228,7 +228,7 @@ EATHREADLIB_API void SetStackBase(void* pStackBase) // EATHREADLIB_API void* GetStackBase() { - #if defined(EA_PLATFORM_UNIX) + #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_MINGW) void* pBase; if(GetPthreadStackInfo(&pBase, NULL)) return pBase; @@ -246,7 +246,7 @@ EATHREADLIB_API void* GetStackBase() // EATHREADLIB_API void* GetStackLimit() { - #if defined(EA_PLATFORM_UNIX) + #if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_MINGW) void* pLimit; if(GetPthreadStackInfo(NULL, &pLimit)) return pLimit; diff --git a/source/unix/eathread_pthread_stack_info.cpp b/source/unix/eathread_pthread_stack_info.cpp index 248f7f9..1f50fc7 100644 --- a/source/unix/eathread_pthread_stack_info.cpp +++ b/source/unix/eathread_pthread_stack_info.cpp @@ -10,12 +10,16 @@ #include #endif +#if defined(EA_PLATFORM_MICROSOFT) + #include +#endif + namespace EA { namespace Thread { -#if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_SONY) +#if defined(EA_PLATFORM_UNIX) || defined(EA_PLATFORM_APPLE) || defined(EA_PLATFORM_SONY) || defined(EA_PLATFORM_MINGW) // With some implementations of pthread, the stack base is returned by pthread as NULL if it's the main thread, // or possibly if it's a thread you created but didn't call pthread_attr_setstack manually to provide your // own stack. It's impossible for us to tell here whether will be such a NULL return value, so we just do what @@ -80,6 +84,25 @@ namespace Thread return returnValue; } + #elif defined(EA_PLATFORM_MINGW) + bool GetPthreadStackInfo(void** pBase, void** pLimit) + { + // Do the same as Windows x64 here, but also use the same strategy for 32 bit builds. + + // NtCurrentTeb is defined in as an inline call to __readgsqword + #if defined(EA_PROCESSOR_X86) + NT_TIB *pTIB = reinterpret_cast(NtCurrentTeb()); + #else // defined(EA_PROCESSOR_X64) + NT_TIB64* pTIB = reinterpret_cast(NtCurrentTeb()); + #endif + + if(pBase) + *pBase = reinterpret_cast(pTIB->StackBase); + if(pLimit) + *pLimit = reinterpret_cast(pTIB->StackLimit); + + return true; + } #else bool GetPthreadStackInfo(void** pBase, void** pLimit) { diff --git a/source/unix/eathread_thread_unix.cpp b/source/unix/eathread_thread_unix.cpp index 1e3c3b9..db024cd 100644 --- a/source/unix/eathread_thread_unix.cpp +++ b/source/unix/eathread_thread_unix.cpp @@ -58,7 +58,7 @@ namespace using namespace EA::Thread; #if defined(EA_PLATFORM_WINDOWS) - param.sched_priority = THREAD_PRIORITY_NORMAL + (nPriority - kThreadPriorityDefault); + param.sched_priority = THREAD_PRIORITY_NORMAL + (eathreadPriority - kThreadPriorityDefault); #elif defined(EA_PLATFORM_LINUX) && !defined(EA_PLATFORM_CYGWIN) // We are assuming Kernel 2.6 and later behaviour, but perhaps we should dynamically detect. @@ -177,7 +177,7 @@ namespace { EAT_ASSERT(pTP->mnStackSize != 0); - #if !defined(EA_PLATFORM_CYGWIN) // Some implementations of pthreads does not support pthread_attr_setstack. + #if !defined(EA_PLATFORM_CYGWIN) && !defined(EA_PLATFORM_MINGW) // Some implementations of pthreads does not support pthread_attr_setstack. #if defined(PTHREAD_STACK_MIN) EAT_ASSERT((pTP->mnStackSize >= PTHREAD_STACK_MIN)); #endif @@ -235,6 +235,26 @@ namespace pthread_setaffinity_np(pTDD->mThreadId, sizeof(cpus), &cpus); // We don't assert on the pthread_setaffinity_np return value, as that could be very noisy for some users. #endif + #elif defined(EA_PLATFORM_WINDOWS) + int nProcessorCount = EA::Thread::GetProcessorCount(); + + if(pTDD->mStartupProcessor < 0) + pTDD->mStartupProcessor = MAXIMUM_PROCESSORS; + else + { + if(pTDD->mStartupProcessor >= nProcessorCount) + pTDD->mStartupProcessor %= nProcessorCount; + } + + void *winThreadId = pthread_gethandle(pTDD->mThreadId); + EAT_ASSERT(winThreadId); + + // SetThreadIdealProcessor differs from SetThreadAffinityMask in that SetThreadIdealProcessor is not + // a strict assignment, and it allows the OS to move the thread if the ideal processor is busy. + // SetThreadAffinityMask is a more rigid assignment, but it can result in slower performance and + // possibly hangs due to processor contention between threads. For Windows we use SetIdealThreadProcessor + // in the name of safety and likely better overall performance. + ::SetThreadIdealProcessor(winThreadId, pTDD->mStartupProcessor); #endif } // Else the thread hasn't started yet, or has already exited. Let the thread set its own @@ -543,6 +563,16 @@ static void* RunnableFunctionInternal(void* pContext) SetPlatformThreadAffinity(pTDD); else if(pTDD->mStartupProcessor == EA::Thread::kProcessorAny) EA::Thread::SetThreadAffinityMask(pTDD->mnThreadAffinityMask); + + #elif defined(EA_PLATFORM_MINGW) + pTDD->mThreadPid = getpid(); + + if(pTDD->mStartupProcessor != EA::Thread::kProcessorDefault + && pTDD->mStartupProcessor != EA::Thread::kProcessorAny) + SetPlatformThreadAffinity(pTDD); + else if(pTDD->mStartupProcessor == EA::Thread::kProcessorAny) + EA::Thread::SetThreadAffinityMask(pTDD->mnThreadAffinityMask); + #elif !defined(EA_PLATFORM_CONSOLE) && !defined(EA_PLATFORM_MOBILE) pTDD->mThreadPid = getpid(); // We can't set a thread affinity with a process id. #else @@ -607,6 +637,15 @@ static void* RunnableObjectInternal(void* pContext) else if(pTDD->mStartupProcessor == EA::Thread::kProcessorAny) EA::Thread::SetThreadAffinityMask(pTDD->mnThreadAffinityMask); + #elif defined(EA_PLATFORM_MINGW) + pTDD->mThreadPid = getpid(); + + if(pTDD->mStartupProcessor != EA::Thread::kProcessorDefault + && pTDD->mStartupProcessor != EA::Thread::kProcessorAny) + SetPlatformThreadAffinity(pTDD); + else if(pTDD->mStartupProcessor == EA::Thread::kProcessorAny) + EA::Thread::SetThreadAffinityMask(pTDD->mnThreadAffinityMask); + #elif !defined(EA_PLATFORM_CONSOLE) && !defined(EA_PLATFORM_MOBILE) pTDD->mThreadPid = getpid(); // We can't set a thread affinity with a process id. #else @@ -970,34 +1009,7 @@ bool EA::Thread::Thread::SetPriority(int nPriority) // To consider: Make it so we return a value. void EA::Thread::Thread::SetProcessor(int nProcessor) { - #if defined(EA_PLATFORM_WINDOWS) - if(mThreadData.mpData) - { - static AtomicInt32 nProcessorCount = 0; - - if(nProcessorCount == 0) - { - SYSTEM_INFO systemInfo; - memset(&systemInfo, 0, sizeof(systemInfo)); - GetSystemInfo(&systemInfo); - nProcessorCount = (int)systemInfo.dwNumberOfProcessors; - } - - DWORD dwThreadAffinityMask; - - if(nProcessor < 0) - dwThreadAffinityMask = 0xffffffff; - else - { - if(nProcessor >= nProcessorCount) - nProcessor %= nProcessorCount; - - dwThreadAffinityMask = 1 << nProcessor; - } - - SetThreadAffinityMask(mThreadData.mpData->mThreadId, dwThreadAffinityMask); - } - #elif defined(EA_PLATFORM_LINUX) + #if defined(EA_PLATFORM_LINUX) || defined(EA_PLATFORM_WINDOWS) if(mThreadData.mpData) { mThreadData.mpData->mStartupProcessor = nProcessor; // Assign this in case the thread hasn't started yet and thus we are leaving it a message to set it when it has started. diff --git a/source/unix/eathread_unix.cpp b/source/unix/eathread_unix.cpp index 5be260a..a0ee758 100644 --- a/source/unix/eathread_unix.cpp +++ b/source/unix/eathread_unix.cpp @@ -7,7 +7,7 @@ #include #include #include - +#include #if defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE #include @@ -155,7 +155,7 @@ if(result == 0) { // Cygwin does not support any scheduling policy other than SCHED_OTHER. - #if !defined(EA_PLATFORM_CYGWIN) + #if !defined(EA_PLATFORM_CYGWIN) && !defined(EA_PLATFORM_MINGW) if(policy == SCHED_OTHER) policy = SCHED_FIFO; #endif @@ -203,10 +203,17 @@ thr_stksegment(&s); return s.ss_sp; // Note that this is not the sp pointer (which would refer to the a location low in the stack address space). When returned by thr_stksegment(), ss_sp refers to the top (base) of the stack. - #elif defined(EA_PLATFORM_CYGWIN) - // Cygwin reserves pthread_attr_getstackaddr and pthread_attr_getstacksize for future use. - // The solution here is probably to use the Windows implementation of this here. - return 0; + #elif defined(EA_PLATFORM_CYGWIN) || defined(EA_PLATFORM_MINGW) + // libwinpthreads reserves pthread_attr_getstackaddr and pthread_attr_getstacksize for future use. + // So we currently use a Windows implementation here. + + #if defined(EA_PROCESSOR_X86) + NT_TIB *pTIB = reinterpret_cast(NtCurrentTeb()); + #else // defined(EA_PROCESSOR_X64) + NT_TIB64* pTIB = reinterpret_cast(NtCurrentTeb()); + #endif + + return reinterpret_cast(pTIB->StackBase); #else // Other Unix void* stackLow = NULL; @@ -241,23 +248,22 @@ { // Posix threading doesn't have the ability to set the processor. #if defined(EA_PLATFORM_WINDOWS) - static int nProcessorCount = 0; // This doesn't really need to be an atomic integer. + static const int nProcessorCount = GetProcessorCount(); - if(nProcessorCount == 0) + if(nProcessor < 0) + nProcessor = MAXIMUM_PROCESSORS; // This cases the SetThreadIdealProcessor to reset to 'no ideal processor'. + else { - SYSTEM_INFO systemInfo; - memset(&systemInfo, 0, sizeof(systemInfo)); - GetSystemInfo(&systemInfo); - nProcessorCount = (int)systemInfo.dwNumberOfProcessors; + if(nProcessor >= nProcessorCount) + nProcessor %= nProcessorCount; } - DWORD dwThreadAffinityMask; - - if((nProcessor < 0) || (nProcessor >= nProcessorCount)) - dwThreadAffinityMask = 0xffffffff; - else - dwThreadAffinityMask = 1 << nProcessor; - SetThreadAffinityMask(GetCurrentThread(), dwThreadAffinityMask); + // SetThreadIdealProcessor differs from SetThreadAffinityMask in that SetThreadIdealProcessor is not + // a strict assignment, and it allows the OS to move the thread if the ideal processor is busy. + // SetThreadAffinityMask is a more rigid assignment, but it can result in slower performance and + // possibly hangs due to processor contention between threads. For Windows we use SetIdealThreadProcessor + // in the name of safety and likely better overall performance. + SetThreadIdealProcessor(GetCurrentThread(), (DWORD)nProcessor); #elif (defined(EA_PLATFORM_LINUX) && !defined(EA_PLATFORM_ANDROID)) || defined(CS_UNDEFINED_STRING) cpu_set_t cpus; @@ -284,42 +290,85 @@ } - #if defined(EA_PLATFORM_WINDOWS) && defined(EA_PROCESSOR_X86) && defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1400) - int GetCurrentProcessorNumberXP() + #if defined(EA_PLATFORM_WIN32) && defined(EA_PROCESSOR_X86) && defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1400) + // People report on the Internet that this function can get you what CPU the current thread + // is running on. But that's false, as this function has been seen to return values greater than + // the number of physical or real CPUs present. For example, this function returns 6 for my + // Single CPU that's dual-hyperthreaded. + static int GetCurrentProcessorNumberCPUID() { _asm { mov eax, 1 } _asm { cpuid } _asm { shr ebx, 24 } _asm { mov eax, ebx } } - #endif + int GetCurrentProcessorNumberXP() + { + int cpuNumber = GetCurrentProcessorNumberCPUID(); + int cpuCount = EA::Thread::GetProcessorCount(); + + return (cpuNumber % cpuCount); // I don't know if this is the right thing to do, but it's better than returning an impossible number and Windows XP is a fading OS as it is. + } + + #endif int EA::Thread::GetThreadProcessor() { #if defined(EA_PLATFORM_WINDOWS) // We are using Posix threading on Windows. It happens to be mapped to Windows threading and // so we can use Windows facilities to tell what processor the thread is running on. - // Only Windows Vista and later provides GetCurrentProcessorNumber. - // So we must dynamically link to this function. - static EA_THREAD_LOCAL bool bInitialized = false; - static EA_THREAD_LOCAL DWORD (WINAPI *pfnGetCurrentProcessorNumber)() = NULL; + #if defined(EA_PLATFORM_WIN32) + // Only Windows Vista and later provides GetCurrentProcessorNumber. + // So we must dynamically link to this function. + static EA_THREAD_LOCAL bool bInitialized = false; + static EA_THREAD_LOCAL DWORD (WINAPI *pfnGetCurrentProcessorNumber)() = NULL; - if(!bInitialized) - { - HMODULE hKernel32 = GetModuleHandle("KERNEL32.DLL"); - if(hKernel32) - pfnGetCurrentProcessorNumber = (DWORD (WINAPI*)())GetProcAddress(hKernel32, "GetCurrentProcessorNumber"); - bInitialized = true; - } + if(!bInitialized) + { + HMODULE hKernel32 = GetModuleHandleA("KERNEL32.DLL"); + if(hKernel32) + pfnGetCurrentProcessorNumber = + (DWORD (WINAPI*)())(uintptr_t)GetProcAddress( + hKernel32, + "GetCurrentProcessorNumber"); + + bInitialized = true; + } - if(pfnGetCurrentProcessorNumber) - return (int)(unsigned)pfnGetCurrentProcessorNumber(); + if(pfnGetCurrentProcessorNumber) + return (int)(unsigned)pfnGetCurrentProcessorNumber(); + + #if defined(EA_PLATFORM_WINDOWS) && defined(EA_PROCESSOR_X86) && defined(EA_COMPILER_MSVC) && (EA_COMPILER_MSVC >= 1400) + return GetCurrentProcessorNumberXP(); + #else + return 0; + #endif + + #elif defined(EA_PLATFORM_WIN64) + static EA_THREAD_LOCAL bool bInitialized = false; + static EA_THREAD_LOCAL DWORD (WINAPI *pfnGetCurrentProcessorNumber)() = NULL; + + if(!bInitialized) + { + HMODULE hKernel32 = GetModuleHandleA("KERNEL32.DLL"); // Yes, we want to use Kernel32.dll. There is no Kernel64.dll on Win64. + if(hKernel32) + pfnGetCurrentProcessorNumber = + (DWORD (WINAPI*)())(uintptr_t)GetProcAddress( + hKernel32, + "GetCurrentProcessorNumber"); + + bInitialized = true; + } + + if(pfnGetCurrentProcessorNumber) + return (int)(unsigned)pfnGetCurrentProcessorNumber(); - #if defined(EA_PLATFORM_WINDOWS) && defined(EA_PROCESSOR_X86) && defined(EA_COMPILER_MSVC) && (EA_COMPILER_VERSION >= 1400) - return GetCurrentProcessorNumberXP(); - #else return 0; + + #else + return (int)(unsigned)GetCurrentProcessorNumber(); + #endif #elif defined(EA_PLATFORM_ANDROID) @@ -367,7 +416,7 @@ { pTDD->mnThreadAffinityMask = nAffinityMask; - #if EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED + #if EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED && !defined(EA_PLATFORM_WINDOWS) cpu_set_t cpuSetMask; memset(&cpuSetMask, 0, sizeof(cpu_set_t)); @@ -382,6 +431,27 @@ sched_setaffinity(pTDD->mThreadPid, sizeof(cpu_set_t), &cpuSetMask); #endif } + + #if EATHREAD_THREAD_AFFINITY_MASK_SUPPORTED && defined(EA_PLATFORM_WINDOWS) + // Call the Windows library function. + DWORD_PTR nProcessorCountMask = (DWORD_PTR)1 << GetProcessorCount(); + DWORD_PTR nProcessAffinityMask, nSystemAffinityMask; + + if(EA_LIKELY(GetProcessAffinityMask(GetCurrentProcess(), &nProcessAffinityMask, &nSystemAffinityMask))) + nProcessorCountMask = nProcessAffinityMask; + + nAffinityMask &= nProcessorCountMask; + + void *winThreadId = pthread_gethandle(pTDD->mThreadId); + EAT_ASSERT(winThreadId); + + auto opResult = ::SetThreadAffinityMask(winThreadId, static_cast(nAffinityMask)); + EA_UNUSED(opResult); + EAT_ASSERT_FORMATTED( + opResult != 0, + "The Windows (pthreads) platform SetThreadAffinityMask failed. GetLastError %x", + GetLastError()); + #endif } @@ -578,9 +648,9 @@ #if defined(EA_PLATFORM_WINDOWS) // There is no nanosleep on Windows, but there is Sleep. if(timeRelative == kTimeoutImmediate) - Sleep(0); + SwitchToThread(); else - Sleep((unsigned)((timeRelative.tv_sec * 1000) + (((timeRelative.tv_nsec % 1000) * 1000000)))); + SleepEx((unsigned)((timeRelative.tv_sec * 1000) + (timeRelative.tv_nsec / 1000000)), TRUE); #else if(timeRelative == kTimeoutImmediate) { diff --git a/test/thread/source/TestThreadCallstack.cpp b/test/thread/source/TestThreadCallstack.cpp index 65fd629..1bf9a5e 100644 --- a/test/thread/source/TestThreadCallstack.cpp +++ b/test/thread/source/TestThreadCallstack.cpp @@ -257,7 +257,7 @@ EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE int TestRemoteThreadContextVsCal auto threadId = remoteThread.mThread.GetId(); { -#if defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE) +#if (defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE)) && !defined(EA_PLATFORM_MINGW) // suspend the target thread to make sure we get a coherent callstack bool wasSuspended = (::SuspendThread(threadId) != ((DWORD)-1)); // fail is (DWORD)-1 #endif @@ -268,7 +268,7 @@ EA_NO_INLINE EACALLSTACK_TEST_FUNCTION_LINKAGE int TestRemoteThreadContextVsCal EA::Thread::GetCallstack(addressContextArray, EAArrayCount(addressContextArray), &callstackContext); } -#if defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE) +#if (defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_XBOXONE)) && !defined(EA_PLATFORM_MINGW) // resume the target thread as needed if (wasSuspended) { diff --git a/test/thread/source/TestThreadThread.cpp b/test/thread/source/TestThreadThread.cpp index 6f6c517..9388967 100644 --- a/test/thread/source/TestThreadThread.cpp +++ b/test/thread/source/TestThreadThread.cpp @@ -899,7 +899,8 @@ int TestThreadThread() #if defined(EA_PLATFORM_WINDOWS) && !EA_USE_CPP11_CONCURRENCY - { // Try to reproduce Windows problem with Thread::GetStatus returning kStatusEnded when it should return kStatusRunning. + { + // Try to reproduce Windows problem with Thread::GetStatus returning kStatusEnded when it should return kStatusRunning. // On my current work machine (WinXP32, Single P4 CPU) this problem doesn't occur. But it might occur with others. Thread::Status status; Thread threadBackground[8]; @@ -910,6 +911,7 @@ int TestThreadThread() EA::Thread::SetThreadPriority(kThreadPriorityDefault + 2); thread.Begin(TestFunction1); + ThreadSleep(10); // It's possible the thread hasn't started yet, so wait to make sure it has. status = thread.GetStatus(); EA::Thread::SetThreadPriority(kThreadPriorityDefault);