diff --git a/BeefRT/dbg/gc.cpp b/BeefRT/dbg/gc.cpp index e5f9fc03..7fb3d3ae 100644 --- a/BeefRT/dbg/gc.cpp +++ b/BeefRT/dbg/gc.cpp @@ -214,6 +214,8 @@ BFGC::ThreadInfo::~ThreadInfo() { if (mThreadHandle != NULL) BfpThread_Release(mThreadHandle); + if (mThreadInfo != NULL) + BfpThreadInfo_Release(mThreadInfo); } bool BFGC::ThreadInfo::WantsSuspend() @@ -226,6 +228,14 @@ bool BFGC::ThreadInfo::WantsSuspend() #endif } +void BFGC::ThreadInfo::CalcStackStart() +{ + intptr stackBase; + int stackLimit; + BfpThreadInfo_GetStackInfo(mThreadInfo, &stackBase, &stackLimit, BfpThreadInfoFlags_NoCache, NULL); + mStackStart = stackBase; +} + ////////////////////////////////////////////////////////////////////////// #ifdef BF_GC_LOG_ENABLED @@ -1447,6 +1457,7 @@ bool BFGC::ScanThreads() mQueueMarkObjects = true; ConservativeScan(regVals, regValCount * sizeof(intptr)); + thread->CalcStackStart(); int length = thread->mStackStart - stackPtr; AdjustStackPtr(stackPtr, length); @@ -1895,11 +1906,9 @@ void BFGC::ThreadStarted() thread->mThreadHandle = BfpThread_GetCurrent(); thread->mThreadId = BfpThread_GetCurrentId(); thread->mTEB = GetTEB((HANDLE)thread->mThreadHandle); - - intptr stackBase; - int stackLimit; - BfpThread_GetStackInfo(thread->mThreadHandle, &stackBase, &stackLimit, NULL); - thread->mStackStart = stackBase; + thread->mThreadInfo = BfpThreadInfo_Create(); + + thread->CalcStackStart(); mThreadList.Add(thread); diff --git a/BeefRT/dbg/gc.h b/BeefRT/dbg/gc.h index cc43b8ca..daa60674 100644 --- a/BeefRT/dbg/gc.h +++ b/BeefRT/dbg/gc.h @@ -170,6 +170,7 @@ public: Beefy::CritSect mCritSect; BfpThread* mThreadHandle; + BfpThreadInfo* mThreadInfo; BfpThreadId mThreadId; void* mTEB; intptr mStackStart; @@ -180,6 +181,7 @@ public: { mThreadId = 0; mThreadHandle = NULL; + mThreadInfo = NULL; mTEB = NULL; mStackStart = NULL; mRunning = true; @@ -188,6 +190,7 @@ public: ~ThreadInfo(); bool WantsSuspend(); + void CalcStackStart(); }; struct RawLeakInfo diff --git a/BeefySysLib/platform/PlatformInterface.h b/BeefySysLib/platform/PlatformInterface.h index 8dc00d29..a2591ed6 100644 --- a/BeefySysLib/platform/PlatformInterface.h +++ b/BeefySysLib/platform/PlatformInterface.h @@ -24,6 +24,7 @@ typedef uint64 BfpTimeStamp; typedef intptr BfpThreadId; struct BfpThread; +struct BfpThreadInfo; struct BfpFile; struct BfpSpawn; struct BfpFileWatcher; @@ -231,6 +232,12 @@ enum BfpThreadPriority BfpThreadPriority_VeryHigh =2 }; +enum BfpThreadInfoFlags +{ + BfpThreadInfoFlags_None = 0, + BfpThreadInfoFlags_NoCache = 1 +}; + enum BfpThreadResult { BfpThreadResult_Ok = BfpResult_Ok, @@ -251,10 +258,13 @@ BFP_EXPORT void BFP_CALLTYPE BfpThread_SetPriority(BfpThread* thread, BfpThreadP BFP_EXPORT void BFP_CALLTYPE BfpThread_Suspend(BfpThread* thread, BfpThreadResult* outResult); BFP_EXPORT void BFP_CALLTYPE BfpThread_Resume(BfpThread* thread, BfpThreadResult* outResult); BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr* outStackPtr, intptr* outIntRegs, int* inOutIntRegCount, BfpThreadResult* outResult); -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult); BFP_EXPORT void BFP_CALLTYPE BfpThread_Sleep(int sleepMS); BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield(); +BFP_EXPORT BfpThreadInfo* BFP_CALLTYPE BfpThreadInfo_Create(); +BFP_EXPORT void BFP_CALLTYPE BfpThreadInfo_Release(BfpThreadInfo* threadInfo); +BFP_EXPORT void BFP_CALLTYPE BfpThreadInfo_GetStackInfo(BfpThreadInfo* thread, intptr* outStackBase, int* outStackLimit, BfpThreadInfoFlags flags, BfpThreadResult* outResult); + struct BfpCritSect; BFP_EXPORT BfpCritSect* BFP_CALLTYPE BfpCritSect_Create(); BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Release(BfpCritSect* critSect); diff --git a/BeefySysLib/platform/posix/PosixCommon.cpp b/BeefySysLib/platform/posix/PosixCommon.cpp index 58ebfee5..198b377e 100644 --- a/BeefySysLib/platform/posix/PosixCommon.cpp +++ b/BeefySysLib/platform/posix/PosixCommon.cpp @@ -1166,6 +1166,7 @@ struct BfpThreadInfo { intptr mStackBase; int mStackLimit; + pthread_t mPThread; }; static __thread BfpThread* gCurrentThread; @@ -1338,32 +1339,6 @@ BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr NOT_IMPL; } -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult) -{ -#ifdef BFP_HAS_PTHREAD_GETATTR_NP - if (gCurrentThreadInfo.mStackBase == 0) - { - void* stackBase = 0; - size_t stackLimit = 0; - - pthread_attr_t attr; - pthread_getattr_np(pthread_self(), &attr); - pthread_attr_getstack(&attr, &stackBase, &stackLimit); - - gCurrentThreadInfo.mStackBase = (intptr)stackBase + stackLimit; - gCurrentThreadInfo.mStackLimit = (int)stackLimit; - pthread_attr_destroy(&attr); - } - - *outStackBase = gCurrentThreadInfo.mStackBase; - *outStackLimit = gCurrentThreadInfo.mStackLimit; - - OUTRESULT(BfpThreadResult_Ok); -#else - OUTRESULT(BfpThreadResult_UnknownError); -#endif -} - BFP_EXPORT void BFP_CALLTYPE BfpThread_Sleep(int sleepMS) { usleep(sleepMS * 1000); @@ -1374,6 +1349,55 @@ BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield() return sched_yield() == 0; } +/// + +BFP_EXPORT BfpThreadInfo* BFP_CALLTYPE BfpThreadInfo_Create() +{ + BfpThreadInfo* threadInfo = new BfpThreadInfo(); + threadInfo->mStackBase = 0; + threadInfo->mStackLimit = 0; + threadInfo->mPThread = pthread_self(); +} + +BFP_EXPORT void BFP_CALLTYPE BfpThreadInfo_Release(BfpThreadInfo* threadInfo) +{ + delete threadInfo; +} + +BFP_EXPORT void BFP_CALLTYPE BfpThreadInfo_GetStackInfo(BfpThreadInfo* threadInfo, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult) +{ +#ifdef BFP_HAS_PTHREAD_GETATTR_NP + if (threadInfo == NULL) + { + threadInfo = &gCurrentThreadInfo; + threadInfo->mPThread = pthread_self(); + } + + if (threadInfo->mStackBase == 0) + { + void* stackBase = 0; + size_t stackLimit = 0; + + pthread_attr_t attr; + pthread_getattr_np(threadInfo->mPThread, &attr); + pthread_attr_getstack(&attr, &stackBase, &stackLimit); + + threadInfo->mStackBase = (intptr)stackBase + stackLimit; + threadInfo->mStackLimit = (int)stackLimit; + pthread_attr_destroy(&attr); + } + + *outStackBase = threadInfo->mStackBase; + *outStackLimit = threadInfo->mStackLimit; + + OUTRESULT(BfpThreadResult_Ok); +#else + OUTRESULT(BfpThreadResult_UnknownError); +#endif +} + +/// + struct BfpCritSect { pthread_mutex_t mPMutex; diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index f5bbafee..01984441 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -2253,39 +2253,6 @@ BFP_EXPORT void BFP_CALLTYPE BfpThread_GetIntRegisters(BfpThread* thread, intptr *inOutIntRegCount = (int)(curPtr - outIntRegs); } -struct BfpThreadStackInfo -{ - intptr mStackBase; - intptr mStackLimit; -}; -static __declspec(thread) BfpThreadStackInfo gThreadStackInfo; - -BFP_EXPORT void BFP_CALLTYPE BfpThread_GetStackInfo(BfpThread* thread, intptr* outStackBase, int* outStackLimit, BfpThreadResult* outResult) -{ - if (gThreadStackInfo.mStackBase == 0) - { - auto teb = (NT_TIB*)NtCurrentTeb(); - - MEMORY_BASIC_INFORMATION stackInfo = { 0 }; - // We subtract one page for our request. VirtualQuery rounds UP to the next page. - // Unfortunately, the stack grows down. If we're on the first page (last page in the - // VirtualAlloc), we'll be moved to the next page, which is off the stack! Note this - // doesn't work right for IA64 due to bigger pages. - void* currentAddr = (void*)((intptr_t)&stackInfo - 4096); - - // Query for the current stack allocation information. - VirtualQuery(currentAddr, &stackInfo, sizeof(MEMORY_BASIC_INFORMATION)); - - gThreadStackInfo.mStackBase = (uintptr_t)teb->StackBase; - gThreadStackInfo.mStackLimit = (uintptr_t)stackInfo.AllocationBase; - } - - *outStackBase = (intptr)gThreadStackInfo.mStackBase; - *outStackLimit = (int)(gThreadStackInfo.mStackBase - gThreadStackInfo.mStackLimit); - OUTRESULT(BfpThreadResult_Ok); - return; -} - struct BfpCritSect { CRITICAL_SECTION mCritSect; @@ -2303,6 +2270,62 @@ BFP_EXPORT bool BFP_CALLTYPE BfpThread_Yield() /// +struct BfpThreadInfo +{ + intptr mStackBase; + intptr mStackLimit; + NT_TIB* mTeb; +}; + +BFP_EXPORT BfpThreadInfo* BFP_CALLTYPE BfpThreadInfo_Create() +{ + BfpThreadInfo* threadInfo = new BfpThreadInfo(); + threadInfo->mStackBase = 0; + threadInfo->mStackLimit = 0; + threadInfo->mTeb = (NT_TIB*)NtCurrentTeb(); + return threadInfo; +} + +BFP_EXPORT void BFP_CALLTYPE BfpThreadInfo_Release(BfpThreadInfo* threadInfo) +{ + delete threadInfo; +} + +static __declspec(thread) BfpThreadInfo gThreadStackInfo; + +BFP_EXPORT void BFP_CALLTYPE BfpThreadInfo_GetStackInfo(BfpThreadInfo* threadInfo, intptr* outStackBase, int* outStackLimit, BfpThreadInfoFlags flags, BfpThreadResult* outResult) +{ + if (threadInfo == NULL) + { + threadInfo = &gThreadStackInfo; + if (threadInfo->mTeb == NULL) + threadInfo->mTeb = (NT_TIB*)NtCurrentTeb(); + } + + if ((threadInfo->mStackBase == 0) || ((flags & BfpThreadInfoFlags_NoCache) != 0)) + { + MEMORY_BASIC_INFORMATION stackInfo = { 0 }; + // We subtract one page for our request. VirtualQuery rounds UP to the next page. + // Unfortunately, the stack grows down. If we're on the first page (last page in the + // VirtualAlloc), we'll be moved to the next page, which is off the stack! Note this + // doesn't work right for IA64 due to bigger pages. + void* currentAddr = (void*)((intptr_t)&stackInfo - 4096); + + // Query for the current stack allocation information. + VirtualQuery(currentAddr, &stackInfo, sizeof(MEMORY_BASIC_INFORMATION)); + + threadInfo->mStackBase = (uintptr_t)threadInfo->mTeb->StackBase; + threadInfo->mStackLimit = (uintptr_t)stackInfo.AllocationBase; + } + + *outStackBase = (intptr)threadInfo->mStackBase; + *outStackLimit = (int)(threadInfo->mStackBase - threadInfo->mStackLimit); + OUTRESULT(BfpThreadResult_Ok); + return; +} + +/// + BFP_EXPORT BfpCritSect* BFP_CALLTYPE BfpCritSect_Create() { BfpCritSect* critSect = new BfpCritSect(); diff --git a/BeefySysLib/util/StackHelper.cpp b/BeefySysLib/util/StackHelper.cpp index e60ea039..b3eaa4f2 100644 --- a/BeefySysLib/util/StackHelper.cpp +++ b/BeefySysLib/util/StackHelper.cpp @@ -25,7 +25,7 @@ bool StackHelper::CanStackExpand(int wantBytes) intptr stackBase = 0; int stackLimit = 0; BfpThreadResult threadResult; - BfpThread_GetStackInfo(NULL, &stackBase, &stackLimit, &threadResult); + BfpThreadInfo_GetStackInfo(NULL, &stackBase, &stackLimit, BfpThreadInfoFlags_None, &threadResult); if (threadResult != BfpThreadResult_Ok) return true;