summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJan Vorlicek <janvorli@microsoft.com>2018-11-16 19:08:29 +0100
committerGitHub <noreply@github.com>2018-11-16 19:08:29 +0100
commit488d2a70ba59c58b26aa3f4f988a42f6b8927146 (patch)
treeedfa9a20628c2c8d503a17534434c7b0ac87d97a /src
parent7f22a149708a9ad6a90b9a92b78c12a7f4ae9d41 (diff)
downloadcoreclr-488d2a70ba59c58b26aa3f4f988a42f6b8927146.tar.gz
coreclr-488d2a70ba59c58b26aa3f4f988a42f6b8927146.tar.bz2
coreclr-488d2a70ba59c58b26aa3f4f988a42f6b8927146.zip
Fix unloadability races (#21024)
* Fix LoaderAllocator::AllocateHandle When another thread wins the race in growing the handle table, the code was not refreshing the slotsUsed local to the new up to date value. This was leading to overwriting / reusing a live handle. This change fixes it. * Embed ThreadLocalBlock in Thread Instead of allocating ThreadLocalBlock dynamically, embed it in the Thread. That solves race issue between thread destruction and LoaderAllocator destruction. The ThreadLocalBlock could have been deleted during Thread shutdown while the LoaderAllocator's destruction would be working with it.
Diffstat (limited to 'src')
-rw-r--r--src/debug/daccess/dacdbiimpl.cpp2
-rw-r--r--src/debug/daccess/inspect.cpp2
-rw-r--r--src/debug/daccess/request.cpp21
-rw-r--r--src/gc/objecthandle.cpp3
-rw-r--r--src/vm/appdomain.cpp55
-rw-r--r--src/vm/appdomain.hpp1
-rw-r--r--src/vm/comsynchronizable.cpp4
-rw-r--r--src/vm/loaderallocator.cpp1
-rw-r--r--src/vm/methodtable.h4
-rw-r--r--src/vm/methodtable.inl20
-rw-r--r--src/vm/proftoeeinterfaceimpl.cpp2
-rw-r--r--src/vm/threads.cpp94
-rw-r--r--src/vm/threads.h88
-rw-r--r--src/vm/threadstatics.cpp28
-rw-r--r--src/vm/threadstatics.h123
15 files changed, 133 insertions, 315 deletions
diff --git a/src/debug/daccess/dacdbiimpl.cpp b/src/debug/daccess/dacdbiimpl.cpp
index cc68cdc930..b19d4c47df 100644
--- a/src/debug/daccess/dacdbiimpl.cpp
+++ b/src/debug/daccess/dacdbiimpl.cpp
@@ -3239,7 +3239,7 @@ CORDB_ADDRESS DacDbiInterfaceImpl::GetThreadStaticAddress(VMPTR_FieldDesc vmFiel
// Find out whether the field is thread local and get its address.
if (pFieldDesc->IsThreadStatic())
{
- fieldAddress = pRuntimeThread->GetStaticFieldAddrNoCreate(pFieldDesc, NULL);
+ fieldAddress = pRuntimeThread->GetStaticFieldAddrNoCreate(pFieldDesc);
}
else
{
diff --git a/src/debug/daccess/inspect.cpp b/src/debug/daccess/inspect.cpp
index a69cfa3835..bbd724fb5c 100644
--- a/src/debug/daccess/inspect.cpp
+++ b/src/debug/daccess/inspect.cpp
@@ -1431,7 +1431,7 @@ ClrDataValue::NewFromFieldDesc(ClrDataAccess* dac,
}
baseAddr =
- TO_CDADDR(tlsThread->GetStaticFieldAddrNoCreate(fieldDesc, NULL));
+ TO_CDADDR(tlsThread->GetStaticFieldAddrNoCreate(fieldDesc));
}
else if (fieldDesc->IsStatic())
{
diff --git a/src/debug/daccess/request.cpp b/src/debug/daccess/request.cpp
index c196d7f2a4..fcd21fe08c 100644
--- a/src/debug/daccess/request.cpp
+++ b/src/debug/daccess/request.cpp
@@ -3302,25 +3302,18 @@ ClrDataAccess::GetThreadLocalModuleData(CLRDATA_ADDRESS thread, unsigned int ind
pLocalModuleData->ModuleIndex = index;
PTR_Thread pThread = PTR_Thread(TO_TADDR(thread));
- PTR_ThreadLocalBlock pLocalBlock = ThreadStatics::GetCurrentTLBIfExists(pThread, NULL);
- if (!pLocalBlock)
+ PTR_ThreadLocalBlock pLocalBlock = ThreadStatics::GetCurrentTLB(pThread);
+ PTR_ThreadLocalModule pLocalModule = pLocalBlock->GetTLMIfExists(ModuleIndex(index));
+ if (!pLocalModule)
{
hr = E_INVALIDARG;
}
else
{
- PTR_ThreadLocalModule pLocalModule = pLocalBlock->GetTLMIfExists(ModuleIndex(index));
- if (!pLocalModule)
- {
- hr = E_INVALIDARG;
- }
- else
- {
- pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
- pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
- pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable);
- pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(ThreadLocalModule, pLocalModule, m_pDataBlob));
- }
+ pLocalModuleData->pGCStaticDataStart = TO_CDADDR(PTR_TO_TADDR(pLocalModule->GetPrecomputedGCStaticsBasePointer()));
+ pLocalModuleData->pNonGCStaticDataStart = TO_CDADDR(pLocalModule->GetPrecomputedNonGCStaticsBasePointer());
+ pLocalModuleData->pDynamicClassTable = PTR_CDADDR(pLocalModule->m_pDynamicClassTable);
+ pLocalModuleData->pClassData = (TADDR) (PTR_HOST_MEMBER_TADDR(ThreadLocalModule, pLocalModule, m_pDataBlob));
}
SOSDacLeave();
diff --git a/src/gc/objecthandle.cpp b/src/gc/objecthandle.cpp
index 347ba34b4b..b3d93b40dd 100644
--- a/src/gc/objecthandle.cpp
+++ b/src/gc/objecthandle.cpp
@@ -812,9 +812,6 @@ void Ref_DestroyHandleTableBucket(HandleTableBucket *pBucket)
{
WRAPPER_NO_CONTRACT;
- // this check is because here we might be called from AppDomain::Terminate after AppDomain::ClearGCRoots,
- // which calls Ref_RemoveHandleTableBucket itself
-
Ref_RemoveHandleTableBucket(pBucket);
for (int uCPUindex=0; uCPUindex < getNumberOfSlots(); uCPUindex++)
{
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index 368725fd07..cb94f3b666 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -7807,61 +7807,6 @@ void AppDomain::UnwindThreads()
while (TRUE) ;
}
-void AppDomain::ClearGCRoots()
-{
- CONTRACTL
- {
- GC_TRIGGERS;
- MODE_COOPERATIVE;
- NOTHROW;
- }
- CONTRACTL_END;
-
- Thread *pThread = NULL;
- ThreadSuspend::SuspendEE(ThreadSuspend::SUSPEND_FOR_APPDOMAIN_SHUTDOWN);
-
- // Tell the JIT managers to delete any entries in their structures. All the cooperative mode threads are stopped at
- // this point, so only need to synchronize the preemptive mode threads.
- ExecutionManager::Unload(GetLoaderAllocator());
-
- while ((pThread = ThreadStore::GetAllThreadList(pThread, 0, 0)) != NULL)
- {
- // Delete the thread local static store
- pThread->DeleteThreadStaticData(this);
-
- // <TODO>@TODO: A pre-allocated AppDomainUnloaded exception might be better.</TODO>
- if (m_handleStore->ContainsHandle(pThread->m_LastThrownObjectHandle))
- {
- // Never delete a handle to a preallocated exception object.
- if (!CLRException::IsPreallocatedExceptionHandle(pThread->m_LastThrownObjectHandle))
- {
- DestroyHandle(pThread->m_LastThrownObjectHandle);
- }
-
- pThread->m_LastThrownObjectHandle = NULL;
- }
-
- // Clear out the exceptions objects held by a thread.
- pThread->GetExceptionState()->ClearThrowablesForUnload(m_handleStore);
- }
-
- //delete them while we still have the runtime suspended
- // This must be deleted before the loader heaps are deleted.
- if (m_pMarshalingData != NULL)
- {
- delete m_pMarshalingData;
- m_pMarshalingData = NULL;
- }
-
- if (m_pLargeHeapHandleTable != NULL)
- {
- delete m_pLargeHeapHandleTable;
- m_pLargeHeapHandleTable = NULL;
- }
-
- ThreadSuspend::RestartEE(FALSE, TRUE);
-}
-
#ifdef _DEBUG
void AppDomain::TrackADThreadEnter(Thread *pThread, Frame *pFrame)
diff --git a/src/vm/appdomain.hpp b/src/vm/appdomain.hpp
index 143a012552..03e2c870a9 100644
--- a/src/vm/appdomain.hpp
+++ b/src/vm/appdomain.hpp
@@ -3242,7 +3242,6 @@ private:
while (lastStage !=stage)
lastStage = (Stage)FastInterlockCompareExchange((LONG*)&m_Stage,stage,lastStage);
};
- void ClearGCRoots();
void UnwindThreads();
// Return TRUE if EE is stopped
// Return FALSE if more work is needed
diff --git a/src/vm/comsynchronizable.cpp b/src/vm/comsynchronizable.cpp
index 5f54bcda93..e7ed1f0c6e 100644
--- a/src/vm/comsynchronizable.cpp
+++ b/src/vm/comsynchronizable.cpp
@@ -1343,7 +1343,7 @@ OBJECTREF ThreadBaseObject::GetManagedThreadCulture(BOOL bUICulture)
if (pFD != NULL)
{
- pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD, NULL);
+ pCurrentCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD);
if (pCurrentCulture)
{
return *pCurrentCulture;
@@ -1418,7 +1418,7 @@ void ThreadBaseObject::ResetManagedThreadCulture(BOOL bUICulture)
{
OBJECTREF *pCulture = NULL;
BEGIN_SO_INTOLERANT_CODE_NO_THROW_CHECK_THREAD(COMPlusThrowSO());
- pCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD, NULL);
+ pCulture = (OBJECTREF*)pThread->GetStaticFieldAddrNoCreate(pFD);
if (pCulture)
{
SetObjectReferenceUnchecked(pCulture, NULL);
diff --git a/src/vm/loaderallocator.cpp b/src/vm/loaderallocator.cpp
index acb9bcacf3..fd065e52ab 100644
--- a/src/vm/loaderallocator.cpp
+++ b/src/vm/loaderallocator.cpp
@@ -801,6 +801,7 @@ LOADERHANDLE LoaderAllocator::AllocateHandle(OBJECTREF value)
gc.handleTable = gc.loaderAllocator->GetHandleTable();
}
+ slotsUsed = gc.loaderAllocator->GetSlotsUsed();
numComponents = gc.handleTable->GetNumComponents();
if (slotsUsed < numComponents)
diff --git a/src/vm/methodtable.h b/src/vm/methodtable.h
index 2367d38c6b..557c2fbc10 100644
--- a/src/vm/methodtable.h
+++ b/src/vm/methodtable.h
@@ -2550,8 +2550,8 @@ public:
inline PTR_BYTE GetGCThreadStaticsBasePointer();
#endif //!DACCESS_COMPILE
- inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain);
- inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain);
+ inline PTR_BYTE GetNonGCThreadStaticsBasePointer(PTR_Thread pThread);
+ inline PTR_BYTE GetGCThreadStaticsBasePointer(PTR_Thread pThread);
inline DWORD IsDynamicStatics()
{
diff --git a/src/vm/methodtable.inl b/src/vm/methodtable.inl
index 88ce26cffd..d998f1fe36 100644
--- a/src/vm/methodtable.inl
+++ b/src/vm/methodtable.inl
@@ -1408,9 +1408,7 @@ inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer()
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
- PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, NULL);
- if (pTLB == NULL)
- return NULL;
+ PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
@@ -1436,9 +1434,7 @@ inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer()
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
- PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, NULL);
- if (pTLB == NULL)
- return NULL;
+ PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
@@ -1450,16 +1446,14 @@ inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer()
#endif //!DACCESS_COMPILE
//==========================================================================================
-inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain)
+inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread)
{
LIMITED_METHOD_DAC_CONTRACT;
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
- PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, pDomain);
- if (pTLB == NULL)
- return NULL;
+ PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
@@ -1469,16 +1463,14 @@ inline PTR_BYTE MethodTable::GetNonGCThreadStaticsBasePointer(PTR_Thread pThread
}
//==========================================================================================
-inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread, PTR_AppDomain pDomain)
+inline PTR_BYTE MethodTable::GetGCThreadStaticsBasePointer(PTR_Thread pThread)
{
LIMITED_METHOD_DAC_CONTRACT;
// Get the current module's ModuleIndex
ModuleIndex index = GetModuleForStatics()->GetModuleIndex();
- PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLBIfExists(pThread, pDomain);
- if (pTLB == NULL)
- return NULL;
+ PTR_ThreadLocalBlock pTLB = ThreadStatics::GetCurrentTLB(pThread);
PTR_ThreadLocalModule pTLM = pTLB->GetTLMIfExists(index);
if (pTLM == NULL)
diff --git a/src/vm/proftoeeinterfaceimpl.cpp b/src/vm/proftoeeinterfaceimpl.cpp
index 2238543066..6cf30c45c0 100644
--- a/src/vm/proftoeeinterfaceimpl.cpp
+++ b/src/vm/proftoeeinterfaceimpl.cpp
@@ -3513,7 +3513,7 @@ HRESULT ProfToEEInterfaceImpl::GetThreadStaticAddress2(ClassID classId,
//
// Store the result and return
//
- PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc, pAppDomain));
+ PTR_VOID pAddress = (void *)(((Thread *)threadId)->GetStaticFieldAddrNoCreate(pFieldDesc));
if (pAddress == NULL)
{
return E_INVALIDARG;
diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp
index 707330a30f..45f37a3a68 100644
--- a/src/vm/threads.cpp
+++ b/src/vm/threads.cpp
@@ -62,6 +62,24 @@ SPTR_IMPL(ThreadStore, ThreadStore, s_pThreadStore);
CONTEXT *ThreadStore::s_pOSContext = NULL;
CLREvent *ThreadStore::s_pWaitForStackCrawlEvent;
+PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(ModuleIndex index)
+{
+ WRAPPER_NO_CONTRACT;
+ SUPPORTS_DAC;
+
+ if (index.m_dwIndex >= m_TLMTableSize)
+ return NULL;
+
+ return m_pTLMTable[index.m_dwIndex].pTLM;
+}
+
+PTR_ThreadLocalModule ThreadLocalBlock::GetTLMIfExists(MethodTable* pMT)
+{
+ WRAPPER_NO_CONTRACT;
+ ModuleIndex index = pMT->GetModuleForStatics()->GetModuleIndex();
+ return GetTLMIfExists(index);
+}
+
#ifndef DACCESS_COMPILE
BOOL Thread::s_fCleanFinalizedThread = FALSE;
@@ -115,7 +133,6 @@ template<> void GCAssert<FALSE>::BeginGCAssert()
}
#endif
-
// #define NEW_TLS 1
#ifdef _DEBUG
@@ -1386,9 +1403,6 @@ Thread::Thread()
m_ulEnablePreemptiveGCCount = 0;
#endif
- // Initialize data members related to thread statics
- m_pThreadLocalBlock = NULL;
-
m_dwLockCount = 0;
m_dwBeginLockCount = 0;
@@ -2714,9 +2728,6 @@ Thread::~Thread()
g_pThinLockThreadIdDispenser->DisposeId(GetThreadId());
- //Ensure DeleteThreadStaticData was executed
- _ASSERTE(m_pThreadLocalBlock == NULL);
-
#ifdef FEATURE_PREJIT
if (m_pIBCInfo) {
delete m_pIBCInfo;
@@ -7814,11 +7825,6 @@ void Thread::EnterContextRestricted(Context *pContext, ContextTransitionFrame *p
}
#endif // FEATURE_APPDOMAIN_RESOURCE_MONITORING
- // NULL out the Thread's pointer to the current ThreadLocalBlock. On the next
- // access to thread static data, the Thread's pointer to the current ThreadLocalBlock
- // will be updated correctly.
- m_pThreadLocalBlock = NULL;
-
m_pDomain = pDomain;
SetAppDomain(m_pDomain);
}
@@ -7935,11 +7941,6 @@ void Thread::ReturnToContext(ContextTransitionFrame *pFrame)
FlushIBCInfo();
- // NULL out the Thread's pointer to the current ThreadLocalBlock. On the next
- // access to thread static data, the Thread's pointer to the current ThreadLocalBlock
- // will be updated correctly.
- m_pThreadLocalBlock = NULL;
-
m_pDomain = pReturnDomain;
SetAppDomain(pReturnDomain);
@@ -8894,7 +8895,7 @@ LPVOID Thread::GetStaticFieldAddress(FieldDesc *pFD)
//
//+----------------------------------------------------------------------------
-TADDR Thread::GetStaticFieldAddrNoCreate(FieldDesc *pFD, PTR_AppDomain pDomain)
+TADDR Thread::GetStaticFieldAddrNoCreate(FieldDesc *pFD)
{
CONTRACTL {
NOTHROW;
@@ -8914,11 +8915,11 @@ TADDR Thread::GetStaticFieldAddrNoCreate(FieldDesc *pFD, PTR_AppDomain pDomain)
if (pFD->GetFieldType() == ELEMENT_TYPE_CLASS ||
pFD->GetFieldType() == ELEMENT_TYPE_VALUETYPE)
{
- base = pMT->GetGCThreadStaticsBasePointer(dac_cast<PTR_Thread>(this), pDomain);
+ base = pMT->GetGCThreadStaticsBasePointer(dac_cast<PTR_Thread>(this));
}
else
{
- base = pMT->GetNonGCThreadStaticsBasePointer(dac_cast<PTR_Thread>(this), pDomain);
+ base = pMT->GetNonGCThreadStaticsBasePointer(dac_cast<PTR_Thread>(this));
}
if (base == NULL)
@@ -9012,13 +9013,7 @@ void Thread::DeleteThreadStaticData()
}
CONTRACTL_END;
- // Deallocate the memory used by the table of ThreadLocalBlocks
- if (m_pThreadLocalBlock != NULL)
- {
- m_pThreadLocalBlock->FreeTable();
- delete m_pThreadLocalBlock;
- m_pThreadLocalBlock = NULL;
- }
+ m_ThreadLocalBlock.FreeTable();
}
//+----------------------------------------------------------------------------
@@ -9033,47 +9028,9 @@ void Thread::DeleteThreadStaticData()
void Thread::DeleteThreadStaticData(ModuleIndex index)
{
- if (m_pThreadLocalBlock != NULL)
- {
- m_pThreadLocalBlock->FreeTLM(index.m_dwIndex, FALSE /* isThreadShuttingDown */);
- }
+ m_ThreadLocalBlock.FreeTLM(index.m_dwIndex, FALSE /* isThreadShuttingDown */);
}
-//+----------------------------------------------------------------------------
-//
-// Method: Thread::DeleteThreadStaticData protected
-//
-// Synopsis: Delete the static data for the given appdomain. This is called
-// when the appdomain unloads.
-//
-//
-//+----------------------------------------------------------------------------
-
-void Thread::DeleteThreadStaticData(AppDomain *pDomain)
-{
- CONTRACTL {
- NOTHROW;
- GC_NOTRIGGER;
- }
- CONTRACTL_END;
-
- // Look up the AppDomain index
- SIZE_T index = pDomain->GetIndex().m_dwIndex;
-
- ThreadLocalBlock * pTLB = m_pThreadLocalBlock;
- m_pThreadLocalBlock = NULL;
-
- if (pTLB != NULL)
- {
- // Since the AppDomain is being unloaded anyway, all the memory used by
- // the TLB will be reclaimed, so we don't really have to call FreeTable()
- pTLB->FreeTable();
-
- delete pTLB;
- }
-}
-
-
void Thread::InitCultureAccessors()
{
CONTRACTL {
@@ -10219,10 +10176,7 @@ Thread::EnumMemoryRegions(CLRDataEnumMemoryFlags flags)
m_ExceptionState.EnumChainMemoryRegions(flags);
- // Like the old thread static implementation, we only enumerate
- // the current TLB. Should we be enumerating all of the TLBs?
- if (m_pThreadLocalBlock.IsValid())
- m_pThreadLocalBlock->EnumMemoryRegions(flags);
+ m_ThreadLocalBlock.EnumMemoryRegions(flags);
if (flags != CLRDATA_ENUM_MEM_MINI && flags != CLRDATA_ENUM_MEM_TRIAGE)
{
diff --git a/src/vm/threads.h b/src/vm/threads.h
index 44a30b0b5b..f195cd0e1b 100644
--- a/src/vm/threads.h
+++ b/src/vm/threads.h
@@ -187,6 +187,79 @@ typedef DPTR(PTR_ThreadLocalBlock) PTR_PTR_ThreadLocalBlock;
class EventPipeBufferList;
#endif // FEATURE_PERFTRACING
+struct TLMTableEntry;
+
+typedef DPTR(struct TLMTableEntry) PTR_TLMTableEntry;
+typedef DPTR(struct ThreadLocalModule) PTR_ThreadLocalModule;
+
+class ThreadStaticHandleTable;
+struct ThreadLocalModule;
+class Module;
+
+struct ThreadLocalBlock
+{
+ friend class ClrDataAccess;
+
+private:
+ PTR_TLMTableEntry m_pTLMTable; // Table of ThreadLocalModules
+ SIZE_T m_TLMTableSize; // Current size of table
+ SpinLock m_TLMTableLock; // Spinlock used to synchronize growing the table and freeing TLM by other threads
+
+ // Each ThreadLocalBlock has its own ThreadStaticHandleTable. The ThreadStaticHandleTable works
+ // by allocating Object arrays on the GC heap and keeping them alive with pinning handles.
+ //
+ // We use the ThreadStaticHandleTable to allocate space for GC thread statics. A GC thread
+ // static is thread static that is either a reference type or a value type whose layout
+ // contains a pointer to a reference type.
+
+ ThreadStaticHandleTable * m_pThreadStaticHandleTable;
+
+ // Need to keep a list of the pinning handles we've created
+ // so they can be cleaned up when the thread dies
+ ObjectHandleList m_PinningHandleList;
+
+public:
+
+#ifndef DACCESS_COMPILE
+ void AddPinningHandleToList(OBJECTHANDLE oh);
+ void FreePinningHandles();
+ void AllocateThreadStaticHandles(Module * pModule, ThreadLocalModule * pThreadLocalModule);
+ OBJECTHANDLE AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTHANDLE* ppLazyAllocate = NULL);
+ void InitThreadStaticHandleTable();
+
+ void AllocateThreadStaticBoxes(MethodTable* pMT);
+#endif
+
+public: // used by code generators
+ static SIZE_T GetOffsetOfModuleSlotsPointer() { return offsetof(ThreadLocalBlock, m_pTLMTable); }
+
+public:
+
+#ifndef DACCESS_COMPILE
+ ThreadLocalBlock()
+ : m_pTLMTable(NULL), m_TLMTableSize(0), m_pThreadStaticHandleTable(NULL)
+ {
+ m_TLMTableLock.Init(LOCK_TYPE_DEFAULT);
+ }
+
+ void FreeTLM(SIZE_T i, BOOL isThreadShuttingDown);
+
+ void FreeTable();
+
+ void EnsureModuleIndex(ModuleIndex index);
+
+#endif
+
+ void SetModuleSlot(ModuleIndex index, PTR_ThreadLocalModule pLocalModule);
+
+ PTR_ThreadLocalModule GetTLMIfExists(ModuleIndex index);
+ PTR_ThreadLocalModule GetTLMIfExists(MethodTable* pMT);
+
+#ifdef DACCESS_COMPILE
+ void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
+#endif
+};
+
#ifdef CROSSGEN_COMPILE
#include "asmconstants.h"
@@ -195,7 +268,7 @@ class Thread
{
friend class ThreadStatics;
- PTR_ThreadLocalBlock m_pThreadLocalBlock;
+ ThreadLocalBlock m_ThreadLocalBlock;
public:
BOOL IsAddressInStack (PTR_VOID addr) const { return TRUE; }
@@ -4198,7 +4271,7 @@ public:
bool GetDebugCantStop(void);
static LPVOID GetStaticFieldAddress(FieldDesc *pFD);
- TADDR GetStaticFieldAddrNoCreate(FieldDesc *pFD, PTR_AppDomain pDomain);
+ TADDR GetStaticFieldAddrNoCreate(FieldDesc *pFD);
void SetLoadingFile(DomainFile *pFile)
{
@@ -4406,21 +4479,12 @@ public:
void EnsurePreallocatedContext();
- // m_pThreadLocalBLock points to the ThreadLocalBlock that corresponds to the
- // AppDomain that the Thread is currently in
-
- PTR_ThreadLocalBlock m_pThreadLocalBlock;
+ ThreadLocalBlock m_ThreadLocalBlock;
// Called during AssemblyLoadContext teardown to clean up all structures
// associated with thread statics for the specific Module
void DeleteThreadStaticData(ModuleIndex index);
-protected:
-
- // Called during AD teardown to clean up any references this
- // thread may have to the AppDomain
- void DeleteThreadStaticData(AppDomain *pDomain);
-
private:
// Called during Thread death to clean up all structures
diff --git a/src/vm/threadstatics.cpp b/src/vm/threadstatics.cpp
index dcfc082927..fbcd4fa9b3 100644
--- a/src/vm/threadstatics.cpp
+++ b/src/vm/threadstatics.cpp
@@ -33,8 +33,7 @@ void ThreadLocalBlock::FreeTLM(SIZE_T i, BOOL isThreadShuttingdown)
{
SpinLock::Holder lock(&m_TLMTableLock);
- _ASSERTE(m_pTLMTable != NULL);
- if (i >= m_TLMTableSize)
+ if ((m_pTLMTable == NULL) || (i >= m_TLMTableSize))
{
return;
}
@@ -98,6 +97,8 @@ void ThreadLocalBlock::FreeTable()
}
}
+ SpinLock::Holder lock(&m_TLMTableLock);
+
// Free the table itself
delete m_pTLMTable;
m_pTLMTable = NULL;
@@ -581,9 +582,7 @@ void ThreadLocalModule::AllocateDynamicClass(MethodTable *pMT)
{
if (!pMT->Collectible())
{
- PTR_ThreadLocalBlock pThreadLocalBlock = GetThread()->m_pThreadLocalBlock;
- _ASSERTE(pThreadLocalBlock != NULL);
- pThreadLocalBlock->AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
+ GetThread()->m_ThreadLocalBlock.AllocateStaticFieldObjRefPtrs(dwNumHandleStatics,
&((NormalDynamicEntry *)pDynamicStatics)->m_pGCStatics);
}
else
@@ -697,25 +696,6 @@ PTR_ThreadLocalModule ThreadStatics::GetTLM(MethodTable * pMT) //static
return GetTLM(pModule->GetModuleIndex(), pModule);
}
-PTR_ThreadLocalBlock ThreadStatics::AllocateTLB(PTR_Thread pThread) //static
-{
- CONTRACTL
- {
- THROWS;
- GC_NOTRIGGER;
- SO_TOLERANT;
- MODE_ANY;
- }
- CONTRACTL_END;
- _ASSERTE(pThread->m_pThreadLocalBlock == NULL);
-
- // Allocate a new TLB and update this Thread's pointer to the current
- // ThreadLocalBlock. Constructor zeroes out everything for us.
- pThread->m_pThreadLocalBlock = new ThreadLocalBlock();
-
- return pThread->m_pThreadLocalBlock;
-}
-
PTR_ThreadLocalModule ThreadStatics::AllocateTLM(Module * pModule)
{
CONTRACTL
diff --git a/src/vm/threadstatics.h b/src/vm/threadstatics.h
index 823e1d1626..f23d669a81 100644
--- a/src/vm/threadstatics.h
+++ b/src/vm/threadstatics.h
@@ -517,94 +517,11 @@ struct TLMTableEntry
typedef DPTR(struct ThreadLocalBlock) PTR_ThreadLocalBlock;
typedef DPTR(PTR_ThreadLocalBlock) PTR_PTR_ThreadLocalBlock;
-struct ThreadLocalBlock
-{
- friend class ClrDataAccess;
-
-private:
- PTR_TLMTableEntry m_pTLMTable; // Table of ThreadLocalModules
- SIZE_T m_TLMTableSize; // Current size of table
- SpinLock m_TLMTableLock; // Spinlock used to synchronize growing the table and freeing TLM by other threads
-
- // Each ThreadLocalBlock has its own ThreadStaticHandleTable. The ThreadStaticHandleTable works
- // by allocating Object arrays on the GC heap and keeping them alive with pinning handles.
- //
- // We use the ThreadStaticHandleTable to allocate space for GC thread statics. A GC thread
- // static is thread static that is either a reference type or a value type whose layout
- // contains a pointer to a reference type.
-
- ThreadStaticHandleTable * m_pThreadStaticHandleTable;
-
- // Need to keep a list of the pinning handles we've created
- // so they can be cleaned up when the thread dies
- ObjectHandleList m_PinningHandleList;
-
-public:
-
-#ifndef DACCESS_COMPILE
- void AddPinningHandleToList(OBJECTHANDLE oh);
- void FreePinningHandles();
- void AllocateThreadStaticHandles(Module * pModule, ThreadLocalModule * pThreadLocalModule);
- OBJECTHANDLE AllocateStaticFieldObjRefPtrs(int nRequested, OBJECTHANDLE* ppLazyAllocate = NULL);
- void InitThreadStaticHandleTable();
-
- void AllocateThreadStaticBoxes(MethodTable* pMT);
-#endif
-
-public: // used by code generators
- static SIZE_T GetOffsetOfModuleSlotsPointer() { return offsetof(ThreadLocalBlock, m_pTLMTable); }
-
-public:
-
-#ifndef DACCESS_COMPILE
- ThreadLocalBlock()
- : m_pTLMTable(NULL), m_TLMTableSize(0), m_pThreadStaticHandleTable(NULL)
- {
- m_TLMTableLock.Init(LOCK_TYPE_DEFAULT);
- }
-
- void FreeTLM(SIZE_T i, BOOL isThreadShuttingDown);
-
- void FreeTable();
-
- void EnsureModuleIndex(ModuleIndex index);
-
-#endif
-
- void SetModuleSlot(ModuleIndex index, PTR_ThreadLocalModule pLocalModule);
-
- FORCEINLINE PTR_ThreadLocalModule GetTLMIfExists(ModuleIndex index)
- {
- WRAPPER_NO_CONTRACT;
- SUPPORTS_DAC;
-
- if (index.m_dwIndex >= m_TLMTableSize)
- return NULL;
-
- return m_pTLMTable[index.m_dwIndex].pTLM;
- }
-
- FORCEINLINE PTR_ThreadLocalModule GetTLMIfExists(MethodTable* pMT)
- {
- WRAPPER_NO_CONTRACT;
- ModuleIndex index = pMT->GetModuleForStatics()->GetModuleIndex();
- return GetTLMIfExists(index);
- }
-
-#ifdef DACCESS_COMPILE
- void EnumMemoryRegions(CLRDataEnumMemoryFlags flags);
-#endif
-};
-
-
-
-
class ThreadStatics
{
public:
#ifndef DACCESS_COMPILE
- static PTR_ThreadLocalBlock AllocateTLB(PTR_Thread pThread);
static PTR_ThreadLocalModule AllocateTLM(Module * pModule);
static PTR_ThreadLocalModule AllocateAndInitTLM(ModuleIndex index, PTR_ThreadLocalBlock pThreadLocalBlock, Module * pModule);
@@ -612,59 +529,35 @@ class ThreadStatics
static PTR_ThreadLocalModule GetTLM(MethodTable * pMT);
#endif
-#ifndef DACCESS_COMPILE
- FORCEINLINE static PTR_ThreadLocalBlock GetCurrentTLBIfExists()
- {
- // Get the current thread
- PTR_Thread pThread = GetThread();
-
- return pThread->m_pThreadLocalBlock;
- }
-#endif
-
- FORCEINLINE static PTR_ThreadLocalBlock GetCurrentTLBIfExists(PTR_Thread pThread, PTR_AppDomain pDomain)
+ FORCEINLINE static PTR_ThreadLocalBlock GetCurrentTLB(PTR_Thread pThread)
{
SUPPORTS_DAC;
- PTR_ThreadLocalBlock pTLB = pThread->m_pThreadLocalBlock;
-
- return pTLB;
+ return dac_cast<PTR_ThreadLocalBlock>(&pThread->m_ThreadLocalBlock);
}
#ifndef DACCESS_COMPILE
- FORCEINLINE static PTR_ThreadLocalBlock GetCurrentTLB()
+ FORCEINLINE static ThreadLocalBlock* GetCurrentTLB()
{
// Get the current thread
Thread * pThread = GetThread();
- // If the current TLB pointer is NULL, search the TLB table
- if (pThread->m_pThreadLocalBlock == NULL)
- {
- // Allocate the new ThreadLocalBlock.
- // If the allocation fails this will throw.
- return ThreadStatics::AllocateTLB(pThread);
- }
-
- return pThread->m_pThreadLocalBlock;
+ return &pThread->m_ThreadLocalBlock;
}
- FORCEINLINE static PTR_ThreadLocalModule GetTLMIfExists(ModuleIndex index)
+ FORCEINLINE static ThreadLocalModule* GetTLMIfExists(ModuleIndex index)
{
// Get the current ThreadLocalBlock
- PTR_ThreadLocalBlock pThreadLocalBlock = GetCurrentTLBIfExists();
- if (pThreadLocalBlock == NULL)
- return NULL;
+ PTR_ThreadLocalBlock pThreadLocalBlock = GetCurrentTLB();
// Get the TLM from the ThreadLocalBlock's table
return pThreadLocalBlock->GetTLMIfExists(index);
}
- FORCEINLINE static PTR_ThreadLocalModule GetTLMIfExists(MethodTable * pMT)
+ FORCEINLINE static ThreadLocalModule* GetTLMIfExists(MethodTable * pMT)
{
// Get the current ThreadLocalBlock
- PTR_ThreadLocalBlock pThreadLocalBlock = GetCurrentTLBIfExists();
- if (pThreadLocalBlock == NULL)
- return NULL;
+ ThreadLocalBlock* pThreadLocalBlock = GetCurrentTLB();
// Get the TLM from the ThreadLocalBlock's table
return pThreadLocalBlock->GetTLMIfExists(pMT);