diff --git a/src/coreclr/vm/appdomain.cpp b/src/coreclr/vm/appdomain.cpp index 083c33768b818d..a5d2342f8b648d 100644 --- a/src/coreclr/vm/appdomain.cpp +++ b/src/coreclr/vm/appdomain.cpp @@ -3566,7 +3566,9 @@ BOOL AppDomain::AddFileToCache(AssemblySpec* pSpec, PEAssembly *pFile, BOOL fAll } CONTRACTL_END; - CrstHolder holder(&m_DomainCacheCrst); + GCX_PREEMP(); + DomainCacheCrstHolderForGCCoop holder(this); + // !!! suppress exceptions if(!m_AssemblyCache.StoreFile(pSpec, pFile) && !fAllowFailure) { @@ -3596,7 +3598,9 @@ BOOL AppDomain::AddAssemblyToCache(AssemblySpec* pSpec, DomainAssembly *pAssembl } CONTRACTL_END; - CrstHolder holder(&m_DomainCacheCrst); + GCX_PREEMP(); + DomainCacheCrstHolderForGCCoop holder(this); + // !!! suppress exceptions BOOL bRetVal = m_AssemblyCache.StoreAssembly(pSpec, pAssembly); return bRetVal; @@ -3617,7 +3621,9 @@ BOOL AppDomain::AddExceptionToCache(AssemblySpec* pSpec, Exception *ex) if (ex->IsTransient()) return TRUE; - CrstHolder holder(&m_DomainCacheCrst); + GCX_PREEMP(); + DomainCacheCrstHolderForGCCoop holder(this); + // !!! suppress exceptions return m_AssemblyCache.StoreException(pSpec, ex); } @@ -3635,7 +3641,7 @@ void AppDomain::AddUnmanagedImageToCache(LPCWSTR libraryName, NATIVE_LIBRARY_HAN } CONTRACTL_END; - CrstHolder lock(&m_DomainCacheCrst); + DomainCacheCrstHolderForGCPreemp lock(this); const UnmanagedImageCacheEntry *existingEntry = m_unmanagedCache.LookupPtr(libraryName); if (existingEntry != NULL) @@ -3665,7 +3671,8 @@ NATIVE_LIBRARY_HANDLE AppDomain::FindUnmanagedImageInCache(LPCWSTR libraryName) } CONTRACT_END; - CrstHolder lock(&m_DomainCacheCrst); + DomainCacheCrstHolderForGCPreemp lock(this); + const UnmanagedImageCacheEntry *existingEntry = m_unmanagedCache.LookupPtr(libraryName); if (existingEntry == NULL) RETURN NULL; @@ -3707,7 +3714,8 @@ BOOL AppDomain::RemoveAssemblyFromCache(DomainAssembly* pAssembly) } CONTRACTL_END; - CrstHolder holder(&m_DomainCacheCrst); + GCX_PREEMP(); + DomainCacheCrstHolderForGCCoop holder(this); return m_AssemblyCache.RemoveAssembly(pAssembly); } diff --git a/src/coreclr/vm/appdomain.hpp b/src/coreclr/vm/appdomain.hpp index 6c41b1cfd7d238..447f78345d3288 100644 --- a/src/coreclr/vm/appdomain.hpp +++ b/src/coreclr/vm/appdomain.hpp @@ -1164,6 +1164,30 @@ class BaseDomain }; friend class LockHolder; + // To be used when the thread will remain in preemptive GC mode while holding the lock + class DomainCacheCrstHolderForGCPreemp : private CrstHolder + { + public: + DomainCacheCrstHolderForGCPreemp(BaseDomain *pD) + : CrstHolder(&pD->m_DomainCacheCrst) + { + WRAPPER_NO_CONTRACT; + } + }; + + // To be used when the thread may enter cooperative GC mode while holding the lock. The thread enters a + // forbid-suspend-for-debugger region along with acquiring the lock, such that it would not suspend for the debugger while + // holding the lock, as that may otherwise cause a FuncEval to deadlock when trying to acquire the lock. + class DomainCacheCrstHolderForGCCoop : private CrstAndForbidSuspendForDebuggerHolder + { + public: + DomainCacheCrstHolderForGCCoop(BaseDomain *pD) + : CrstAndForbidSuspendForDebuggerHolder(&pD->m_DomainCacheCrst) + { + WRAPPER_NO_CONTRACT; + } + }; + class DomainLocalBlockLockHolder : public CrstHolder { public: diff --git a/src/coreclr/vm/crst.cpp b/src/coreclr/vm/crst.cpp index 63472e454e210b..d617647f27233b 100644 --- a/src/coreclr/vm/crst.cpp +++ b/src/coreclr/vm/crst.cpp @@ -789,8 +789,8 @@ CrstBase::CrstAndForbidSuspendForDebuggerHolder::CrstAndForbidSuspendForDebugger // Reentrant locks are currently not supported _ASSERTE((pCrst->m_dwFlags & CRST_REENTRANCY) == 0); - Thread *pThread = GetThread(); - if (pThread->IsInForbidSuspendForDebuggerRegion()) + Thread *pThread = GetThreadNULLOk(); + if (pThread == nullptr || pThread->IsInForbidSuspendForDebuggerRegion()) { AcquireLock(pCrst); return;