Skip to content

Commit

Permalink
Fixes for MinGW
Browse files Browse the repository at this point in the history
Use pthreads instead of the win32 threads implementation, as SEH
exceptions are poorly supported.
  • Loading branch information
RA-Kooi committed Mar 3, 2020
1 parent b05f3b3 commit 4ef7ef7
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 86 deletions.
2 changes: 1 addition & 1 deletion include/eathread/eathread_callstack.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions include/eathread/eathread_futex.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
8 changes: 4 additions & 4 deletions include/eathread/internal/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions source/eathread_callstack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@

#include <EABase/eabase.h>

#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"
Expand Down
2 changes: 1 addition & 1 deletion source/pc/eathread_thread_pc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
4 changes: 2 additions & 2 deletions source/unix/eathread_callstack_glibc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
25 changes: 24 additions & 1 deletion source/unix/eathread_pthread_stack_info.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,16 @@
#include <pthread.h>
#endif

#if defined(EA_PLATFORM_MICROSOFT)
#include <Windows.h>
#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
Expand Down Expand Up @@ -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 <WinNT.h> as an inline call to __readgsqword
#if defined(EA_PROCESSOR_X86)
NT_TIB *pTIB = reinterpret_cast<NT_TIB*>(NtCurrentTeb());
#else // defined(EA_PROCESSOR_X64)
NT_TIB64* pTIB = reinterpret_cast<NT_TIB64*>(NtCurrentTeb());
#endif

if(pBase)
*pBase = reinterpret_cast<void*>(pTIB->StackBase);
if(pLimit)
*pLimit = reinterpret_cast<void*>(pTIB->StackLimit);

return true;
}
#else
bool GetPthreadStackInfo(void** pBase, void** pLimit)
{
Expand Down
72 changes: 42 additions & 30 deletions source/unix/eathread_thread_unix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
#else
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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
Loading

0 comments on commit 4ef7ef7

Please sign in to comment.