//========================================================================= // Asserts if lock mode is PREEMPTIVE and thread in a GC_NOTRIGGER contract //========================================================================= void SimpleRWLock::CheckGCNoTrigger() { STATIC_CONTRACT_NOTHROW; // On PREEMPTIVE locks we'll toggle the GC mode, so we better not be in a GC_NOTRIGGERS region if (m_gcMode == PREEMPTIVE) { ClrDebugState *pClrDebugState = CheckClrDebugState(); if (pClrDebugState) { if (pClrDebugState->GetGCNoTriggerCount()) { // If we have no thread object, we won't be toggling the GC. This is the case, // for example, on the debugger helper thread which is always GC_NOTRIGGERS. if (GetThreadNULLOk() != NULL) { if (!( (GCViolation|BadDebugState) & pClrDebugState->ViolationMask())) { CONTRACT_ASSERT("You cannot enter a lock in a GC_NOTRIGGER region.", Contract::GC_NoTrigger, Contract::GC_Mask, __FUNCTION__, __FILE__, __LINE__); } } } // The mode checks and enforcement of GC_NOTRIGGER during the lock are done in SimpleRWLock::PostEnter(). } } }
// This is effectively an implicit probe, because we are guaranteeing that we have // enought stack to run and will not take an SO. So we enter SO-intolerant code when // we install one of these. BaseStackMarker::BaseStackMarker(float numPages, BOOL fAllowDisabling) : m_prevWasSOTolerant(FALSE), m_pDebugState(CheckClrDebugState()), m_fMarkerSet(FALSE) , m_fTemporarilyDisabled(FALSE), m_fAddedToStack(FALSE), m_pPrevious(NULL) , m_numPages(0.0), m_pMarker(NULL) , m_fProtectedStackPage(FALSE), m_fAllowDisabling(fAllowDisabling) { WRAPPER_CONTRACT; STATIC_CONTRACT_DEBUG_ONLY; // If backout stack validation isn't enabled then we are done. if (!g_EnableBackoutStackValidation) { return; } // If we can't talk to other markers then the markers could get in each others way if (!m_pDebugState) { return; } // Allow only the lowest marker to be active at any one time. Yes, this means that // the stack will only ever have one element in it. However having multiple markers // is problematic for debugging and conflicts with the VirtualProtect option. It // adds little value, in that small backout checks stop happening in exception // codepaths, but these get plenty of coverage in success cases and the lowest // placed marked is the one that could actually indicate a stack overflow. if (!m_pDebugState->m_StackMarkerStack.IsEmpty()) { return; } // Switch the SO tolerance mode m_prevWasSOTolerant = m_pDebugState->SetSOTolerance(FALSE); // If we have less then numPages left before the end of the stack then there is // no point in adding a marker since we will take an SO anyway if we use too much // stack. Putting the marker is actually very bad since it artificially forces an // SO in cases where it wouldn't normally occur if we use less than num pages of stack. if (g_fpCheckNStackPagesAvailable && !g_fpCheckNStackPagesAvailable(numPages < 1 ? 1 : (unsigned int)numPages)) { return; } if (m_fAllowDisabling) { // Push ourselves on to the stack of stack markers on the CLR debug state. m_pDebugState->m_StackMarkerStack.PushStackMarker(this); m_fAddedToStack = TRUE; } // Set the actual stack guard marker if we have enough stack to do so. SetMarker(numPages); if (m_fMarkerSet && m_fAllowDisabling) { ProtectMarkerPageInDebugger(); } }